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

  1. /* cmd2.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 commands - mostly ones that change text */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #include "regexp.h"
  16.  
  17.  
  18. /*ARGSUSED*/
  19. void cmd_substitute(frommark, tomark, cmd, bang, extra)
  20.     MARK    frommark;
  21.     MARK    tomark;
  22.     CMD    cmd;
  23.     int    bang;
  24.     char    *extra;    /* rest of the command line */
  25. {
  26.     char    *line;    /* a line from the file */
  27.     regexp    *re;    /* the compiled search expression */
  28.     char    *subst;    /* the substitution string */
  29.     char    *opt;    /* substitution options */
  30.     int    optp;    /* boolean option: print when done? */
  31.     int    optg;    /* boolean option: substitute globally in line? */
  32.     long    l;    /* a line number */
  33.     char    *s, *d;    /* used during subtitutions */
  34.     long    chline;    /* # of lines changed */
  35.     long    chsub;    /* # of substitutions made */
  36.  
  37.  
  38.     /* make sure we got a search pattern */
  39.     if (*extra != '/' && *extra != '?')
  40.     {
  41.         msg("Usage: s/regular expression/new text/");
  42.         return;
  43.     }
  44.  
  45.     /* parse & compile the search pattern */
  46.     subst = parseptrn(extra);
  47.     re = regcomp(extra + 1);
  48.     if (!re)
  49.     {
  50.         return;
  51.     }
  52.  
  53.     /* parse the substitution string & find the option string */
  54.     for (opt = subst; *opt && (*opt != *extra || opt[-1] == '\\'); opt++)
  55.     {
  56.     }
  57.     if (*opt)
  58.     {
  59.         *opt++ = '\0';
  60.     }
  61.  
  62.     /* analyse the option string */
  63.     optp = optg = 0;
  64.     while (*opt)
  65.     {
  66.         switch (*opt++)
  67.         {
  68.           case 'p':    optp = 1;    break;
  69.           case 'g':    optg = 1;    break;
  70.           case ' ':
  71.           case '\t':            break;
  72.           default:
  73.             msg("Subst options are p and g -- not %c", opt[-1]);
  74.             return;
  75.         }
  76.     }
  77.  
  78.     ChangeText
  79.     {
  80.         /* reset the change counters */
  81.         chline = chsub = 0L;
  82.  
  83.         /* for each selected line */
  84.         for (l = markline(frommark); l <= markline(tomark); l++)
  85.         {
  86.             /* fetch the line */
  87.             line = fetchline(l);
  88.  
  89.             /* if it contains the search pattern... */
  90.             if (regexec(re, line, TRUE))
  91.             {
  92.                 /* increment the line change counter */
  93.                 chline++;
  94.  
  95.                 /* initialize the pointers */
  96.                 s = line;
  97.                 d = tmpblk.c;
  98.  
  99.                 /* do once or globally ... */
  100.                 do
  101.                 {
  102.                     /* increment the substitution change counter */
  103.                     chsub++;
  104.  
  105.                     /* this may be the first line to redraw */
  106.                     redrawrange(l, l + 1L, l + 1L);
  107.  
  108.                     /* copy stuff from before the match */
  109.                     while (s < re->startp[0])
  110.                     {
  111.                         *d++ = *s++;
  112.                     }
  113.     
  114.                     /* subtitute for the matched part */
  115.                     regsub(re, subst, d);
  116.                     s = re->endp[0];
  117.                     d += strlen(d);
  118.  
  119.                 } while (optg && regexec(re, s, FALSE));
  120.  
  121.                 /* copy stuff from after the match */
  122.                 while (*d++ = *s++)    /* yes, ASSIGNMENT! */
  123.                 {
  124.                 }
  125.  
  126.                 /* replace the old version of the line with the new */
  127.                 changeline(l, tmpblk.c);
  128.  
  129.                 /* if supposed to print it, do so */
  130.                 if (optp)
  131.                 {
  132.                     addstr(tmpblk.c);
  133.                     addch('\n');
  134.                     exrefresh();
  135.                 }
  136.             }
  137.         }
  138.     }
  139.  
  140.     /* report what happened */
  141.     if (chsub == 0)
  142.     {
  143.         msg("Substitution failed");
  144.     }
  145.  
  146.     /* tweak for redrawing */
  147.     if (chline > 1 || redrawafter && redrawafter != markline(cursor))
  148.     {
  149.         mustredraw = TRUE;
  150.     }
  151.  
  152.     /* free the regexp */
  153.     free(re);
  154.  
  155.     /* Reporting */
  156.     if (chline >= *o_report)
  157.     {
  158.         msg("%ld substitutions on %ld lines", chsub, chline);
  159.     }
  160.     rptlines = 0;
  161. }
  162.  
  163.  
  164.  
  165.  
  166. /*ARGSUSED*/
  167. void cmd_delete(frommark, tomark, cmd, bang, extra)
  168.     MARK    frommark;
  169.     MARK    tomark;
  170.     CMD    cmd;
  171.     int    bang;
  172.     char    *extra;
  173. {
  174.     MARK    curs2;    /* al altered form of the cursor */
  175.  
  176.     /* choose your cut buffer */
  177.     if (*extra == '"')
  178.     {
  179.         extra++;
  180.     }
  181.     if (*extra)
  182.     {
  183.         cutname(*extra);
  184.     }
  185.  
  186.     /* make sure we're talking about whole lines here */
  187.     frommark = frommark & ~(BLKSIZE - 1);
  188.     tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
  189.  
  190.     /* yank the lines */
  191.     cut(frommark, tomark);
  192.  
  193.     /* if CMD_DELETE then delete the lines */
  194.     if (cmd != CMD_YANK)
  195.     {
  196.         curs2 = cursor;
  197.         ChangeText
  198.         {
  199.             /* delete the lines */
  200.             delete(frommark, tomark);
  201.         }
  202.         if (curs2 > tomark)
  203.         {
  204.             cursor = curs2 - tomark + frommark;
  205.         }
  206.         else if (curs2 > frommark)
  207.         {
  208.             cursor = frommark;
  209.         }
  210.     }
  211. }
  212.  
  213.  
  214. /*ARGSUSED*/
  215. void cmd_append(frommark, tomark, cmd, bang, extra)
  216.     MARK    frommark;
  217.     MARK    tomark;
  218.     CMD    cmd;
  219.     int    bang;
  220.     char    *extra;
  221. {
  222.     long    l;    /* line counter */
  223.  
  224.     ChangeText
  225.     {
  226.         /* if we're doing a change, delete the old version */
  227.         if (cmd == CMD_CHANGE)
  228.         {
  229.             /* delete 'em */
  230.             cmd_delete(frommark, tomark, cmd, bang, extra);
  231.         }
  232.  
  233.         /* new lines start at the frommark line, or after it */
  234.         l = markline(frommark);
  235.         if (cmd == CMD_APPEND)
  236.         {
  237.              l++;
  238.         }
  239.  
  240.         /* get lines until no more lines, or "." line, and insert them */
  241.         while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
  242.         {
  243.             addch('\n');
  244.             if (!strcmp(tmpblk.c, "."))
  245.             {
  246.                 break;
  247.             }
  248.  
  249.             addline(l, tmpblk.c);
  250.             l++;
  251.         }
  252.     }
  253.  
  254.     /* on the odd chance that we're calling this from vi mode ... */
  255.     redraw(MARK_UNSET, FALSE);
  256. }
  257.  
  258.  
  259. /*ARGSUSED*/
  260. void cmd_put(frommark, tomark, cmd, bang, extra)
  261.     MARK    frommark;
  262.     MARK    tomark;
  263.     CMD    cmd;
  264.     int    bang;
  265.     char    *extra;
  266. {
  267.     /* choose your cut buffer */
  268.     if (*extra == '"')
  269.     {
  270.         extra++;
  271.     }
  272.     if (*extra)
  273.     {
  274.         cutname(*extra);
  275.     }
  276.  
  277.     /* paste it */
  278.     ChangeText
  279.     {
  280.         cursor = paste(frommark, !bang, FALSE);
  281.     }
  282. }
  283.  
  284.  
  285. /*ARGSUSED*/
  286. void cmd_join(frommark, tomark, cmd, bang, extra)
  287.     MARK    frommark;
  288.     MARK    tomark;
  289.     CMD    cmd;
  290.     int    bang;
  291.     char    *extra;
  292. {
  293.     long    l;
  294.     char    *scan;
  295.     int    len;    /* length of the new line */
  296.  
  297.     /* if only one line is specified, assume the following one joins too */
  298.     if (markline(frommark) == nlines)
  299.     {
  300.         msg("Nothing to join with this line");
  301.         return;
  302.     }
  303.     if (markline(frommark) == markline(tomark))
  304.     {
  305.         tomark = m_down(tomark, 1L);
  306.     }
  307.  
  308.     /* get the first line */
  309.     l = markline(frommark);
  310.     strcpy(tmpblk.c, fetchline(l++));
  311.     len = strlen(tmpblk.c);
  312.  
  313.     /* build the longer line */
  314.     while (l <= markline(tomark))
  315.     {
  316.         /* get the next line */
  317.         scan = fetchline(l++);
  318.  
  319.         /* remove any leading whitespace */
  320.         while (*scan == '\t' || *scan == ' ')
  321.         {
  322.             scan++;
  323.         }
  324.  
  325.         /* see if the line will fit */
  326.         if (strlen(scan) + len + 1 > BLKSIZE)
  327.         {
  328.             msg("Can't join -- the resulting line would be too long");
  329.             return;
  330.         }
  331.  
  332.         /* catenate it, with a space in between */
  333.         tmpblk.c[len++] = ' ';
  334.         strcpy(tmpblk.c + len, scan);
  335.         len += strlen(scan);
  336.     }
  337.  
  338.     /* make the change */
  339.     ChangeText
  340.     {
  341.         frommark &= ~(BLKSIZE - 1);
  342.         tomark &= ~(BLKSIZE - 1);
  343.         tomark += BLKSIZE;
  344.         delete(frommark, tomark);
  345.         addline(markline(frommark), tmpblk.c);
  346.     }
  347. }
  348.  
  349.  
  350.  
  351. /*ARGSUSED*/
  352. void cmd_shift(frommark, tomark, cmd, bang, extra)
  353.     MARK    frommark;
  354.     MARK    tomark;
  355.     CMD    cmd;
  356.     int    bang;
  357.     char    *extra;
  358. {
  359.     long    l;    /* line number counter */
  360.     int    oldidx;    /* number of chars previously used for indent */
  361.     int    newidx;    /* number of chars in the new indent string */
  362.     int    oldcol;    /* previous indent amount */
  363.     int    newcol;    /* new indent amount */
  364.     char    *text;    /* pointer to the old line's text */
  365.  
  366.     /* figure out how much of the screen we must redraw (for vi mode) */
  367.     if (markline(frommark) != markline(tomark))
  368.     {
  369.         mustredraw = TRUE;
  370.         redrawrange(markline(frommark), markline(tomark) + 1L, markline(tomark) + 1L);
  371.     }
  372.  
  373.     ChangeText
  374.     {
  375.         /* for each line to shift... */
  376.         for (l = markline(frommark); l <= markline(tomark); l++)
  377.         {
  378.             /* get the line - ignore empty lines unless ! mode */
  379.             text = fetchline(l);
  380.             if (!*text && !bang)
  381.                 continue;
  382.  
  383.             /* calc oldidx and oldcol */
  384.             for (oldidx = 0, oldcol = 0;
  385.                  text[oldidx] == ' ' || text[oldidx] == '\t';
  386.                  oldidx++)
  387.             {
  388.                 if (text[oldidx] == ' ')
  389.                 {
  390.                     oldcol += 1;
  391.                 }
  392.                 else
  393.                 {
  394.                     oldcol += *o_tabstop - (oldcol % *o_tabstop);
  395.                 }
  396.             }
  397.     
  398.             /* calc newcol */
  399.             if (cmd == CMD_SHIFTR)
  400.             {
  401.                 newcol = oldcol + (*o_shiftwidth & 0xff);
  402.             }
  403.             else
  404.             {
  405.                 newcol = oldcol - (*o_shiftwidth & 0xff);
  406.                 if (newcol < 0)
  407.                     newcol = 0;
  408.             }
  409.  
  410.             /* if no change, then skip to next line */
  411.             if (oldcol == newcol)
  412.                 continue;
  413.  
  414.             /* build a new indent string */
  415.             newidx = 0;
  416.             while (newcol >= *o_tabstop)
  417.             {
  418.                 tmpblk.c[newidx++] = '\t';
  419.                 newcol -= *o_tabstop;
  420.             }
  421.             while (newcol > 0)
  422.             {
  423.                 tmpblk.c[newidx++] = ' ';
  424.                 newcol--;
  425.             }
  426.             tmpblk.c[newidx] = '\0';
  427.             
  428.             /* change the old indent string into the new */
  429.             change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
  430.         }
  431.     }
  432.  
  433.     /* Reporting... */
  434.     rptlines = markline(tomark) - markline(frommark) + 1L;
  435.     if (cmd == CMD_SHIFTR)
  436.     {
  437.         rptlabel = ">ed";
  438.     }
  439.     else
  440.     {
  441.         rptlabel = "<ed";
  442.     }
  443. }
  444.  
  445.  
  446. /*ARGSUSED*/
  447. void cmd_read(frommark, tomark, cmd, bang, extra)
  448.     MARK    frommark;
  449.     MARK    tomark;
  450.     CMD    cmd;
  451.     int    bang;
  452.     char    *extra;
  453. {
  454.     long    l;    /* line number counter - where new lines go */
  455.     int    fd, rc;    /* used while reading from the file */
  456.     char    *scan;    /* used for finding newlines */
  457.     char    *line;    /* points to the start of a line */
  458.     int    prevrc;    /* used to detect abnormal EOF */
  459.  
  460.     /* special case: if ":r !cmd" then let the filter() function do it */
  461.     if (bang || extra[0] == '!')
  462.     {
  463.         if (extra[0] == '!')
  464.         {
  465.             extra++;
  466.         }
  467.         frommark = (frommark & ~(BLKSIZE - 1)) + BLKSIZE;
  468.         filter(frommark, MARK_UNSET, extra);
  469.         return;
  470.     }
  471.  
  472.     /* first line goes after the selected line */
  473.     l = markline(frommark) + 1;
  474.  
  475.     /* open the file */
  476.     fd = open(extra, O_RDONLY);
  477.     if (fd < 0)
  478.     {
  479.         msg("Can't open \"%s\"", extra);
  480.         return;
  481.     }
  482.  
  483.     /* get blocks from the file, and add each line in the block */
  484.     ChangeText
  485.     {
  486.         /* NOTE!  lint worries needlessly about the order of evaluation
  487.          * of the 'rc' expressions in the test clause of this for(;;){}
  488.          */
  489.         for (prevrc = rc = 0;
  490.              (rc = rc + tread(fd, tmpblk.c + rc, BLKSIZE - rc)) > 0;
  491.              prevrc = rc)
  492.         {
  493.             /* if we couldn't read anything, we damn well better have \n */
  494.             if (prevrc == rc)
  495.             {
  496.                 if (rc == BLKSIZE)
  497.                 {
  498.                     rc--;
  499.                 }
  500.                 if (tmpblk.c[rc - 1] != '\n' || rc <= 0)
  501.                 {
  502.                     tmpblk.c[rc++] = '\n';
  503.                 }
  504.             }
  505.  
  506.             /* for each complete line in this block, add it */
  507.             for (line = scan = tmpblk.c; rc > 0; rc--, scan++)
  508.             {
  509.                 if (*scan == '\n')
  510.                 {
  511.                     *scan = '\0';
  512.                     addline(l, line);
  513.                     l++;
  514.                     line = scan + 1;
  515.                 }
  516.                 else if (!*scan)
  517.                 {
  518.                     /* protect against NUL chars in file */
  519.                     *scan = 0x80;
  520.                 }
  521.             }
  522.  
  523.             /* any extra chars are shifted to the start of the buffer */
  524.             rc = scan - line;
  525.             for (scan = tmpblk.c; scan < tmpblk.c + rc; )
  526.             {
  527.                 *scan++ = *line++;
  528.             }
  529.         }
  530.     }
  531.  
  532.     /* close the file */
  533.     close(fd);
  534.  
  535.     /* Reporting... */
  536.     rptlines = l - markline(frommark) - 1L;
  537.     rptlabel = "read";
  538. }
  539.  
  540.  
  541. /*ARGSUSED*/
  542. void cmd_list(frommark, tomark, cmd, bang, extra)
  543.     MARK    frommark;
  544.     MARK    tomark;
  545.     CMD    cmd;
  546.     int    bang;
  547.     char    *extra;
  548. {
  549.     long        l;    /* line number counter */
  550.     register char    *scan;    /* used for moving through the line */
  551.  
  552.     for (l = markline(frommark); l <= markline(tomark); l++)
  553.     {
  554.         /* list the line */
  555.         scan = fetchline(l);
  556.  
  557.         while (*scan)
  558.         {
  559.             /* if the char is non-printable, write it as \000 */
  560.             if (*scan < ' ' || *scan > '~')
  561.             {
  562.                 /* build the \000 form & write it */
  563.                 addch('\\');
  564.                 addch('0' + ((*scan >> 6) & 3));
  565.                 addch('0' + ((*scan >> 3) & 7));
  566.                 addch('0' + (*scan & 7));
  567.             }
  568.             else
  569.             {
  570.                 addch(*scan);
  571.             }
  572.             scan++;
  573.         }
  574.  
  575.         /* write a $ and a \n */
  576.         addstr("$\n");
  577.         exrefresh();
  578.     }
  579. }
  580.  
  581.  
  582. /*ARGSUSED*/
  583. void cmd_undo(frommark, tomark, cmd, bang, extra)
  584.     MARK    frommark;
  585.     MARK    tomark;
  586.     CMD    cmd;
  587.     int    bang;
  588.     char    *extra;
  589. {
  590.     undo();
  591. }
  592.  
  593.  
  594. /* print the selected lines */
  595. /*ARGSUSED*/
  596. void cmd_print(frommark, tomark, cmd, bang, extra)
  597.     MARK    frommark;
  598.     MARK    tomark;
  599.     CMD    cmd;
  600.     int    bang;
  601.     char    *extra;
  602. {
  603.     register char    *scan;
  604.     register long    l;
  605.     register int    col;
  606.  
  607.     for (l = markline(frommark); l <= markline(tomark); l++)
  608.     {
  609.         /* get the next line & display it */
  610.         for (col = 0, scan = fetchline(l); *scan; scan++)
  611.         {
  612.             /* expand tabs to the proper width */
  613.             if (*scan == '\t')
  614.             {
  615.                 do
  616.                 {
  617.                     qaddch(' ');
  618.                     col++;
  619.                 } while (col % *o_tabstop != 0);
  620.             }
  621.             else
  622.             {
  623.                 qaddch(*scan);
  624.             }
  625.  
  626.             /* wrap at the edge of the screen */
  627.             if (!has_AM && col >= COLS)
  628.             {
  629.                 addch('\n');
  630.                 col = 0;
  631.             }
  632.         }
  633.         addch('\n');
  634.         exrefresh();
  635.     }
  636. }
  637.  
  638.  
  639. /* move or copy selected lines */
  640. /*ARGSUSED*/
  641. void cmd_move(frommark, tomark, cmd, bang, extra)
  642.     MARK    frommark;
  643.     MARK    tomark;
  644.     CMD    cmd;
  645.     int    bang;
  646.     char    *extra;
  647. {
  648.     MARK    destmark;
  649.  
  650.     /* parse the destination linespec.  No defaults.  Line 0 is okay */
  651.     destmark = cursor;
  652.     if (!strcmp(extra, "0"))
  653.     {
  654.         destmark = 0L;
  655.     }
  656.     else if (linespec(extra, &destmark) == extra || !destmark)
  657.     {
  658.         msg("invalid destination address");
  659.         return;
  660.     }
  661.  
  662.     /* flesh the marks out to encompass whole lines */
  663.     frommark &= ~(BLKSIZE - 1);
  664.     tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
  665.     destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
  666.  
  667.     /* make sure the destination is valid */
  668.     if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
  669.     {
  670.         msg("invalid destination address");
  671.     }
  672.  
  673.     /* Do it */
  674.     ChangeText
  675.     {
  676.         /* save the text to a cut buffer */
  677.         cutname('\0');
  678.         cut(frommark, tomark);
  679.  
  680.         /* if we're not copying, delete the old text & adjust destmark */
  681.         if (cmd != CMD_COPY)
  682.         {
  683.             delete(frommark, tomark);
  684.             if (destmark >= frommark)
  685.             {
  686.                 destmark -= (tomark - frommark);
  687.             }
  688.         }
  689.  
  690.         /* add the new text */
  691.         paste(destmark, FALSE, FALSE);
  692.     }
  693.  
  694.     /* move the cursor to the last line of the moved text */
  695.     cursor = destmark + (tomark - frommark) - BLKSIZE;
  696.     if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE)
  697.     {
  698.         cursor = MARK_LAST;
  699.     }
  700.  
  701.     /* Reporting... */
  702.     rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
  703. }
  704.  
  705.  
  706.  
  707. /* execute EX commands from a file */
  708. /*ARGSUSED*/
  709. void cmd_source(frommark, tomark, cmd, bang, extra)
  710.     MARK    frommark;
  711.     MARK    tomark;
  712.     CMD    cmd;
  713.     int    bang;
  714.     char    *extra;
  715. {
  716.     /* must have a filename */
  717.     if (!*extra)
  718.     {
  719.         msg("\"source\" requires a filename");
  720.         return;
  721.     }
  722.  
  723.     doexrc(extra);
  724. }
  725.