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