home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / ex / ex_voperate.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  14KB  |  835 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #include "ex.h"
  3. #include "ex_tty.h"
  4. #include "ex_vis.h"
  5.  
  6. #define    blank()        isspace(wcursor[0])
  7. #define    forbid(a)    if (a) goto errlab;
  8.  
  9. char    vscandir[2] =    { '/', 0 };
  10.  
  11. /*
  12.  * Decode an operator/operand type command.
  13.  * Eventually we switch to an operator subroutine in ex_vops.c.
  14.  * The work here is setting up a function variable to point
  15.  * to the routine we want, and manipulation of the variables
  16.  * wcursor and wdot, which mark the other end of the affected
  17.  * area.  If wdot is zero, then the current line is the other end,
  18.  * and if wcursor is zero, then the first non-blank location of the
  19.  * other line is implied.
  20.  */
  21. operate(c, cnt)
  22.     register int c, cnt;
  23. {
  24.     register int i;
  25.     int (*moveop)(), (*deleteop)();
  26.     register int (*opf)();
  27.     bool subop = 0;
  28.     char *oglobp, *ocurs;
  29.     register line *addr;
  30.     static char lastFKND, lastFCHR;
  31.     char d;
  32.  
  33.     moveop = vmove, deleteop = vdelete;
  34.     wcursor = cursor;
  35.     wdot = NOLINE;
  36.     notecnt = 0;
  37.     dir = 1;
  38.     switch (c) {
  39.  
  40.     /*
  41.      * d        delete operator.
  42.      */
  43.     case 'd':
  44.         moveop = vdelete;
  45.         deleteop = beep;
  46.         break;
  47.  
  48.     /*
  49.      * s        substitute characters, like c\040, i.e. change space.
  50.      */
  51.     case 's':
  52.         ungetkey(' ');
  53.         subop++;
  54.         /* fall into ... */
  55.  
  56.     /*
  57.      * c        Change operator.
  58.      */
  59.     case 'c':
  60.         if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
  61.             subop++;
  62.         moveop = vchange;
  63.         deleteop = beep;
  64.         break;
  65.  
  66.     /*
  67.      * !        Filter through a UNIX command.
  68.      */
  69.     case '!':
  70.         moveop = vfilter;
  71.         deleteop = beep;
  72.         break;
  73.  
  74.     /*
  75.      * y        Yank operator.  Place specified text so that it
  76.      *        can be put back with p/P.  Also yanks to named buffers.
  77.      */
  78.     case 'y':
  79.         moveop = vyankit;
  80.         deleteop = beep;
  81.         break;
  82.  
  83.     /*
  84.      * =        Reformat operator (for LISP).
  85.      */
  86. #ifdef LISP
  87.     case '=':
  88.         forbid(!value(LISP));
  89.         /* fall into ... */
  90. #endif
  91.  
  92.     /*
  93.      * >        Right shift operator.
  94.      * <        Left shift operator.
  95.      */
  96.     case '<':
  97.     case '>':
  98.         moveop = vshftop;
  99.         deleteop = beep;
  100.         break;
  101.  
  102.     /*
  103.      * r        Replace character under cursor with single following
  104.      *        character.
  105.      */
  106.     case 'r':
  107.         vrep(cnt);
  108.         return;
  109.  
  110.     default:
  111.         goto nocount;
  112.     }
  113.     /*
  114.      * Had an operator, so accept another count.
  115.      * Multiply counts together.
  116.      */
  117.     if (isdigit(peekkey()) && peekkey() != '0') {
  118.         cnt *= vgetcnt();
  119.         Xcnt = cnt;
  120.         forbid (cnt <= 0);
  121.     }
  122.  
  123.     /*
  124.      * Get next character, mapping it and saving as
  125.      * part of command for repeat.
  126.      */
  127.     c = map(getesc());
  128.     if (c == 0)
  129.         return;
  130.     if (!subop)
  131.         *lastcp++ = c;
  132. nocount:
  133.     opf = moveop;
  134.     switch (c) {
  135.  
  136.     /*
  137.      * b        Back up a word.
  138.      * B        Back up a word, liberal definition.
  139.      */
  140.     case 'b':
  141.     case 'B':
  142.         dir = -1;
  143.         /* fall into ... */
  144.  
  145.     /*
  146.      * w        Forward a word.
  147.      * W        Forward a word, liberal definition.
  148.      */
  149.     case 'W':
  150.     case 'w':
  151.         wdkind = c & ' ';
  152.         if (edge()) {
  153.             forbid (opf == vmove);
  154.             wcursor = dir == -1 ? linebuf : strend(linebuf);
  155.         } else
  156.             while (cnt > 0 && !edge())
  157.                 word(opf, cnt), cnt--;
  158.         vmoving = 0;
  159.         break;
  160.  
  161.     /*
  162.      * E to end of following blank/nonblank word
  163.      */
  164.     case 'E':
  165.         wdkind = 0;
  166.         goto ein;
  167.  
  168.     /*
  169.      * e        To end of following word.
  170.      */
  171.     case 'e':
  172.         wdkind = 1;
  173. ein:
  174.         if (edge()) {
  175.             forbid(opf == vmove);
  176.             wcursor = dir == -1 ? linebuf : strend(linebuf);
  177.         } else {
  178.             while (cnt > 1 && !edge()) {
  179.                 word(opf, cnt);
  180.                 cnt--;
  181.             }
  182.             eend(opf, cnt);
  183.         }
  184.         vmoving = 0;
  185.         break;
  186.  
  187.     /*
  188.      * (        Back an s-expression.
  189.      */
  190.     case '(':
  191.         dir = -1;
  192.         /* fall into... */
  193.  
  194.     /*
  195.      * )        Forward an s-expression.
  196.      */
  197.     case ')':
  198.         forbid(lfind(0, cnt, opf, (line *) 0) < 0);
  199.         if (wdot)
  200.             markpr(wdot);
  201.         break;
  202.  
  203.     /*
  204.      * {        Back an s-expression, but don't stop on atoms.
  205.      *        In text mode, a paragraph.  For C, a balanced set
  206.      *        of {}'s.
  207.      */
  208.     case '{':
  209.         dir = -1;
  210.         /* fall into... */
  211.  
  212.     /*
  213.      * }        Forward an s-expression, but don't stop on atoms.
  214.      *        In text mode, back paragraph.  For C, back a balanced
  215.      *        set of {}'s.
  216.      */
  217.     case '}':
  218.         forbid(lfind(1, cnt, opf, (line *) 0) < 0);
  219.         if (wdot)
  220.             markpr(wdot);
  221.         break;
  222.  
  223.     /*
  224.      * %        To matching () or {}.  If not at ( or { scan for
  225.      *        first such after cursor on this line.
  226.      */
  227.     case '%':
  228.         vsave();
  229.         i = lmatchp((line *) 0);
  230.         getDOT();
  231.         forbid(!i);
  232.         if (opf != vmove)
  233.             if (dir > 0)
  234.                 wcursor++;
  235.             else
  236.                 cursor++;
  237.         else
  238.             if (wdot)
  239.                 markpr(wdot);
  240.         break;
  241.  
  242.     /*
  243.      * [        Back to beginning of defun, i.e. an ( in column 1.
  244.      *        For text, back to a section macro.
  245.      *        For C, back to a { in column 1 (~~ beg of function.)
  246.      */
  247.     case '[':
  248.         dir = -1;
  249.         /* fall into ... */
  250.  
  251.     /*
  252.      * ]        Forward to next defun, i.e. a ( in column 1.
  253.      *        For text, forward section.
  254.      *        For C, forward to a } in column 1 (if delete or such)
  255.      *        or if a move to a { in column 1.
  256.      */
  257.     case ']':
  258.         if (!vglobp)
  259.             forbid(getkey() != c);
  260.         if (Xhadcnt)
  261.             vsetsiz(Xcnt);
  262.         vsave();
  263.         i = lbrack(c, opf);
  264.         getDOT();
  265.         forbid(!i);
  266.         if (wdot)
  267.             markpr(wdot);
  268.         if (ospeed > B300)
  269.             hold |= HOLDWIG;
  270.         break;
  271.  
  272.     /*
  273.      * ,        Invert last find with f F t or T, like inverse
  274.      *        of ;.
  275.      */
  276.     case ',':
  277.         forbid (lastFKND == 0);
  278.         c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
  279.         ungetkey(lastFCHR);
  280.         if (vglobp == 0)
  281.             vglobp = "";
  282.         subop++;
  283.         goto nocount;
  284.  
  285.     /*
  286.      * 0        To beginning of real line.
  287.      */
  288.     case '0':
  289.         wcursor = linebuf;
  290.         vmoving = 0;
  291.         break;
  292.  
  293.     /*
  294.      * ;        Repeat last find with f F t or T.
  295.      */
  296.     case ';':
  297.         forbid (lastFKND == 0);
  298.         c = lastFKND;
  299.         ungetkey(lastFCHR);
  300.         subop++;
  301.         goto nocount;
  302.  
  303.     /*
  304.      * F        Find single character before cursor in current line.
  305.      * T        Like F, but stops before character.
  306.      */
  307.     case 'F':    /* inverted find */
  308.     case 'T':
  309.         dir = -1;
  310.         /* fall into ... */
  311.  
  312.     /*
  313.      * f        Find single character following cursor in current line.
  314.      * t        Like f, but stope before character.
  315.      */
  316.     case 'f':    /* find */
  317.     case 't':
  318.         i = getesc();
  319.         if (i == 0)
  320.             return;
  321.         if (!subop)
  322.             *lastcp++ = i;
  323.         if (vglobp == 0)
  324.             lastFKND = c, lastFCHR = i;
  325.         for (; cnt > 0; cnt--)
  326.             forbid (find(i) == 0);
  327.         switch (c) {
  328.  
  329.         case 'T':
  330.             wcursor++;
  331.             break;
  332.  
  333.         case 't':
  334.             wcursor--;
  335.         case 'f':
  336. fixup:
  337.             if (moveop != vmove)
  338.                 wcursor++;
  339.             break;
  340.         }
  341.         vmoving = 0;
  342.         break;
  343.  
  344.     /*
  345.      * |        Find specified print column in current line.
  346.      */
  347.     case '|':
  348.         if (Pline == numbline)
  349.             cnt += 8;
  350.         vmovcol = cnt;
  351.         vmoving = 1;
  352.         wcursor = vfindcol(cnt);
  353.         break;
  354.  
  355.     /*
  356.      * ^        To beginning of non-white space on line.
  357.      */
  358.     case '^':
  359.         wcursor = vskipwh(linebuf);
  360.         vmoving = 0;
  361.         break;
  362.  
  363.     /*
  364.      * $        To end of line.
  365.      */
  366.     case '$':
  367.         if (cnt > 1) {
  368.             if (opf == vmove) {
  369.                 wcursor = 0;
  370.                 vmoving = 1;
  371.                 vmovcol = 20000;
  372.                 cnt--;
  373.             } else
  374.                 wcursor = linebuf;
  375.             wdot = dot + cnt;
  376.             break;
  377.         }
  378.         if (linebuf[0]) {
  379.             wcursor = strend(linebuf) - 1;
  380.             goto fixup;
  381.         }
  382.         wcursor = linebuf;
  383.         vmoving = 0;
  384.         break;
  385.  
  386.     /*
  387.      * h        Back a character.
  388.      * ^H        Back a character.
  389.      */
  390.     case 'h':
  391.     case CTRL(h):
  392.         dir = -1;
  393.         /* fall into ... */
  394.  
  395.     /*
  396.      * space    Forward a character.
  397.      */
  398.     case ' ':
  399.         forbid (margin() || opf == vmove && edge());
  400.         while (cnt > 0 && !margin())
  401.             wcursor += dir, cnt--;
  402.         if (margin() && opf == vmove || wcursor < linebuf)
  403.             wcursor -= dir;
  404.         vmoving = 0;
  405.         break;
  406.  
  407.     /*
  408.      * D        Delete to end of line, short for d$.
  409.      */
  410.     case 'D':
  411.         cnt = INF;
  412.         goto deleteit;
  413.  
  414.     /*
  415.      * X        Delete character before cursor.
  416.      */
  417.     case 'X':
  418.         dir = -1;
  419.         /* fall into ... */
  420. deleteit:
  421.     /*
  422.      * x        Delete character at cursor, leaving cursor where it is.
  423.      */
  424.     case 'x':
  425.         if (margin())
  426.             goto errlab;
  427.         while (cnt > 0 && !margin())
  428.             wcursor += dir, cnt--;
  429.         opf = deleteop;
  430.         vmoving = 0;
  431.         break;
  432.  
  433.     default:
  434.         /*
  435.          * Stuttered operators are equivalent to the operator on
  436.          * a line, thus turn dd into d_.
  437.          */
  438.         if (opf == vmove || c != workcmd[0]) {
  439. errlab:
  440.             beep();
  441.             return;
  442.         }
  443.         /* fall into ... */
  444.  
  445.     /*
  446.      * _        Target for a line or group of lines.
  447.      *        Stuttering is more convenient; this is mostly
  448.      *        for aesthetics.
  449.      */
  450.     case '_':
  451.         wdot = dot + cnt - 1;
  452.         vmoving = 0;
  453.         wcursor = 0;
  454.         break;
  455.  
  456.     /*
  457.      * H        To first, home line on screen.
  458.      *        Count is for count'th line rather than first.
  459.      */
  460.     case 'H':
  461.         wdot = (dot - vcline) + cnt - 1;
  462.         if (opf == vmove)
  463.             markit(wdot);
  464.         vmoving = 0;
  465.         wcursor = 0;
  466.         break;
  467.  
  468.     /*
  469.      * -        Backwards lines, to first non-white character.
  470.      */
  471.     case '-':
  472.         wdot = dot - cnt;
  473.         vmoving = 0;
  474.         wcursor = 0;
  475.         break;
  476.  
  477.     /*
  478.      * ^P        To previous line same column.  Ridiculous on the
  479.      *        console of the VAX since it puts console in LSI mode.
  480.      */
  481.     case CTRL(p):
  482.         wdot = dot - cnt;
  483.         if (vmoving == 0)
  484.             vmoving = 1, vmovcol = column(cursor);
  485.         wcursor = 0;
  486.         break;
  487.  
  488.     /*
  489.      * L        To last line on screen, or count'th line from the
  490.      *        bottom.
  491.      */
  492.     case 'L':
  493.         wdot = dot + vcnt - vcline - cnt;
  494.         if (opf == vmove)
  495.             markit(wdot);
  496.         vmoving = 0;
  497.         wcursor = 0;
  498.         break;
  499.  
  500.     /*
  501.      * M        To the middle of the screen.
  502.      */
  503.     case 'M':
  504.         wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
  505.         if (opf == vmove)
  506.             markit(wdot);
  507.         vmoving = 0;
  508.         wcursor = 0;
  509.         break;
  510.  
  511.     /*
  512.      * +        Forward line, to first non-white.
  513.      *
  514.      * CR        Convenient synonym for +.
  515.      */
  516.     case '+':
  517.     case CR:
  518.         wdot = dot + cnt;
  519.         vmoving = 0;
  520.         wcursor = 0;
  521.         break;
  522.  
  523.     /*
  524.      * ^N        To next line, same column if possible.
  525.      *
  526.      * LF        Linefeed is a convenient synonym for ^N.
  527.      */
  528.     case CTRL(n):
  529.     case NL:
  530.         wdot = dot + cnt;
  531.         if (vmoving == 0)
  532.             vmoving = 1, vmovcol = column(cursor);
  533.         wcursor = 0;
  534.         break;
  535.  
  536.     /*
  537.      * n        Search to next match of current pattern.
  538.      */
  539.     case 'n':
  540.         vglobp = vscandir;
  541.         c = *vglobp++;
  542.         goto nocount;
  543.  
  544.     /*
  545.      * N        Like n but in reverse direction.
  546.      */
  547.     case 'N':
  548.         vglobp = vscandir[0] == '/' ? "?" : "/";
  549.         c = *vglobp++;
  550.         goto nocount;
  551.  
  552.     /*
  553.      * '        Return to line specified by following mark,
  554.      *        first white position on line.
  555.      *
  556.      * `        Return to marked line at remembered column.
  557.      */
  558.     case '\'':
  559.     case '`':
  560.         d = c;
  561.         c = getesc();
  562.         if (c == 0)
  563.             return;
  564.         c = markreg(c);
  565.         forbid (c == 0);
  566.         wdot = getmark(c);
  567.         forbid (wdot == NOLINE);
  568.         if (Xhadcnt)
  569.             vsetsiz(Xcnt);
  570.         if (opf == vmove)
  571.             markit(wdot);
  572.         vmoving = 0;
  573.         wcursor = d == '`' ? ncols[c - 'a'] : 0;
  574.         if (wcursor) {
  575.             vsave();
  576.             getline(*wdot);
  577.             if (wcursor > strend(linebuf))
  578.                 wcursor = 0;
  579.             getDOT();
  580.         }
  581.         if (ospeed > B300)
  582.             hold |= HOLDWIG;
  583.         break;
  584.  
  585.     /*
  586.      * G        Goto count'th line, or last line if no count
  587.      *        given.
  588.      */
  589.     case 'G':
  590.         if (!Xhadcnt)
  591.             cnt = lineDOL();
  592.         wdot = zero + cnt;
  593.         forbid (wdot < one || wdot > dol);
  594.         if (opf == vmove)
  595.             markit(wdot);
  596.         vmoving = 0;
  597.         wcursor = 0;
  598.         break;
  599.  
  600.     /*
  601.      * /        Scan forward for following re.
  602.      * ?        Scan backward for following re.
  603.      */
  604.     case '/':
  605.     case '?':
  606.         if (Xhadcnt)
  607.             vsetsiz(Xcnt);
  608.         vsave();
  609.         ocurs = cursor;
  610.         wcursor = 0;
  611.         if (readecho(c))
  612.             return;
  613.         if (!vglobp)
  614.             vscandir[0] = genbuf[0];
  615.         oglobp = globp; CP(vutmp, genbuf); globp = vutmp;
  616.         d = peekc; ungetchar(0); fixech();
  617.         CATCH
  618. #ifdef V6
  619.             /*
  620.              * Lose typeahead (ick).
  621.              */
  622.             vcook();
  623. #endif
  624.             addr = address();
  625. #ifdef V6
  626.             vraw();
  627. #endif
  628.         ONERR
  629. #ifdef V6
  630.             vraw();
  631. #endif
  632.             globp = oglobp;
  633.             ungetchar(d);
  634.             splitw = 0;
  635.             vclean();
  636.             vjumpto(dot, ocurs, 0);
  637.             return;
  638.         ENDCATCH
  639.         if (globp == 0)
  640.             globp = "";
  641.         else if (peekc)
  642.             --globp;
  643.         ungetchar(d);
  644.         c = 0;
  645.         if (*globp == 'z')
  646.             globp++, c = '\n';
  647.         if (any(*globp, "^+-."))
  648.             c = *globp++;
  649.         i = 0;
  650.         while (isdigit(*globp))
  651.             i = i * 10 + *globp++ - '0';
  652.         if (*globp)
  653.             c = *globp++;
  654.         globp = oglobp;
  655.         splitw = 0;
  656.         vmoving = 0;
  657.         if (i != 0)
  658.             vsetsiz(i);
  659.         if (opf == vmove) {
  660.             if (state == ONEOPEN || state == HARDOPEN)
  661.                 outline = destline = WBOT;
  662.             markit(addr);
  663.             if (loc1 > linebuf && *loc1 == 0)
  664.                 loc1--;
  665.             if (c)
  666.                 vjumpto(addr, loc1, c);
  667.             else {
  668.                 vmoving = 0;
  669.                 if (loc1) {
  670.                     vmoving++;
  671.                     vmovcol = column(loc1);
  672.                 }
  673.                 getDOT();
  674.                 if (state == CRTOPEN && addr != dot)
  675.                     vup1();
  676.                 vupdown(addr - dot, NOSTR);
  677.             }
  678.             return;
  679.         }
  680.         lastcp[-1] = 'n';
  681.         getDOT();
  682.         wdot = addr;
  683.         break;
  684.     }
  685.     /*
  686.      * Apply.
  687.      */
  688.     if (vreg && wdot == 0)
  689.         wdot = dot;
  690.     (*opf)(c);
  691.     wdot = NOLINE;
  692. }
  693.  
  694. /*
  695.  * Find single character c, in direction dir from cursor.
  696.  */
  697. find(c)
  698.     char c;
  699. {
  700.  
  701.     for(;;) {
  702.         if (edge())
  703.             return (0);
  704.         wcursor += dir;
  705.         if (*wcursor == c)
  706.             return (1);
  707.     }
  708. }
  709.  
  710. /*
  711.  * Do a word motion with operator op, and cnt more words
  712.  * to go after this.
  713.  */
  714. word(op, cnt)
  715.     register int (*op)();
  716.     int cnt;
  717. {
  718.     register int which;
  719.     register char *iwc;
  720.  
  721.     if (dir == 1) {
  722.         iwc = wcursor;
  723.         which = wordch(wcursor);
  724.         while (!margin() && wordof(which, wcursor))
  725.             wcursor++;
  726.         /* Unless last segment of a change skip blanks */
  727.         if (op != vchange || cnt > 1)
  728.             while (!margin() && blank())
  729.                 wcursor++;
  730.         else
  731.             if (wcursor == iwc && *iwc)
  732.                 wcursor++;
  733.         if (op == vmove && margin())
  734.             wcursor--;
  735.     } else {
  736.         wcursor--;
  737.         while (!margin() && blank())
  738.             wcursor--;
  739.         if (!margin()) {
  740.             which = wordch(wcursor);
  741.             while (!margin() && wordof(which, wcursor))
  742.                 wcursor--;
  743.         }
  744.         if (margin() || !wordof(which, wcursor))
  745.             wcursor++;
  746.     }
  747. }
  748.  
  749. /*
  750.  * To end of word, with operator op and cnt more motions
  751.  * remaining after this.
  752.  */
  753. eend(op, cnt)
  754.     register int (*op)();
  755.     int cnt;
  756. {
  757.     register int which;
  758.  
  759. /*
  760.     if (dir == 1) {
  761. */
  762.         if (!margin())
  763.             wcursor++;
  764.         while (!margin() && blank())
  765.             wcursor++;
  766.         which = wordch(wcursor);
  767.         while (!margin() && wordof(which, wcursor))
  768.             wcursor++;
  769.         if (cnt == 1 && op != vchange && op != vdelete)
  770.             wcursor--;
  771. /* backwards is useless... used to be on E
  772.     } else {
  773.         if (!blank()) {
  774.             which = wordch(wcursor);
  775.             while (!margin() && wordof(which, wcursor))
  776.                 wcursor--;
  777.         }
  778.         while (!margin() && blank())
  779.             wcursor--;
  780.         if (margin())
  781.             wcursor++;
  782.     }
  783. */
  784. }
  785.         
  786. /*
  787.  * Wordof tells whether the character at *wc is in a word of
  788.  * kind which (blank/nonblank words are 0, conservative words 1).
  789.  */
  790. wordof(which, wc)
  791.     char which;
  792.     register char *wc;
  793. {
  794.  
  795.     if (isspace(*wc))
  796.         return (0);
  797.     return (!wdkind || wordch(wc) == which);
  798. }
  799.  
  800. /*
  801.  * Wordch tells whether character at *wc is a word character
  802.  * i.e. an alfa, digit, or underscore.
  803.  */
  804. wordch(wc)
  805.     char *wc;
  806. {
  807.     register int c;
  808.  
  809.     c = wc[0];
  810.     return (isalpha(c) || isdigit(c) || c == '_');
  811. }
  812.  
  813. /*
  814.  * Edge tells when we hit the last character in the current line.
  815.  */
  816. edge()
  817. {
  818.  
  819.     if (linebuf[0] == 0)
  820.         return (1);
  821.     if (dir == 1)
  822.         return (wcursor[1] == 0);
  823.     else
  824.         return (wcursor == linebuf);
  825. }
  826.  
  827. /*
  828.  * Margin tells us when we have fallen off the end of the line.
  829.  */
  830. margin()
  831. {
  832.  
  833.     return (wcursor < linebuf || wcursor[0] == 0);
  834. }
  835.