cmd1.c

Go to the documentation of this file.
00001 /* cmd1.c */
00002 
00003 /* Author:
00004  *      Steve Kirkendall
00005  *      14407 SW Teal Blvd. #C
00006  *      Beaverton, OR 97005
00007  *      kirkenda@cs.pdx.edu
00008  */
00009 
00010 
00011 /* This file contains some of the EX commands - mostly ones that deal with
00012  * files, options, etc. -- anything except text.
00013  */
00014 
00015 #include "config.h"
00016 #include "ctype.h"
00017 #include "vi.h"
00018 #include "regexp.h"
00019 
00020 #ifdef DEBUG
00021 /* print the selected lines with info on the blocks */
00022 /*ARGSUSED*/
00023 void cmd_debug(frommark, tomark, cmd, bang, extra)
00024         MARK    frommark;
00025         MARK    tomark;
00026         CMD     cmd;
00027         int     bang;
00028         char    *extra;
00029 {
00030         REG char        *scan;
00031         REG long        l;
00032         REG int         i;
00033         int             len;
00034 
00035         /* scan lnum[] to determine which block its in */
00036         l = markline(frommark);
00037         for (i = 1; l > lnum[i]; i++)
00038         {
00039         }
00040 
00041         do
00042         {
00043                 /* fetch text of the block containing that line */
00044                 scan = blkget(i)->c;
00045 
00046                 /* calculate its length */
00047                 if (scan[BLKSIZE - 1])
00048                 {
00049                         len = BLKSIZE;
00050                 }
00051                 else
00052                 {
00053                         len = strlen(scan);
00054                 }
00055 
00056                 /* print block stats */
00057                 msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
00058                         i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
00059                 msg("##### len=%d, buf=0x%lx, %sdirty",
00060                         len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
00061                 if (bang)
00062                 {
00063                         while (--len >= 0)
00064                         {
00065                                 addch(*scan);
00066                                 scan++;
00067                         }
00068                 }
00069                 exrefresh();
00070 
00071                 /* next block */
00072                 i++;
00073         } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
00074 }
00075 
00076 
00077 /* This function checks a lot of conditions to make sure they aren't screwy */
00078 /*ARGSUSED*/
00079 void cmd_validate(frommark, tomark, cmd, bang, extra)
00080         MARK    frommark;
00081         MARK    tomark;
00082         CMD     cmd;
00083         int     bang;
00084         char    *extra;
00085 {
00086         char    *scan;
00087         int     i;
00088         int     nlcnt;  /* used to count newlines */
00089         int     len;    /* counts non-NUL characters */
00090 
00091         /* check lnum[0] */
00092         if (lnum[0] != 0L)
00093         {
00094                 msg("lnum[0] = %ld", lnum[0]);
00095         }
00096 
00097         /* check each block */
00098         for (i = 1; lnum[i] <= nlines; i++)
00099         {
00100                 scan = blkget(i)->c;
00101                 if (scan[BLKSIZE - 1])
00102                 {
00103                         msg("block %d has no NUL at the end", i);
00104                 }
00105                 else
00106                 {
00107                         for (nlcnt = len = 0; *scan; scan++, len++)
00108                         {
00109                                 if (*scan == '\n')
00110                                 {
00111                                         nlcnt++;
00112                                 }
00113                         }
00114                         if (scan[-1] != '\n')
00115                         {
00116                                 msg("block %d doesn't end with '\\n' (length %d)", i, len);
00117                         }
00118                         if (bang || nlcnt != lnum[i] - lnum[i - 1])
00119                         {
00120                                 msg("block %d (line %ld?) has %d lines, but should have %ld",
00121                                         i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
00122                         }
00123                 }
00124                 exrefresh();
00125         }
00126 
00127         /* check lnum again */
00128         if (lnum[i] != INFINITY)
00129         {
00130                 msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
00131                         i, hdr.n[i], i, lnum[i]);
00132         }
00133 
00134         msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
00135         msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
00136 }
00137 #endif /* DEBUG */
00138 
00139 
00140 /*ARGSUSED*/
00141 void cmd_mark(frommark, tomark, cmd, bang, extra)
00142         MARK    frommark;
00143         MARK    tomark;
00144         CMD     cmd;
00145         int     bang;
00146         char    *extra;
00147 {
00148         /* validate the name of the mark */
00149         if (*extra == '"')
00150         {
00151                 extra++;
00152         }
00153         /* valid mark names are lowercase ascii characters */
00154         if (!isascii(*extra) || !islower(*extra) || extra[1])
00155         {
00156                 msg("Invalid mark name");
00157                 return;
00158         }
00159 
00160         mark[*extra - 'a'] = tomark;
00161 }
00162 
00163 /*ARGSUSED*/
00164 void cmd_write(frommark, tomark, cmd, bang, extra)
00165         MARK    frommark;
00166         MARK    tomark;
00167         CMD     cmd;
00168         int     bang;
00169         char    *extra;
00170 {
00171         int             fd;
00172         int             append; /* boolean: write in "append" mode? */
00173         REG long        l;
00174         REG char        *scan;
00175         REG int         i;
00176 
00177         /* if writing to a filter, then let filter() handle it */
00178         if (*extra == '!')
00179         {
00180                 filter(frommark, tomark, extra + 1, FALSE);
00181                 return;
00182         }
00183 
00184         /* if all lines are to be written, use tmpsave() */
00185         if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
00186         {
00187                 tmpsave(extra, bang);
00188                 return;
00189         }
00190 
00191         /* see if we're going to do this in append mode or not */
00192         append = FALSE;
00193         if (extra[0] == '>' && extra[1] == '>')
00194         {
00195                 extra += 2;
00196                 append = TRUE;
00197         }
00198 
00199         /* either the file must not exist, or we must have a ! or be appending */
00200         if (access(extra, 0) == 0 && !bang && !append)
00201         {
00202                 msg("File already exists - Use :w! to overwrite");
00203                 return;
00204         }
00205 
00206         /* else do it line-by-line, like cmd_print() */
00207         if (append)
00208         {
00209 #ifdef O_APPEND
00210                 fd = open(extra, O_WRONLY|O_APPEND);
00211 #else
00212                 fd = open(extra, O_WRONLY);
00213                 if (fd >= 0)
00214                 {
00215                         lseek(fd, 0L, 2);
00216                 }
00217 #endif
00218         }
00219         else
00220         {
00221                 fd = -1; /* so we know the file isn't open yet */
00222         }
00223 
00224         if (fd < 0)
00225         {
00226                 fd = creat(extra, FILEPERMS);
00227                 if (fd < 0)
00228                 {
00229                         msg("Can't write to \"%s\"", extra);
00230                         return;
00231                 }
00232         }
00233         for (l = markline(frommark); l <= markline(tomark); l++)
00234         {
00235                 /* get the next line */
00236                 scan = fetchline(l);
00237                 i = strlen(scan);
00238                 scan[i++] = '\n';
00239 
00240                 /* print the line */
00241                 if (twrite(fd, scan, i) < i)
00242                 {
00243                         msg("Write failed");
00244                         break;
00245                 }
00246         }
00247         rptlines = markline(tomark) - markline(frommark) + 1;
00248         rptlabel = "written";
00249         close(fd);
00250 }       
00251 
00252 
00253 /*ARGSUSED*/
00254 void cmd_shell(frommark, tomark, cmd, bang, extra)
00255         MARK    frommark, tomark;
00256         CMD     cmd;
00257         int     bang;
00258         char    *extra;
00259 {
00260         static char     prevextra[80];
00261 
00262         /* special case: ":sh" means ":!sh" */
00263         if (cmd == CMD_SHELL)
00264         {
00265                 extra = o_shell;
00266                 frommark = tomark = 0L;
00267         }
00268 
00269         /* if extra is "!", substitute previous command */
00270         if (*extra == '!')
00271         {
00272                 if (!*prevextra)
00273                 {
00274                         msg("No previous shell command to substitute for '!'");
00275                         return;
00276                 }
00277                 extra = prevextra;
00278         }
00279         else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
00280         {
00281                 strcpy(prevextra, extra);
00282         }
00283 
00284         /* warn the user if the file hasn't been saved yet */
00285         if (*o_warn && tstflag(file, MODIFIED))
00286         {
00287                 if (mode == MODE_VI)
00288                 {
00289                         mode = MODE_COLON;
00290                 }
00291                 msg("Warning: \"%s\" has been modified but not yet saved", origname);
00292         }
00293 
00294         /* if no lines were specified, just run the command */
00295         suspend_curses();
00296         if (frommark == 0L)
00297         {
00298                 system(extra);
00299         }
00300         else /* pipe lines from the file through the command */
00301         {
00302                 filter(frommark, tomark, extra, TRUE);
00303         }
00304 
00305         /* resume curses quietly for MODE_EX, but noisily otherwise */
00306         resume_curses(mode == MODE_EX);
00307 }
00308 
00309 
00310 /*ARGSUSED*/
00311 void cmd_global(frommark, tomark, cmd, bang, extra)
00312         MARK    frommark, tomark;
00313         CMD     cmd;
00314         int     bang;
00315         char    *extra; /* rest of the command line */
00316 {
00317         char    *cmdptr;        /* the command from the command line */
00318         char    cmdln[100];     /* copy of the command from the command line */
00319         char    *line;          /* a line from the file */
00320         long    l;              /* used as a counter to move through lines */
00321         long    lqty;           /* quantity of lines to be scanned */
00322         long    nchanged;       /* number of lines changed */
00323         regexp  *re;            /* the compiled search expression */
00324 
00325         /* can't nest global commands */
00326         if (doingglobal)
00327         {
00328                 msg("Can't nest global commands.");
00329                 rptlines = -1L;
00330                 return;
00331         }
00332 
00333         /* ":g! ..." is the same as ":v ..." */
00334         if (bang)
00335         {
00336                 cmd = CMD_VGLOBAL;
00337         }
00338 
00339         /* make sure we got a search pattern */
00340         if (*extra != '/' && *extra != '?')
00341         {
00342                 msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
00343                 return;
00344         }
00345 
00346         /* parse & compile the search pattern */
00347         cmdptr = parseptrn(extra);
00348         if (!extra[1])
00349         {
00350                 msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
00351                 return;
00352         }
00353         re = regcomp(extra + 1);
00354         if (!re)
00355         {
00356                 /* regcomp found & described an error */
00357                 return;
00358         }
00359 
00360         /* for each line in the range */
00361         doingglobal = TRUE;
00362         ChangeText
00363         {
00364                 /* NOTE: we have to go through the lines in a forward order,
00365                  * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
00366                  * to work, simply adding 1 to the line# on each loop won't
00367                  * work.  The solution: count lines relative to the end of
00368                  * the file.  Think about it.
00369                  */
00370                 for (l = nlines - markline(frommark),
00371                         lqty = markline(tomark) - markline(frommark) + 1L,
00372                         nchanged = 0L;
00373                      lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
00374                      l--, lqty--)
00375                 {
00376                         /* fetch the line */
00377                         line = fetchline(nlines - l);
00378 
00379                         /* if it contains the search pattern... */
00380                         if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
00381                         {
00382                                 /* move the cursor to that line */
00383                                 cursor = MARK_AT_LINE(nlines - l);
00384 
00385                                 /* do the ex command (without mucking up
00386                                  * the original copy of the command line)
00387                                  */
00388                                 strcpy(cmdln, cmdptr);
00389                                 rptlines = 0L;
00390                                 doexcmd(cmdln);
00391                                 nchanged += rptlines;
00392                         }
00393                 }
00394         }
00395         doingglobal = FALSE;
00396 
00397         /* free the regexp */
00398         free(re);
00399 
00400         /* Reporting...*/
00401         rptlines = nchanged;
00402 }
00403 
00404 
00405 /*ARGSUSED*/
00406 void cmd_file(frommark, tomark, cmd, bang, extra)
00407         MARK    frommark, tomark;
00408         CMD     cmd;
00409         int     bang;
00410         char    *extra;
00411 {
00412 #ifndef CRUNCH
00413         /* if we're given a new filename, use it as this file's name */
00414         if (extra && *extra)
00415         {
00416                 strcpy(origname, extra);
00417                 storename(origname);
00418                 setflag(file, NOTEDITED);
00419         }
00420 #endif
00421         if (cmd == CMD_FILE)
00422         {
00423 #ifndef CRUNCH
00424                 msg("\"%s\" %s%s%s %ld lines,  line %ld [%ld%%]",
00425 #else
00426                 msg("\"%s\" %s%s %ld lines,  line %ld [%ld%%]",
00427 #endif
00428                         *origname ? origname : "[NO FILE]",
00429                         tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
00430 #ifndef CRUNCH
00431                         tstflag(file, NOTEDITED) ?"[NOT EDITED]":"",
00432 #endif
00433                         tstflag(file, READONLY) ? "[READONLY]" : "",
00434                         nlines,
00435                         markline(frommark),
00436                         markline(frommark) * 100 / nlines);
00437         }
00438 #ifndef CRUNCH
00439         else if (markline(frommark) != markline(tomark))
00440         {
00441                 msg("range \"%ld,%ld\" contains %ld lines",
00442                         markline(frommark),
00443                         markline(tomark),
00444                         markline(tomark) - markline(frommark) + 1L);
00445         }
00446 #endif
00447         else
00448         {
00449                 msg("%ld", markline(frommark));
00450         }
00451 }
00452 
00453 
00454 /*ARGSUSED*/
00455 void cmd_edit(frommark, tomark, cmd, bang, extra)
00456         MARK    frommark, tomark;
00457         CMD     cmd;
00458         int     bang;
00459         char    *extra;
00460 {
00461         long    line = 1L;      /* might be set to prevline */
00462 #ifndef CRUNCH
00463         char    *init = (char *)0;
00464 #endif
00465 
00466 
00467         /* if ":vi", then switch to visual mode, and if no file is named
00468          * then don't switch files.
00469          */
00470         if (cmd == CMD_VISUAL)
00471         {
00472                 mode = MODE_VI;
00473                 msg("");
00474                 if (!*extra)
00475                 {
00476                         return;
00477                 }
00478         }
00479 
00480         /* Editing previous file?  Then start at previous line */
00481         if (!strcmp(extra, prevorig))
00482         {
00483                 line = prevline;
00484         }
00485 
00486 #ifndef CRUNCH
00487         /* if we were given an explicit starting line, then start there */
00488         if (*extra == '+')
00489         {
00490                 for (init = ++extra; !isspace(*extra); extra++)
00491                 {
00492                 }
00493                 while (isspace(*extra))
00494                 {
00495                         *extra++ = '\0';
00496                 }
00497                 if (!*init)
00498                 {
00499                         init = "$";
00500                 }
00501                 if (!extra)
00502                 {
00503                         extra = origname;
00504                 }
00505         }
00506 #endif /* not CRUNCH */
00507 
00508         /* switch files */
00509         if (tmpabort(bang))
00510         {
00511                 tmpstart(extra);
00512                 if (line <= nlines && line >= 1L)
00513                 {
00514                         cursor = MARK_AT_LINE(line);
00515                 }
00516 #ifndef CRUNCH
00517                 if (init)
00518                 {
00519                         doexcmd(init);
00520                 }
00521 #endif
00522         }
00523         else
00524         {
00525                 msg("Use edit! to abort changes, or w to save changes");
00526 
00527                 /* so we can say ":e!#" next time... */
00528                 strcpy(prevorig, extra);
00529                 prevline = 1L;
00530         }
00531 }
00532 
00533 /* This code is also used for rewind -- GB */
00534 
00535 /*ARGSUSED*/
00536 void cmd_next(frommark, tomark, cmd, bang, extra)
00537         MARK    frommark, tomark;
00538         CMD     cmd;
00539         int     bang;
00540         char    *extra;
00541 {
00542         int     i, j;
00543         char    *scan;
00544 
00545         /* if extra stuff given, use ":args" to define a new args list */
00546         if (cmd == CMD_NEXT && extra && *extra)
00547         {
00548                 cmd_args(frommark, tomark, cmd, bang, extra);
00549         }
00550 
00551         /* move to the next arg */
00552         if (cmd == CMD_NEXT)
00553         {
00554                 i = argno + 1;
00555         }
00556         else if (cmd == CMD_PREVIOUS)
00557         {
00558                 i = argno - 1;
00559         }
00560         else /* cmd == CMD_REWIND */
00561         {
00562                 i = 0;
00563         }       
00564         if (i < 0 || i >= nargs)
00565         {
00566                 msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
00567                 return;
00568         }
00569 
00570         /* find & isolate the name of the file to edit */
00571         for (j = i, scan = args; j > 0; j--)
00572         {
00573                 while(*scan++)
00574                 {
00575                 }
00576         }
00577 
00578         /* switch to the next file */
00579         if (tmpabort(bang))
00580         {
00581                 tmpstart(scan);
00582                 argno = i;
00583         }
00584         else
00585         {
00586                 msg("Use :%s! to abort changes, or w to save changes",
00587                         cmd == CMD_NEXT ? "next" :
00588                         cmd == CMD_PREVIOUS ? "previous" :
00589                                         "rewind");
00590         }
00591 }
00592 
00593 /* also called from :wq -- always writes back in this case */
00594 
00595 /*ARGSUSED*/
00596 void cmd_xit(frommark, tomark, cmd, bang, extra)
00597         MARK    frommark, tomark;
00598         CMD     cmd;
00599         int     bang;
00600         char    *extra;
00601 {
00602         static long     whenwarned;     /* when the user was last warned of extra files */
00603         int             oldflag;
00604 
00605         /* if there are more files to edit, then warn user */
00606         if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT))
00607         {
00608                 msg("More files to edit -- Use \":n\" to go to next file");
00609                 whenwarned = changes;
00610                 return;
00611         }
00612 
00613         if (cmd == CMD_QUIT)
00614         {
00615                 oldflag = *o_autowrite;
00616                 *o_autowrite = FALSE;
00617                 if (tmpabort(bang))
00618                 {
00619                         mode = MODE_QUIT;
00620                 }
00621                 else
00622                 {
00623                         msg("Use q! to abort changes, or wq to save changes");
00624                 }
00625                 *o_autowrite = oldflag;
00626         }
00627         else
00628         {
00629                 /* else try to save this file */
00630                 oldflag = tstflag(file, MODIFIED);
00631                 if (cmd == CMD_WQUIT)
00632                         setflag(file, MODIFIED);
00633                 if (tmpend(bang))
00634                 {
00635                         mode = MODE_QUIT;
00636                 }
00637                 else
00638                 {
00639                         msg("Could not save file -- use quit! to abort changes, or w filename");
00640                 }
00641                 if (!oldflag)
00642                         clrflag(file, MODIFIED);
00643         }
00644 }
00645 
00646 
00647 /*ARGSUSED*/
00648 void cmd_args(frommark, tomark, cmd, bang, extra)
00649         MARK    frommark, tomark;
00650         CMD     cmd;
00651         int     bang;
00652         char    *extra;
00653 {
00654         char    *scan;
00655         int     col;
00656         int     arg;
00657         int     scrolled = FALSE;
00658         int     width;
00659 
00660         /* if no extra names given, or just current name, then report the args
00661          * we have now.
00662          */
00663         if (!extra || !*extra)
00664         {
00665                 /* empty args list? */
00666                 if (nargs == 1 && !*args)
00667                 {
00668                         return;
00669                 }
00670 
00671                 /* list the arguments */
00672                 for (scan = args, col = arg = 0;
00673                      arg < nargs;
00674                      scan += width + 1, col += width, arg++)
00675                 {
00676                         width = strlen(scan);
00677                         if (col + width >= COLS - 4)
00678                         {
00679                                 addch('\n');
00680                                 col = 0;
00681                                 scrolled = TRUE;
00682                         }
00683                         else if (col > 0)
00684                         {
00685                                 addch(' ');
00686                                 col++;
00687                         }
00688                         if (arg == argno)
00689                         {
00690                                 addch('[');
00691                                 addstr(scan);
00692                                 addch(']');
00693                                 col += 2;
00694                         }
00695                         else
00696                         {
00697                                 addstr(scan);
00698                         }
00699                 }
00700 
00701                 /* write a trailing newline */
00702                 if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
00703                 {
00704                         addch('\n');
00705                 }
00706                 exrefresh();    
00707         }
00708         else /* new args list given */
00709         {
00710                 for (scan = args, nargs = 1; *extra; )
00711                 {
00712                         if (isspace(*extra))
00713                         {
00714                                 *scan++ = '\0';
00715                                 while (isspace(*extra))
00716                                 {
00717                                         extra++;
00718                                 }
00719                                 if (*extra)
00720                                 {
00721                                         nargs++;
00722                                 }
00723                         }
00724                         else
00725                         {
00726                                 *scan++ = *extra++;
00727                         }
00728                 }
00729                 *scan = '\0';
00730 
00731                 /* reset argno to before the first, so :next will go to first */
00732                 argno = -1;
00733 
00734                 if (nargs != 1)
00735                 {
00736                         msg("%d files to edit", nargs);
00737                 }
00738         }
00739 }
00740 
00741 
00742 /*ARGSUSED*/
00743 void cmd_cd(frommark, tomark, cmd, bang, extra)
00744         MARK    frommark, tomark;
00745         CMD     cmd;
00746         int     bang;
00747         char    *extra;
00748 {
00749         char    *getenv();
00750 
00751 #ifndef CRUNCH
00752         /* if current file is modified, and no '!' was given, then error */
00753         if (tstflag(file, MODIFIED) && !bang)
00754         {
00755                 msg("File modified; use \"cd! %s\" to switch anyway", extra);
00756         }
00757 #endif
00758 
00759         /* default directory name is $HOME */
00760         if (!*extra)
00761         {
00762                 extra = getenv("HOME");
00763                 if (!extra)
00764                 {
00765                         msg("environment variable $HOME not set");
00766                         return;
00767                 }
00768         }
00769 
00770         /* go to the directory */
00771         if (chdir(extra) < 0)
00772         {
00773                 perror(extra);
00774         }
00775 }
00776 
00777 
00778 /*ARGSUSED*/
00779 void cmd_map(frommark, tomark, cmd, bang, extra)
00780         MARK    frommark, tomark;
00781         CMD     cmd;
00782         int     bang;
00783         char    *extra;
00784 {
00785         char    *mapto;
00786         char    *build, *scan;
00787 #ifndef NO_FKEY
00788         static char *fnames[NFKEYS] =
00789         {
00790                 "#10", "#1", "#2", "#3", "#4",
00791                 "#5", "#6", "#7", "#8", "#9",
00792 # ifndef NO_SHIFT_FKEY
00793                 "#10s", "#1s", "#2s", "#3s", "#4s",
00794                 "#5s", "#6s", "#7s", "#8s", "#9s",
00795 #  ifndef NO_CTRL_FKEY
00796                 "#10c", "#1c", "#2c", "#3c", "#4c",
00797                 "#5c", "#6c", "#7c", "#8c", "#9c",
00798 #   ifndef NO_ALT_FKEY
00799                 "#10a", "#1a", "#2a", "#3a", "#4a",
00800                 "#5a", "#6a", "#7a", "#8a", "#9a",
00801 #   endif
00802 #  endif
00803 # endif
00804         };
00805         int     key;
00806 #endif
00807 
00808         /* "map" with no extra will dump the map table contents */
00809         if (!*extra)
00810         {
00811 #ifndef NO_ABBR
00812                 if (cmd == CMD_ABBR)
00813                 {
00814                         dumpkey(bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, TRUE);
00815                 }
00816                 else
00817 #endif
00818                 {
00819                         dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, FALSE);
00820                 }
00821         }
00822         else
00823         {
00824                 /* "extra" is key to map, followed by what it maps to */
00825 
00826                 /* handle quoting inside the "raw" string */
00827                 for (build = mapto = extra;
00828                      *mapto && (*mapto != ' ' && *mapto != '\t');
00829                      *build++ = *mapto++)
00830                 {
00831                         if (*mapto == ctrl('V') && mapto[1])
00832                         {
00833                                 mapto++;
00834                         }
00835                 }
00836 
00837                 /* skip whitespace, and mark the end of the "raw" string */
00838                 while ((*mapto == ' ' || *mapto == '\t'))
00839                 {
00840                         *mapto++ = '\0';
00841                 }
00842                 *build = '\0';
00843 
00844                 /* strip ^Vs from the "cooked" string */
00845                 for (scan = build = mapto; *scan; *build++ = *scan++)
00846                 {
00847                         if (*scan == ctrl('V') && scan[1])
00848                         {
00849                                 scan++;
00850                         }
00851                 }
00852                 *build = '\0';
00853 
00854 #ifndef NO_FKEY
00855                 /* if the mapped string is '#' and a number, then assume
00856                  * the user wanted that function key
00857                  */
00858                 if (extra[0] == '#' && isdigit(extra[1]))
00859                 {
00860                         key = atoi(extra + 1) % 10;
00861 # ifndef NO_SHIFT_FKEY
00862                         build = extra + strlen(extra) - 1;
00863                         if (*build == 's')
00864                                 key += 10;
00865 #  ifndef NO_CTRL_FKEY
00866                         else if (*build == 'c')
00867                                 key += 20;
00868 #   ifndef NO_ALT_FKEY
00869                         else if (*build == 'a')
00870                                 key += 30;
00871 #   endif
00872 #  endif
00873 # endif
00874                         if (FKEY[key])
00875                                 mapkey(FKEY[key], mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, fnames[key]);
00876                         else
00877                                 msg("This terminal has no %s key", fnames[key]);
00878                 }
00879                 else
00880 #endif
00881 #ifndef NO_ABBR
00882                 if (cmd == CMD_ABBR || cmd == CMD_UNABBR)
00883                 {
00884                         mapkey(extra, mapto, bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, "abbr");
00885                 }
00886                 else
00887 #endif
00888                 {
00889                         mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
00890                 }
00891         }
00892 }
00893 
00894 
00895 /*ARGSUSED*/
00896 void cmd_set(frommark, tomark, cmd, bang, extra)
00897         MARK    frommark, tomark;
00898         CMD     cmd;
00899         int     bang;
00900         char    *extra;
00901 {
00902         if (!*extra)
00903         {
00904                 dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
00905         }
00906         else if (!strcmp(extra, "all"))
00907         {
00908                 dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */
00909         }
00910         else
00911         {
00912                 setopts(extra);
00913 
00914                 /* That option may have affected the appearence of text */
00915                 changes++;
00916         }
00917 }
00918 
00919 /*ARGSUSED*/
00920 void cmd_tag(frommark, tomark, cmd, bang, extra)
00921         MARK    frommark, tomark;
00922         CMD     cmd;
00923         int     bang;
00924         char    *extra;
00925 {
00926         int     fd;     /* file descriptor used to read the file */
00927         char    *scan;  /* used to scan through the tmpblk.c */
00928 #ifdef INTERNAL_TAGS
00929         char    *cmp;   /* char of tag name we're comparing, or NULL */
00930         char    *end;   /* marks the end of chars in tmpblk.c */
00931 #else
00932         int     i;
00933 #endif
00934 #ifndef NO_MAGIC
00935         char    wasmagic; /* preserves the original state of o_magic */
00936 #endif
00937         static char prevtag[30];
00938 
00939         /* if no tag is given, use the previous tag */
00940         if (!extra || !*extra)
00941         {
00942                 if (!*prevtag)
00943                 {
00944                         msg("No previous tag");
00945                         return;
00946                 }
00947                 extra = prevtag;
00948         }
00949         else
00950         {
00951                 strncpy(prevtag, extra, sizeof prevtag);
00952                 prevtag[sizeof prevtag - 1] = '\0';
00953         }
00954 
00955 #ifndef INTERNAL_TAGS
00956         /* use "ref" to look up the tag info for this tag */
00957         sprintf(tmpblk.c, "ref -t %s%s %s", (*origname ? "-f" : ""),origname, prevtag);
00958         fd = rpipe(tmpblk.c, 0);
00959         if (fd < 0)
00960         {
00961                 msg("Can't run \"%s\"", tmpblk.c);
00962                 return;
00963         }
00964 
00965         /* try to read the tag info */
00966         for (scan = tmpblk.c;
00967              (i = tread(fd, scan, scan - tmpblk.c + BLKSIZE)) > 0;
00968              scan += i)
00969         {
00970         }
00971         *scan = '\0';
00972 
00973         /* close the pipe.  abort if error */
00974         if (rpclose(fd) != 0 || scan < tmpblk.c + 3)
00975         {
00976                 msg("tag \"%s\" not found", extra);
00977                 return;
00978         }
00979 
00980 #else /* use internal code to look up the tag */
00981         /* open the tags file */
00982         fd = open(TAGS, O_RDONLY);
00983         if (fd < 0)
00984         {
00985                 msg("No tags file");
00986                 return;
00987         }
00988 
00989         /* Hmmm... this would have been a lot easier with <stdio.h> */
00990 
00991         /* find the line with our tag in it */
00992         for(scan = end = tmpblk.c, cmp = extra; ; scan++)
00993         {
00994                 /* read a block, if necessary */
00995                 if (scan >= end)
00996                 {
00997                         end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
00998                         scan = tmpblk.c;
00999                         if (scan >= end)
01000                         {
01001                                 msg("tag \"%s\" not found", extra);
01002                                 close(fd);
01003                                 return;
01004                         }
01005                 }
01006 
01007                 /* if we're comparing, compare... */
01008                 if (cmp)
01009                 {
01010                         /* matched??? wow! */
01011                         if (!*cmp && *scan == '\t')
01012                         {
01013                                 break;
01014                         }
01015                         if (*cmp++ != *scan)
01016                         {
01017                                 /* failed! skip to newline */
01018                                 cmp = (char *)0;
01019                         }
01020                 }
01021 
01022                 /* if we're skipping to newline, do it fast! */
01023                 if (!cmp)
01024                 {
01025                         while (scan < end && *scan != '\n')
01026                         {
01027                                 scan++;
01028                         }
01029                         if (scan < end)
01030                         {
01031                                 cmp = extra;
01032                         }
01033                 }
01034         }
01035 
01036         /* found it! get the rest of the line into memory */
01037         for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
01038         {
01039                 *cmp++ = *scan++;
01040         }
01041         if (scan == end)
01042         {
01043                 tread(fd, cmp, BLKSIZE - (int)(cmp - tmpblk.c));
01044         }
01045         else
01046                 *cmp = *scan;
01047 
01048         /* we can close the tags file now */
01049         close(fd);
01050 #endif /* INTERNAL_TAGS */
01051 
01052         /* extract the filename from the line, and edit the file */
01053         for (scan = tmpblk.c; *scan != '\t'; scan++)
01054         {
01055         }
01056         *scan++ = '\0';
01057         if (strcmp(origname, tmpblk.c) != 0)
01058         {
01059                 if (!tmpabort(bang))
01060                 {
01061                         msg("Use :tag! to abort changes, or :w to save changes");
01062                         return;
01063                 }
01064                 tmpstart(tmpblk.c);
01065         }
01066 
01067         /* move to the desired line (or to line 1 if that fails) */
01068 #ifndef NO_MAGIC
01069         wasmagic = *o_magic;
01070         *o_magic = FALSE;
01071 #endif
01072         cursor = MARK_FIRST;
01073         linespec(scan, &cursor);
01074         if (cursor == MARK_UNSET)
01075         {
01076                 cursor = MARK_FIRST;
01077                 msg("Tag's address is out of date");
01078         }
01079 #ifndef NO_MAGIC
01080         *o_magic = wasmagic;
01081 #endif
01082 }
01083 
01084 
01085 
01086 
01087 
01088 /* describe this version of the program */
01089 /*ARGSUSED*/
01090 void cmd_version(frommark, tomark, cmd, bang, extra)
01091         MARK    frommark;
01092         MARK    tomark;
01093         CMD     cmd;
01094         int     bang;
01095         char    *extra;
01096 {
01097         msg("%s", VERSION);
01098 #ifdef CREDIT
01099         msg("%s", CREDIT);
01100 #endif
01101 #ifdef CREDIT2
01102         msg("%s", CREDIT2);
01103 #endif
01104 #ifdef COMPILED_BY
01105         msg("Compiled by %s", COMPILED_BY);
01106 #endif
01107 #ifdef COPYING
01108         msg("%s", COPYING);
01109 #endif
01110 }
01111 
01112 
01113 #ifndef NO_MKEXRC
01114 /* make a .exrc file which describes the current configuration */
01115 /*ARGSUSED*/
01116 void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
01117         MARK    frommark;
01118         MARK    tomark;
01119         CMD     cmd;
01120         int     bang;
01121         char    *extra;
01122 {
01123         int     fd;
01124 
01125         /* the default name for the .exrc file EXRC */
01126         if (!*extra)
01127         {
01128                 extra = EXRC;
01129         }
01130 
01131         /* create the .exrc file */
01132         fd = creat(extra, FILEPERMS);
01133         if (fd < 0)
01134         {
01135                 msg("Couldn't create a new \"%s\" file", extra);
01136                 return;
01137         }
01138 
01139         /* save stuff */
01140         saveopts(fd);
01141         savemaps(fd, FALSE);
01142 #ifndef NO_ABBR
01143         savemaps(fd, TRUE);
01144 #endif
01145 #ifndef NO_DIGRAPH
01146         savedigs(fd);
01147 #endif
01148 #ifndef NO_COLOR
01149         savecolor(fd);
01150 #endif
01151 
01152         /* close the file */
01153         close(fd);
01154         msg("Configuration saved");
01155 }
01156 #endif
01157 
01158 #ifndef NO_DIGRAPH
01159 /*ARGSUSED*/
01160 void cmd_digraph(frommark, tomark, cmd, bang, extra)
01161         MARK    frommark;
01162         MARK    tomark;
01163         CMD     cmd;
01164         int     bang;
01165         char    *extra;
01166 {
01167         do_digraph(bang, extra);
01168 }
01169 #endif
01170 
01171 
01172 #ifndef NO_ERRLIST 
01173 static char     errfile[256];   /* the name of a file containing an error */
01174 static long     errline;        /* the line number for an error */
01175 static int      errfd = -2;     /* fd of the errlist file */
01176 
01177 /* This static function tries to parse an error message.
01178  *
01179  * For most compilers, the first word is taken to be the name of the erroneous
01180  * file, and the first number after that is taken to be the line number where
01181  * the error was detected.  The description of the error follows, possibly
01182  * preceded by an "error ... :" or "warning ... :" label which is skipped.
01183  *
01184  * For Coherent, error messages look like "line#: filename: message".
01185  *
01186  * For non-error lines, or unparsable error lines, this function returns NULL.
01187  * Normally, though, it alters errfile and errline, and returns a pointer to
01188  * the description.
01189  */
01190 static char *parse_errmsg(text)
01191         REG char        *text;
01192 {
01193         REG char        *cpy;
01194         long            atol();
01195 # if COHERENT || TOS /* any Mark Williams compiler */
01196         /* Get the line number.  If no line number, then ignore this line. */
01197         errline = atol(text);
01198         if (errline == 0L)
01199                 return (char *)0;
01200 
01201         /* Skip to the start of the filename */
01202         while (*text && *text++ != ':')
01203         {
01204         }
01205         if (!*text++)
01206                 return (char *)0;
01207 
01208         /* copy the filename to errfile */
01209         for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; )
01210         {
01211         }
01212         if (!*text++)
01213                 return (char *)0;
01214         cpy[-1] = '\0';
01215 
01216         return text;
01217 # else /* not a Mark Williams compiler */
01218         char            *errmsg;
01219 
01220         /* the error message is the whole line, by default */
01221         errmsg = text;
01222 
01223         /* skip leading garbage */
01224         while (*text && !isalnum(*text))
01225         {
01226                 text++;
01227         }
01228 
01229         /* copy over the filename */
01230         cpy = errfile;
01231         while(isalnum(*text) || *text == '.')
01232         {
01233                 *cpy++ = *text++;
01234         }
01235         *cpy = '\0';
01236 
01237         /* ignore the name "Error" and filenames that contain a '/' */
01238         if (*text == '/' || !*errfile || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0)
01239         {
01240                 return (char *)0;
01241         }
01242 
01243         /* skip garbage between filename and line number */
01244         while (*text && !isdigit(*text))
01245         {
01246                 text++;
01247         }
01248 
01249         /* if the number is part of a larger word, then ignore this line */
01250         if (*text && isalpha(text[-1]))
01251         {
01252                 return (char *)0;
01253         }
01254 
01255         /* get the error line */
01256         errline = 0L;
01257         while (isdigit(*text))
01258         {
01259                 errline *= 10;
01260                 errline += (*text - '0');
01261                 text++;
01262         }
01263 
01264         /* any line which lacks a filename or line number should be ignored */
01265         if (!errfile[0] || !errline)
01266         {
01267                 return (char *)0;
01268         }
01269 
01270         /* locate the beginning of the error description */
01271         while (*text && !isspace(*text))
01272         {
01273                 text++;
01274         }
01275         while (*text)
01276         {
01277 #  ifndef CRUNCH
01278                 /* skip "error #:" and "warning #:" clauses */
01279                 if (!strncmp(text + 1, "rror ", 5)
01280                  || !strncmp(text + 1, "arning ", 7)
01281                  || !strncmp(text + 1, "atal error", 10))
01282                 {
01283                         do
01284                         {
01285                                 text++;
01286                         } while (*text && *text != ':');
01287                         continue;
01288                 }
01289 #  endif
01290 
01291                 /* anything other than whitespace or a colon is important */
01292                 if (!isspace(*text) && *text != ':')
01293                 {
01294                         errmsg = text;
01295                         break;
01296                 }
01297 
01298                 /* else keep looking... */
01299                 text++;
01300         }
01301 
01302         return errmsg;
01303 # endif /* not COHERENT */
01304 }
01305 
01306 /*ARGSUSED*/
01307 void cmd_errlist(frommark, tomark, cmd, bang, extra)
01308         MARK    frommark, tomark;
01309         CMD     cmd;
01310         int     bang;
01311         char    *extra;
01312 {
01313         static long     endline;/* original number of lines in this file */
01314         static long     offset; /* offset of the next line in the errlist file */
01315         int             i;
01316         char            *errmsg;
01317 
01318         /* if a new errlist file is named, open it */
01319         if (extra && extra[0])
01320         {
01321                 /* close the old one */
01322                 if (errfd >= 0)
01323                 {
01324                         close(errfd);
01325                 }
01326 
01327                 /* open the new one */
01328                 errfd = open(extra, O_RDONLY);
01329                 offset = 0L;
01330                 endline = nlines;
01331         }
01332         else if (errfd < 0)
01333         {
01334                 /* open the default file */
01335                 errfd = open(ERRLIST, O_RDONLY);
01336                 offset = 0L;
01337                 endline = nlines;
01338         }
01339 
01340         /* do we have an errlist file now? */
01341         if (errfd < 0)
01342         {
01343                 msg("There is no errlist file");
01344                 beep();
01345                 return;
01346         }
01347 
01348         /* find the next error message in the file */
01349         do
01350         {
01351                 /* read the next line from the errlist */
01352                 lseek(errfd, offset, 0);
01353                 if (tread(errfd, tmpblk.c, (unsigned)BLKSIZE) <= 0)
01354                 {
01355                         msg("No more errors");
01356                         beep();
01357                         close(errfd);
01358                         errfd = -2;
01359                         return;
01360                 }
01361                 for (i = 0; tmpblk.c[i] != '\n'; i++)
01362                 {
01363                 }
01364                 tmpblk.c[i++] = 0;
01365 
01366                 /* look for an error message in the line */
01367                 errmsg = parse_errmsg(tmpblk.c);
01368                 if (!errmsg)
01369                 {
01370                         offset += i;
01371                 }
01372 
01373         } while (!errmsg);
01374 
01375         /* switch to the file containing the error, if this isn't it */
01376         if (strcmp(origname, errfile))
01377         {
01378                 if (!tmpabort(bang))
01379                 {
01380                         msg("Use :er! to abort changes, or :w to save changes");
01381                         beep();
01382                         return;
01383                 }
01384                 tmpstart(errfile);
01385                 endline = nlines;
01386         }
01387         else if (endline == 0L)
01388         {
01389                 endline = nlines;
01390         }
01391 
01392         /* go to the line where the error was detected */
01393         cursor = MARK_AT_LINE(errline + (nlines - endline));
01394         if (cursor > MARK_LAST)
01395         {
01396                 cursor = MARK_LAST;
01397         }
01398         if (mode == MODE_VI)
01399         {
01400                 redraw(cursor, FALSE);
01401         }
01402 
01403         /* display the error message */
01404 #ifdef CRUNCH
01405         msg("%.70s", errmsg);
01406 #else
01407         if (nlines > endline)
01408         {
01409                 msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg);
01410         }
01411         else if (nlines < endline)
01412         {
01413                 msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg);
01414         }
01415         else
01416         {
01417                 msg("line %ld: %.65s", errline, errmsg);
01418         }
01419 #endif
01420 
01421         /* remember where the NEXT error line will start */
01422         offset += i;
01423 }
01424 
01425 
01426 /*ARGSUSED*/
01427 void cmd_make(frommark, tomark, cmd, bang, extra)
01428         MARK    frommark, tomark;
01429         CMD     cmd;
01430         int     bang;
01431         char    *extra;
01432 {
01433         BLK     buf;
01434 
01435         /* if the file hasn't been saved, then complain unless ! */
01436         if (tstflag(file, MODIFIED) && !bang)
01437         {
01438                 msg("\"%s\" not saved yet", origname);
01439                 return;
01440         }
01441 
01442         /* build the command */
01443         sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST);
01444         qaddstr(buf.c);
01445         addch('\n');
01446 
01447         /* close the old errlist file, if any */
01448         if (errfd >= 0)
01449         {
01450                 close(errfd);
01451                 errfd = -3;
01452         }
01453 
01454         /* run the command, with curses temporarily disabled */
01455         suspend_curses();
01456         system(buf.c);
01457         resume_curses(mode == MODE_EX);
01458         if (mode == MODE_COLON)
01459                 mode = MODE_VI;
01460 
01461         /* run the "errlist" command */
01462         cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST);
01463 }
01464 #endif
01465 
01466 
01467 
01468 #ifndef NO_COLOR
01469 
01470 /* figure out the number of text colors we use with this configuration */
01471 # ifndef NO_POPUP
01472 #  ifndef NO_VISIBLE
01473 #   define NCOLORS 7
01474 #  else
01475 #   define NCOLORS 6
01476 #  endif
01477 # else
01478 #  ifndef NO_VISIBLE
01479 #   define NCOLORS 6
01480 #  else
01481 #   define NCOLORS 5
01482 #  endif
01483 # endif
01484 
01485 /* the attribute bytes used in each of "when"s */
01486 static char bytes[NCOLORS];
01487 
01488 static struct
01489 {
01490         char    *word;  /* a legal word */
01491         int     type;   /* what type of word this is */
01492         int     val;    /* some other value */
01493 }
01494         words[] =
01495 {
01496         {"normal",      1,      A_NORMAL},      /* all "when" names must come */
01497         {"standout",    1,      A_STANDOUT},    /* at the top of the list.    */
01498         {"bold",        1,      A_BOLD},        /* The first 3 must be normal,*/
01499         {"underlined",  1,      A_UNDERLINE},   /* standout, and bold; the    */
01500         {"italics",     1,      A_ALTCHARSET},  /* remaining names follow.    */
01501 #ifndef NO_POPUP
01502         {"popup",       1,      A_POPUP},
01503 #endif
01504 #ifndef NO_VISIBLE
01505         {"visible",     1,      A_VISIBLE},
01506 #endif
01507 
01508         {"black",       3,      0x00},          /* The color names start right*/
01509         {"blue",        3,      0x01},          /* after the "when" names.    */
01510         {"green",       3,      0x02},
01511         {"cyan",        3,      0x03},
01512         {"red",         3,      0x04},
01513         {"magenta",     3,      0x05},
01514         {"brown",       3,      0x06},
01515         {"white",       3,      0x07},
01516         {"yellow",      3,      0x0E}, /* bright brown */
01517         {"gray",        3,      0x08}, /* bright black?  of course! */
01518         {"grey",        3,      0x08},
01519 
01520         {"bright",      2,      0x08},
01521         {"light",       2,      0x08},
01522         {"blinking",    2,      0x80},
01523         {"on",          0,      0},
01524         {"n",           1,      A_NORMAL},
01525         {"s",           1,      A_STANDOUT},
01526         {"b",           1,      A_BOLD},
01527         {"u",           1,      A_UNDERLINE},
01528         {"i",           1,      A_ALTCHARSET},
01529 #ifndef NO_POPUP
01530         {"p",           1,      A_POPUP},
01531         {"menu",        1,      A_POPUP},
01532 #endif
01533 #ifndef NO_VISIBLE
01534         {"v",           1,      A_VISIBLE},
01535 #endif
01536         {(char *)0,     0,      0}
01537 };
01538 
01539 /*ARGSUSED*/
01540 void cmd_color(frommark, tomark, cmd, bang, extra)
01541         MARK    frommark, tomark;
01542         CMD     cmd;
01543         int     bang;
01544         char    *extra;
01545 {
01546         int     attrbyte;
01547         int     cmode;
01548         int     nowbg;  /* BOOLEAN: is the next color background? */
01549 
01550         REG char *scan;
01551         REG     i;
01552 
01553 
01554 #ifndef CRUNCH
01555         /* if no args are given, then report the current colors */
01556         if (!*extra)
01557         {
01558                 /* if no colors are set, then say so */
01559                 if (!bytes[0])
01560                 {
01561                         msg("no colors have been set");
01562                         return;
01563                 }
01564 
01565                 /* report all five color combinations */
01566                 for (i = 0; i < NCOLORS; i++)
01567                 {
01568                         qaddstr("color ");
01569                         qaddstr(words[i].word);
01570                         qaddch(' ');
01571                         if (bytes[i] & 0x80)
01572                                 qaddstr("blinking ");
01573                         switch (bytes[i] & 0xf)
01574                         {
01575                           case 0x08:    qaddstr("gray");        break;
01576                           case 0x0e:    qaddstr("yellow");      break;
01577                           case 0x0f:    qaddstr("bright white");break;
01578                           default:
01579                                 if (bytes[i] & 0x08)
01580                                         qaddstr("light ");
01581                                 qaddstr(words[(bytes[i] & 0x07) + NCOLORS].word);
01582                         }
01583                         qaddstr(" on ");
01584                         qaddstr(words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
01585                         addch('\n');
01586                         exrefresh();
01587                 }
01588                 return;
01589         }
01590 #endif
01591 
01592         /* The default background color is the same as "normal" chars.
01593          * There is no default foreground color.
01594          */
01595         cmode = A_NORMAL;
01596         attrbyte = bytes[0] & 0x70;
01597         nowbg = FALSE;
01598 
01599         /* parse each word in the "extra" text */
01600         for (scan = extra; *extra; extra = scan)
01601         {
01602                 /* locate the end of the word */
01603                 while (*scan && *scan != ' ')
01604                 {
01605                         scan++;
01606                 }
01607 
01608                 /* skip whitespace at the end of the word */
01609                 while(*scan == ' ')
01610                 {
01611                         *scan++ = '\0';
01612                 }
01613 
01614                 /* lookup the word */
01615                 for (i = 0; words[i].word && strcmp(words[i].word, extra); i++)
01616                 {
01617                 }
01618 
01619                 /* if not a word, then complain */
01620                 if (!words[i].word)
01621                 {
01622                         msg("Invalid color name: %s", extra);
01623                         return;
01624                 }
01625 
01626                 /* process the word */
01627                 switch (words[i].type)
01628                 {
01629                   case 1:
01630                         cmode = words[i].val;
01631                         break;
01632 
01633                   case 2:
01634                         attrbyte |= words[i].val;
01635                         break;
01636 
01637                   case 3:
01638                         if (nowbg)
01639                                 attrbyte = ((attrbyte & ~0x70) | ((words[i].val & 0x07) << 4));
01640                         else
01641                                 attrbyte |= words[i].val;
01642                         nowbg = TRUE;
01643                         break;
01644                 }
01645         }
01646 
01647         /* if nowbg isn't set now, then we were never given a foreground color */
01648         if (!nowbg)
01649         {
01650                 msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]");
01651                 return;
01652         }
01653 
01654         /* the first ":color" command MUST define the "normal" colors */
01655         if (!bytes[0])
01656                 cmode = A_NORMAL;
01657 
01658         /* we should now have a cmode and an attribute byte... */
01659 
01660         /* set the color */
01661         setcolor(cmode, attrbyte);
01662 
01663         /* remember what we just did */
01664         bytes[cmode] = attrbyte;
01665 
01666         /* if the other colors haven't been set yet, then set them to defaults */
01667         if (!bytes[1])
01668         {
01669                 /* standout is the opposite of normal */
01670                 bytes[1] = ((attrbyte << 4) & 0x70 | (attrbyte >> 4) & 0x07);
01671                 setcolor(A_STANDOUT, bytes[1]);
01672 
01673                 /* if "normal" isn't bright, then bold defaults to normal+bright
01674                  * else bold defaults to bright white.
01675                  */
01676                 bytes[2] = attrbyte | ((attrbyte & 0x08) ? 0x0f : 0x08);
01677                 setcolor(A_BOLD, bytes[2]);
01678 
01679                 /* all others default to the "standout" colors, without blinking */
01680                 for (i = 3; i < NCOLORS; i++)
01681                 {
01682                         bytes[i] = (bytes[1] & 0x7f);
01683                         setcolor(words[i].val, bytes[i]);
01684                 }
01685         }
01686 
01687         /* force a redraw, so we see the new colors */
01688         redraw(MARK_UNSET, FALSE);
01689 }
01690 
01691 
01692 
01693 void savecolor(fd)
01694         int     fd;     /* file descriptor to write colors to */
01695 {
01696         int     i;
01697         char    buf[80];
01698 
01699         /* if no colors are set, then return */
01700         if (!bytes[0])
01701         {
01702                 return;
01703         }
01704 
01705         /* save all five color combinations */
01706         for (i = 0; i < NCOLORS; i++)
01707         {
01708                 strcpy(buf, "color ");
01709                 strcat(buf, words[i].word);
01710                 strcat(buf, " ");
01711                 if (bytes[i] & 0x80)
01712                         strcat(buf, "blinking ");
01713                 switch (bytes[i] & 0xf)
01714                 {
01715                   case 0x08:    strcat(buf, "gray");    break;
01716                   case 0x0e:    strcat(buf, "yellow");  break;
01717                   case 0x0f:    strcat(buf, "bright white");break;
01718                   default:
01719                         if (bytes[i] & 0x08)
01720                                 strcat(buf, "light ");
01721                         strcat(buf, words[(bytes[i] & 0x07) + NCOLORS].word);
01722                 }
01723                 strcat(buf, " on ");
01724                 strcat(buf, words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
01725                 strcat(buf, "\n");
01726                 twrite(fd, buf, (unsigned)strlen(buf));
01727         }
01728 }
01729 #endif
01730 
01731 #ifdef SIGTSTP
01732 /* temporarily suspend elvis */
01733 /*ARGSUSED*/
01734 void cmd_suspend(frommark, tomark, cmd, bang, extra)
01735         MARK    frommark;
01736         MARK    tomark;
01737         CMD     cmd;
01738         int     bang;
01739         char    *extra;
01740 {
01741         void    (*func)();      /* stores the previous setting of SIGTSTP */
01742 
01743 #if ANY_UNIX
01744         /* the Bourne shell can't handle ^Z */
01745         if (!strcmp(o_shell, "/bin/sh"))
01746         {
01747                 msg("The /bin/sh shell doesn't support ^Z");
01748                 return;
01749         }
01750 #endif
01751 
01752         move(LINES - 1, 0);
01753         if (tstflag(file, MODIFIED))
01754         {
01755                 addstr("Warning: \"");
01756                 addstr(origname);
01757                 addstr("\" modified but not yet saved");
01758                 clrtoeol();
01759         }
01760         refresh();
01761         suspend_curses();
01762         func = signal(SIGTSTP, SIG_DFL);
01763         kill (0, SIGTSTP);
01764 
01765         /* the process stops and resumes here */
01766 
01767         signal(SIGTSTP, func);
01768         resume_curses(TRUE);
01769         if (mode == MODE_VI || mode == MODE_COLON)
01770                 redraw(MARK_UNSET, FALSE);
01771         else
01772                 refresh ();
01773 }
01774 #endif

Generated on Fri Apr 14 22:56:52 2006 for minix by  doxygen 1.4.6