home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1705 / cmd1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  16.7 KB  |  923 lines

  1. /* cmd1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains some of the EX commands - mostly ones that deal with
  12.  * files, options, etc. -- anything except text.
  13.  */
  14.  
  15. #include "config.h"
  16. #include <ctype.h>
  17. #include "vi.h"
  18. #include "regexp.h"
  19.  
  20. #if    MSDOS
  21. #define    DATE __DATE__
  22. #endif
  23.  
  24. #ifdef DEBUG
  25. /* print the selected lines with info on the blocks */
  26. /*ARGSUSED*/
  27. void cmd_debug(frommark, tomark, cmd, bang, extra)
  28.     MARK    frommark;
  29.     MARK    tomark;
  30.     CMD    cmd;
  31.     int    bang;
  32.     char    *extra;
  33. {
  34.     register char    *scan;
  35.     register long    l;
  36.     register int    i;
  37.     int        len;
  38.  
  39.     /* scan lnum[] to determine which block its in */
  40.     l = markline(frommark);
  41.     for (i = 1; l > lnum[i]; i++)
  42.     {
  43.     }
  44.  
  45.     do
  46.     {
  47.         /* fetch text of the block containing that line */
  48.         scan = blkget(i)->c;
  49.  
  50.         /* calculate its length */
  51.         if (scan[BLKSIZE - 1])
  52.         {
  53.             len = BLKSIZE;
  54.         }
  55.         else
  56.         {
  57.             len = strlen(scan);
  58.         }
  59.  
  60.         /* print block stats */
  61.         msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
  62.             i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
  63.         msg("##### len=%d, buf=0x%lx, %sdirty",
  64.             len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
  65.         if (bang)
  66.         {
  67.             while (--len >= 0)
  68.             {
  69.                 addch(*scan);
  70.                 scan++;
  71.             }
  72.         }
  73.         exrefresh();
  74.  
  75.         /* next block */
  76.         i++;
  77.     } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
  78. }
  79.  
  80.  
  81. /* This function checks a lot of conditions to make sure they aren't screwy */
  82. /*ARGSUSED*/
  83. void cmd_validate(frommark, tomark, cmd, bang, extra)
  84.     MARK    frommark;
  85.     MARK    tomark;
  86.     CMD    cmd;
  87.     int    bang;
  88.     char    *extra;
  89. {
  90.     char    *scan;
  91.     int    i;
  92.     int    nlcnt;    /* used to count newlines */
  93.     int    len;    /* counts non-NUL characters */
  94.  
  95.     /* check lnum[0] */
  96.     if (lnum[0] != 0L)
  97.     {
  98.         msg("lnum[0] = %ld", lnum[0]);
  99.     }
  100.  
  101.     /* check each block */
  102.     for (i = 1; lnum[i] <= nlines; i++)
  103.     {
  104.         scan = blkget(i)->c;
  105.         if (scan[BLKSIZE - 1])
  106.         {
  107.             msg("block %d has no NUL at the end", i);
  108.         }
  109.         else
  110.         {
  111.             for (nlcnt = len = 0; *scan; scan++, len++)
  112.             {
  113.                 if (*scan == '\n')
  114.                 {
  115.                     nlcnt++;
  116.                 }
  117.             }
  118.             if (scan[-1] != '\n')
  119.             {
  120.                 msg("block %d doesn't end with '\\n' (length %d)", i, len);
  121.             }
  122.             if (bang || nlcnt != lnum[i] - lnum[i - 1])
  123.             {
  124.                 msg("block %d (line %ld?) has %d lines, but should have %ld",
  125.                     i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
  126.             }
  127.         }
  128.         exrefresh();
  129.     }
  130.  
  131.     /* check lnum again */
  132.     if (lnum[i] != INFINITY)
  133.     {
  134.         msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
  135.             i, hdr.n[i], i, lnum[i]);
  136.     }
  137.  
  138.     msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
  139. }
  140. #endif /* DEBUG */
  141.  
  142.  
  143. /*ARGSUSED*/
  144. void cmd_mark(frommark, tomark, cmd, bang, extra)
  145.     MARK    frommark;
  146.     MARK    tomark;
  147.     CMD    cmd;
  148.     int    bang;
  149.     char    *extra;
  150. {
  151.     /* validate the name of the mark */
  152.     if (!extra || *extra < 'a' || *extra > 'z' || extra[1])
  153.     {
  154.         msg("Invalid mark name");
  155.         return;
  156.     }
  157.  
  158.     mark[*extra - 'a'] = tomark;
  159. }
  160.  
  161. /*ARGSUSED*/
  162. void cmd_write(frommark, tomark, cmd, bang, extra)
  163.     MARK    frommark;
  164.     MARK    tomark;
  165.     CMD    cmd;
  166.     int    bang;
  167.     char    *extra;
  168. {
  169.     int        fd;
  170.     int        append;    /* boolean: write in "append" mode? */
  171.     register long    l;
  172.     register char    *scan;
  173.     register int    i;
  174.  
  175.     /* if all lines are to be written, use tmpsave() */
  176.     if (frommark == MARK_FIRST && tomark == MARK_LAST)
  177.     {
  178.         tmpsave(extra, bang);
  179.         return;
  180.     }
  181.  
  182.     /* see if we're going to do this in append mode or not */
  183.     append = FALSE;
  184.     if (extra[0] == '>' && extra[1] == '>')
  185.     {
  186.         extra += 2;
  187.         append = TRUE;
  188.     }
  189.  
  190.     /* either the file must not exist, or we must have a ! or be appending */
  191.     if (access(extra, 0) == 0 && !bang && !append)
  192.     {
  193.         msg("File already exists - Use :w! to overwrite");
  194.         return;
  195.     }
  196.  
  197.     /* else do it line-by-line, like cmd_print() */
  198.     if (append)
  199.     {
  200. #ifdef O_APPEND
  201.         fd = open(extra, O_WRONLY|O_APPEND);
  202. #else
  203.         fd = open(extra, O_WRONLY);
  204.         if (fd >= 0)
  205.         {
  206.             lseek(fd, 0L, 2);
  207.         }
  208. #endif
  209.     }
  210.     else
  211.     {
  212.         fd = creat(extra, 0666);
  213.     }
  214.  
  215.     if (fd < 0)
  216.     {
  217.         fd = creat(extra, 0644);
  218.         if (fd < 0)
  219.         {
  220.             msg("Can't write to \"%s\"", extra);
  221.             return;
  222.         }
  223.     }
  224.     for (l = markline(frommark); l <= markline(tomark); l++)
  225.     {
  226.         /* get the next line */
  227.         scan = fetchline(l);
  228.         i = strlen(scan);
  229.         scan[i++] = '\n';
  230.  
  231.         /* print the line */
  232.         twrite(fd, scan, i);
  233.     }
  234.     close(fd);
  235. }    
  236.  
  237.  
  238. /*ARGSUSED*/
  239. void cmd_shell(frommark, tomark, cmd, bang, extra)
  240.     MARK    frommark, tomark;
  241.     CMD    cmd;
  242.     int    bang;
  243.     char    *extra;
  244. {
  245.     static char    prevextra[80];
  246.  
  247.     /* special case: ":sh" means ":!sh" */
  248.     if (cmd == CMD_SHELL)
  249.     {
  250.         extra = o_shell;
  251.         frommark = tomark = 0L;
  252.     }
  253.  
  254.     /* if extra is "!", substute previous command */
  255.     if (*extra == '!')
  256.     {
  257.         if (!*prevextra)
  258.         {
  259.             msg("No previous shell command to substitute for '!'");
  260.             return;
  261.         }
  262.         extra = prevextra;
  263.     }
  264.     else
  265.     {
  266.         strcpy(prevextra, extra);
  267.     }
  268.  
  269.     /* if no lines were specified, just run the command */
  270.     suspend_curses();
  271.     if (frommark == 0L)
  272.     {
  273.         system(extra);
  274.     }
  275.     else /* pipe lines from the file through the command */
  276.     {
  277.         filter(frommark, tomark, extra);
  278.     }
  279.  
  280.     /* resume curses quietly for MODE_EX, but noisily otherwise */
  281.     resume_curses(mode == MODE_EX);
  282. }
  283.  
  284.  
  285. /*ARGSUSED*/
  286. void cmd_global(frommark, tomark, cmd, bang, extra)
  287.     MARK    frommark, tomark;
  288.     CMD    cmd;
  289.     int    bang;
  290.     char    *extra;    /* rest of the command line */
  291. {
  292.     char    *cmdptr;    /* the command from the command line */
  293.     char    cmdln[100];    /* copy of the command from the command line */
  294.     char    *line;        /* a line from the file */
  295.     long    l;        /* used as a counter to move through lines */
  296.     long    lqty;        /* quantity of lines to be scanned */
  297.     regexp    *re;        /* the compiled search expression */
  298.  
  299.     /* ":g! ..." is the same as ":v ..." */
  300.     if (bang)
  301.     {
  302.         cmd = CMD_VGLOBAL;
  303.     }
  304.  
  305.     /* make sure we got a search pattern */
  306.     if (*extra != '/' && *extra != '?')
  307.     {
  308.         msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
  309.         return;
  310.     }
  311.  
  312.     /* parse & compile the search pattern */
  313.     cmdptr = parseptrn(extra);
  314.     if (!extra[1])
  315.     {
  316.         msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
  317.         return;
  318.     }
  319.     re = regcomp(extra + 1);
  320.     if (!re)
  321.     {
  322.         /* regcomp found & described an error */
  323.         return;
  324.     }
  325.  
  326.     /* for each line in the range */
  327.     ChangeText
  328.     {
  329.         /* NOTE: we have to go through the lines in a forward order,
  330.          * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
  331.          * to work, simply adding 1 to the line# on each loop won't
  332.          * work.  The solution: count lines relative to the end of
  333.          * the file.  Think about it.
  334.          */
  335.         for (l = nlines - markline(frommark), lqty = markline(tomark) - markline(frommark) + 1L;
  336.              lqty > 0 && nlines - l >= 0;
  337.              l--, lqty--)
  338.         {
  339.             /* fetch the line */
  340.             line = fetchline(nlines - l);
  341.  
  342.             /* if it contains the search pattern... */
  343.             if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
  344.             {
  345.                 /* move the cursor to that line */
  346.                 cursor = MARK_AT_LINE(nlines - l);
  347.  
  348.                 /* do the ex command (without mucking up
  349.                  * the original copy of the command line)
  350.                  */
  351.                 strcpy(cmdln, cmdptr);
  352.                 doexcmd(cmdln);
  353.             }
  354.         }
  355.     }
  356.  
  357.     /* free the regexp */
  358.     free(re);
  359. }
  360.  
  361.  
  362. /*ARGSUSED*/
  363. void cmd_file(frommark, tomark, cmd, bang, extra)
  364.     MARK    frommark, tomark;
  365.     CMD    cmd;
  366.     int    bang;
  367.     char    *extra;
  368. {
  369.     if (frommark == tomark)
  370.     {
  371.         msg( "\"%s\" %s%s %ld lines, this is line %ld  [%ld%%]",
  372.             *origname ? origname : "[NO FILE]",
  373.             tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
  374.             tstflag(file, READONLY) ? "[READONLY]" : "",
  375.             nlines,
  376.             markline(frommark),
  377.             markline(frommark) * 100 / nlines);
  378.     }
  379.     else
  380.     {
  381.         msg( "\"%s\" %s%s %ld lines, range  %ld,%ld  contains %ld lines",
  382.             *origname ? origname : "[NO FILE]",
  383.             tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
  384.             tstflag(file, READONLY) ? "[READONLY]" : "",
  385.             nlines,
  386.             markline(frommark), markline(tomark),
  387.             markline(tomark) - markline(frommark) + 1L);
  388.     }
  389. }
  390.  
  391.  
  392. /*ARGSUSED*/
  393. void cmd_edit(frommark, tomark, cmd, bang, extra)
  394.     MARK    frommark, tomark;
  395.     CMD    cmd;
  396.     int    bang;
  397.     char    *extra;
  398. {
  399.     long    line = 1L;    /* might be set to prevline */
  400.  
  401.     if (!strcmp(extra, prevorig))
  402.     {
  403.         line = prevline;
  404.     }
  405.  
  406.     /* switch files */
  407.     if (tmpabort(bang))
  408.     {
  409.         tmpstart(extra);
  410.         if (line <= nlines && line >= 1L)
  411.         {
  412.             cursor = MARK_AT_LINE(line);
  413.         }
  414.     }
  415.     else
  416.     {
  417.         msg("Use edit! to abort changes, or w to save changes");
  418.  
  419.         /* so we can say ":e!" with no filename next time... */
  420.         strcpy(prevorig, extra);
  421.         prevline = 1L;
  422.     }
  423. }
  424.  
  425. /* This code is also used for rewind -- GB */
  426.  
  427. /*ARGSUSED*/
  428. void cmd_next(frommark, tomark, cmd, bang, extra)
  429.     MARK    frommark, tomark;
  430.     CMD    cmd;
  431.     int    bang;
  432.     char    *extra;
  433. {
  434.     int    i, j;
  435.     char    *scan;
  436.     char    *build;
  437.  
  438.     /* if extra stuff given, use ":args" to define a new args list */
  439.     if (cmd == CMD_NEXT && extra && *extra)
  440.     {
  441.         cmd_args(frommark, tomark, cmd, bang, extra);
  442.     }
  443.  
  444.     /* move to the next arg */
  445.     if (cmd == CMD_NEXT)
  446.     {
  447.         i = argno + 1;
  448.     }
  449.     else if (cmd == CMD_PREVIOUS)
  450.     {
  451.         i = argno - 1;
  452.     }
  453.     else /* cmd == CMD_REWIND */
  454.     {
  455.         i = 0;
  456.     }    
  457.     if (i < 0 || i >= nargs)
  458.     {
  459.         msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
  460.         return;
  461.     }
  462.  
  463.     /* find & isolate the name of the file to edit */
  464.     for (j = i, scan = args; j > 0; j--)
  465.     {
  466.         while(!isascii(*scan) || !isspace(*scan))
  467.         {
  468.             scan++;
  469.         }
  470.         while (isascii(*scan) && isspace(*scan))
  471.         {
  472.             scan++;
  473.         }
  474.     }
  475.     for (build = tmpblk.c; *scan && (!isascii(*scan) || !isspace(*scan)); )
  476.     {
  477.         *build++ = *scan++;
  478.     }
  479.     *build = '\0';
  480.  
  481.     /* switch to the next file */
  482.     if (tmpabort(bang))
  483.     {
  484.         tmpstart(tmpblk.c);
  485.         argno = i;
  486.     }
  487.     else
  488.     {
  489.         msg("Use :%s! to abort changes, or w to save changes",
  490.             cmd == CMD_NEXT ? "next" :
  491.             cmd == CMD_PREVIOUS ? "previous" :
  492.                     "rewind");
  493.     }
  494. }
  495.  
  496. /* also called from :wq -- always writes back in this case */
  497.  
  498. /*ARGSUSED*/
  499. void cmd_xit(frommark, tomark, cmd, bang, extra)
  500.     MARK    frommark, tomark;
  501.     CMD    cmd;
  502.     int    bang;
  503.     char    *extra;
  504. {
  505.     static long    whenwarned;    /* when the user was last warned of extra files */
  506.     int        oldflag;
  507.  
  508.     /* if there are more files to edit, then warn user */
  509.     if (argno + 1 < nargs && whenwarned != changes)
  510.     {
  511.         msg("More files to edit -- Use \":n\" to go to next file");
  512.         whenwarned = changes;
  513.         return;
  514.     }
  515.  
  516.     /* else try to save this file */
  517.     oldflag = tstflag(file, MODIFIED);
  518.     if (cmd == CMD_WQUIT)
  519.         setflag(file, MODIFIED);
  520.     if (tmpend(bang))
  521.     {
  522.         mode = MODE_QUIT;
  523.     }
  524.     else
  525.     {
  526.         msg("Could not save file -- use quit! to abort changes, or w filename");
  527.     }
  528.     if (!oldflag)
  529.         clrflag(file, MODIFIED);
  530. }
  531.  
  532.  
  533. void cmd_args(frommark, tomark, cmd, bang, extra)
  534.     MARK    frommark, tomark;
  535.     CMD    cmd;
  536.     int    bang;
  537.     char    *extra;
  538. {
  539.     char    *scan;
  540.     char    *eow;
  541.     int    col;
  542.     int    arg;
  543.     int    addcols;
  544.     int    scrolled = 0;
  545.  
  546.     /* if no extra names given, or just current name, then report the args
  547.      * we have now.
  548.      */
  549.     if (!extra || !*extra)
  550.     {
  551.         for (scan = args, col=arg=0; *scan; )
  552.         {
  553.             while (*scan && isascii(*scan) && isspace(*scan))
  554.                 scan++;
  555.             eow = scan;
  556.             while (*eow && (!isascii(*++eow) || !isspace(*eow)))
  557.                 ;
  558.             if (arg == argno)
  559.                 addcols = 2;
  560.             else
  561.                 addcols = 0;    
  562.             if (col+addcols+(int)(eow-scan)+1>=COLS)
  563.             {
  564.                 addch('\n');
  565.                 scrolled=1;
  566.                 col=0;
  567.             }
  568.             else if (arg)
  569.             {    qaddch(' ');
  570.                 col++;
  571.             }
  572.             if (arg == argno)
  573.                 qaddch('[');
  574.             while (scan < eow)
  575.             {    qaddch(*scan++);
  576.                 col++;
  577.             }
  578.             if (arg == argno)
  579.                 qaddch(']');    
  580.             arg++;    
  581.             col+=addcols;
  582.         }
  583.         /* write a trailing newline */
  584.         if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
  585.             addch('\n');
  586.         exrefresh();    
  587.     }
  588.     else /* new args list given */
  589.     {
  590.         strcpy(args, extra);
  591.         argno = -1; /* before the first, so :next will go to first */
  592.  
  593.         /* count the names */
  594.         for (nargs = 0, scan = args; *scan; nargs++)
  595.         {
  596.             while (*scan && (!isascii(*scan) || !isspace(*scan)))
  597.             {
  598.                 scan++;
  599.             }
  600.             while (isascii(*scan) && isspace(*scan))
  601.             {
  602.                 scan++;
  603.             }
  604.         }
  605.         msg("%d files to edit", nargs);
  606.     }
  607. }
  608.  
  609.  
  610. /*ARGSUSED*/
  611. void cmd_cd(frommark, tomark, cmd, bang, extra)
  612.     MARK    frommark, tomark;
  613.     CMD    cmd;
  614.     int    bang;
  615.     char    *extra;
  616. {
  617.     char    *getenv();
  618.  
  619.     /* default directory name is $HOME */
  620.     if (!*extra)
  621.     {
  622.         extra = getenv("HOME");
  623.         if (!extra)
  624.         {
  625.             msg("environment variable $HOME not set");
  626.             return;
  627.         }
  628.     }
  629.  
  630.     /* go to the directory */
  631.     if (chdir(extra) < 0)
  632.     {
  633.         perror(extra);
  634.     }
  635. }
  636.  
  637.  
  638. /*ARGSUSED*/
  639. void cmd_map(frommark, tomark, cmd, bang, extra)
  640.     MARK    frommark, tomark;
  641.     CMD    cmd;
  642.     int    bang;
  643.     char    *extra;
  644. {
  645.     char    *mapto;
  646.  
  647.     /* "map" with no extra will dump the map table contents */
  648.     if (!*extra)
  649.     {
  650.         dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD);
  651.     }
  652.     else
  653.     {
  654.         /* "extra" is key to map, followed my what it maps to */
  655.         for (mapto = extra; *mapto && *mapto != ' ' && *mapto!= '\t'; mapto++)
  656.         {
  657.         }
  658.         while (*mapto == ' ' || *mapto == '\t')
  659.         {
  660.             *mapto++ = '\0';
  661.         }
  662.  
  663.         mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
  664.     }
  665. }
  666.  
  667.  
  668. /*ARGSUSED*/
  669. void cmd_set(frommark, tomark, cmd, bang, extra)
  670.     MARK    frommark, tomark;
  671.     CMD    cmd;
  672.     int    bang;
  673.     char    *extra;
  674. {
  675.     if (!*extra)
  676.     {
  677.         dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
  678.     }
  679.     else if (!strcmp(extra, "all"))
  680.     {
  681.         dumpopts(TRUE);    /* "TRUE" means "dump all" - even unset vars */
  682.     }
  683.     else
  684.     {
  685.         setopts(extra);
  686.  
  687.         /* That option may have affected the appearence of text */
  688.         changes++;
  689.     }
  690. }
  691.  
  692. /*ARGSUSED*/
  693. void cmd_tag(frommark, tomark, cmd, bang, extra)
  694.     MARK    frommark, tomark;
  695.     CMD    cmd;
  696.     int    bang;
  697.     char    *extra;
  698. {
  699.     char    *scan;    /* used to scan through the tmpblk.c */
  700.     char    *cmp;    /* char of tag name we're comparing, or NULL */
  701.     char    *end;    /* marks the end of chars in tmpblk.c */
  702.     int    fd;    /* file descriptor used to read the file */
  703. #ifndef NO_MAGIC
  704.     char    wasmagic; /* preserves the original state of o_magic */
  705. #endif
  706.     static char prevtag[30];
  707.  
  708.     /* if no tag is given, use the previous tag */
  709.     if (!extra || !*extra)
  710.     {
  711.         if (!*prevtag)
  712.         {
  713.             msg("No previous tag");
  714.             return;
  715.         }
  716.         extra = prevtag;
  717.     }
  718.     else
  719.     {
  720.         strncpy(prevtag, extra, sizeof prevtag);
  721.     }
  722.  
  723.     /* open the tags file */
  724.     fd = open(TAGS, O_RDONLY);
  725.     if (fd < 0)
  726.     {
  727.         msg("No tags file");
  728.         return;
  729.     }
  730.  
  731.     /* Hmmm... this would have been a lot easier with <stdio.h> */
  732.  
  733.     /* find the line with our tag in it */
  734.     for(scan = end = tmpblk.c, cmp = extra; ; scan++)
  735.     {
  736.         /* read a block, if necessary */
  737.         if (scan >= end)
  738.         {
  739.             end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
  740.             scan = tmpblk.c;
  741.             if (scan >= end)
  742.             {
  743.                 msg("tag \"%s\" not found", extra);
  744.                 close(fd);
  745.                 return;
  746.             }
  747.         }
  748.  
  749.         /* if we're comparing, compare... */
  750.         if (cmp)
  751.         {
  752.             /* matched??? wow! */
  753.             if (!*cmp && *scan == '\t')
  754.             {
  755.                 break;
  756.             }
  757.             if (*cmp++ != *scan)
  758.             {
  759.                 /* failed! skip to newline */
  760.                 cmp = (char *)0;
  761.             }
  762.         }
  763.  
  764.         /* if we're skipping to newline, do it fast! */
  765.         if (!cmp)
  766.         {
  767.             while (scan < end && *scan != '\n')
  768.             {
  769.                 scan++;
  770.             }
  771.             if (scan < end)
  772.             {
  773.                 cmp = extra;
  774.             }
  775.         }
  776.     }
  777.  
  778.     /* found it! get the rest of the line into memory */
  779.     for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
  780.     {
  781.         *cmp++ = *scan++;
  782.     }
  783.     if (scan == end)
  784.     {
  785.         tread(fd, cmp, BLKSIZE - (cmp - tmpblk.c));
  786.     }
  787.  
  788.     /* we can close the tags file now */
  789.     close(fd);
  790.  
  791.     /* extract the filename from the line, and edit the file */
  792.     for (cmp = tmpblk.c; *cmp != '\t'; cmp++)
  793.     {
  794.     }
  795.     *cmp++ = '\0';
  796.     if (strcmp(origname, tmpblk.c) != 0)
  797.     {
  798.         if (!tmpabort(bang))
  799.         {
  800.             msg("Use :tag! to abort changes, or :w to save changes");
  801.             return;
  802.         }
  803.         tmpstart(tmpblk.c);
  804.     }
  805.  
  806.     /* move to the desired line (or to line 1 if that fails) */
  807. #ifndef NO_MAGIC
  808.     wasmagic = *o_magic;
  809.     *o_magic = FALSE;
  810. #endif
  811.     cursor = MARK_FIRST;
  812.     linespec(cmp, &cursor);
  813.     if (cursor == MARK_UNSET)
  814.     {
  815.         cursor = MARK_FIRST;
  816.     }
  817. #ifndef NO_MAGIC
  818.     *o_magic = wasmagic;
  819. #endif
  820. }
  821.  
  822.  
  823. /*ARGSUSED*/
  824. void cmd_visual(frommark, tomark, cmd, bang, extra)
  825.     MARK    frommark, tomark;
  826.     CMD    cmd;
  827.     int    bang;
  828.     char    *extra;
  829. {
  830.     mode = MODE_VI;
  831. }
  832.  
  833. /*ARGSUSED*/
  834. void cmd_quit(frommark, tomark, cmd, bang, extra)
  835.     MARK    frommark, tomark;
  836.     CMD    cmd;
  837.     int    bang;
  838.     char    *extra;
  839. {
  840.     if (tmpabort(bang))
  841.     {
  842.         mode = MODE_QUIT;
  843.     }
  844.     else
  845.     {
  846.         msg("Use q! to abort changes, or wq to save changes");
  847.     }
  848. }
  849.  
  850.  
  851.  
  852. /* describe this version of the program */
  853. /*ARGSUSED*/
  854. void cmd_version(frommark, tomark, cmd, bang, extra)
  855.     MARK    frommark;
  856.     MARK    tomark;
  857.     CMD    cmd;
  858.     int    bang;
  859.     char    *extra;
  860. {
  861. #ifndef DATE
  862.     msg("%s", VERSION);
  863. #else
  864.     msg("%s  (%s)", VERSION, DATE);
  865. #endif
  866. #ifdef COMPILED_BY
  867.     msg("Compiled by %s", COMPILED_BY);
  868. #endif
  869. #ifdef CREDIT
  870.     msg("%s", CREDIT);
  871. #endif
  872. #ifdef COPYING
  873.     msg("%s", COPYING);
  874. #endif
  875. }
  876.  
  877.  
  878. #ifndef NO_EXTENSIONS
  879. /* make a .exrc file which describes the current configuration */
  880. /*ARGSUSED*/
  881. void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
  882.     MARK    frommark;
  883.     MARK    tomark;
  884.     CMD    cmd;
  885.     int    bang;
  886.     char    *extra;
  887. {
  888.     int    fd;
  889.  
  890.     /* create the .exrc file */
  891.     fd = creat(EXRC, 0666);
  892.     if (fd < 0)
  893.     {
  894.         msg("Couldn't create a new \"%s\" file", EXRC);
  895.         return;
  896.     }
  897.  
  898.     /* save stuff */
  899.     savekeys(fd);
  900.     saveopts(fd);
  901. #ifndef NO_DIGRAPH
  902.     savedigs(fd);
  903. #endif
  904.  
  905.     /* close the file */
  906.     close(fd);
  907.     msg("Created a new \"%s\" file", EXRC);
  908. }
  909. #endif
  910.  
  911. #ifndef NO_DIGRAPH
  912. /*ARGSUSED*/
  913. void cmd_digraph(frommark, tomark, cmd, bang, extra)
  914.     MARK    frommark;
  915.     MARK    tomark;
  916.     CMD    cmd;
  917.     int    bang;
  918.     char    *extra;
  919. {
  920.     do_digraph(bang, extra);
  921. }
  922. #endif
  923.