home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / pvic_10a.lzh / SRCE / normal.c < prev    next >
Text File  |  1998-04-23  |  19KB  |  983 lines

  1. /* 
  2.  * Contains the main routine for processing characters in command mode.
  3.  * Communicates closely with the code in ops.c to handle the operators.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "pvic.h"
  8. #include "locdefs.h"
  9.  
  10. /*
  11.  * Generally speaking, every command in normal() should either clear any
  12.  * pending operator (with CLEAROP), or set the motion type variable.
  13.  */
  14.  
  15. #define CLEAROP (operator=NOP)  /* clear any pending operator */
  16.  
  17. int     operator = NOP;         /* current pending operator */
  18. int     mtype;                          /* type of the current cursor motion */
  19. int     mincl;                  /* true if char motion is inclusive */
  20. LPTR    startop;                /* cursor pos. at start of operator */
  21.  
  22. /*
  23.  * Operators can have counts either before the operator, or between the
  24.  * operator and the following cursor motion as in:
  25.  *
  26.  *      d3w or 3dw
  27.  *
  28.  * If a count is given before the operator, it is saved in opnum. If
  29.  * normal() is called with a pending operator, the count in opnum (if
  30.  * present) overrides any count that came later.
  31.  */
  32. static  int     opnum = 0;
  33.  
  34. #define DEFAULT1(x)     (((x) == 0) ? 1 : (x))
  35.  
  36. /*
  37.  * normal(c)
  38.  *
  39.  * Execute a command in command mode.
  40.  *
  41.  * This is basically a big switch with the cases arranged in rough categories
  42.  * in the following order:
  43.  *
  44.  *      1. File positioning commands
  45.  *      2. Control commands (e.g. ^G, Z, screen redraw, etc)
  46.  *      3. Character motions
  47.  *      4. Search commands (of various kinds)
  48.  *      5. Edit commands (e.g. J, x, X)
  49.  *      6. Insert commands (e.g. i, o, O, A)
  50.  *      7. Operators
  51.  *      8. Abbreviations (e.g. D, C)
  52.  *      9. Marks
  53.  */
  54. void normal(c)
  55. int c;
  56. {
  57.     register int    n;
  58.     register char   *s;     /* temporary variable for misc. strings */
  59.     int     flag = (0);
  60.     int     type = 0;       /* used in some operations to modify type */
  61.     int     dir = SEARCH_FORWARD;   /* search direction */
  62.     int     nchar = '\0';
  63.     int     finish_op;
  64.  
  65.     /*
  66.      * If there is an operator pending, then the command we take
  67.      * this time will terminate it. Finish_op tells us to finish
  68.      * the operation before returning this time (unless the operation
  69.      * was cancelled.
  70.      */
  71.     finish_op = (operator != NOP);
  72.  
  73.     /*
  74.      * If we're in the middle of an operator AND we had a count before
  75.      * the operator, then that count overrides the current value of
  76.      * prenum. What this means effectively, is that commands like
  77.      * "3dw" get turned into "d3w" which makes things fall into place
  78.      * pretty neatly.
  79.      */
  80.     if (finish_op) {
  81.         if (opnum != 0)
  82.             prenum = opnum;
  83.     } else
  84.         opnum = 0;
  85.  
  86.     u_l_check();     /* clear the "line undo" buffer if we've moved */
  87.  
  88.     switch (c & 0xff) {
  89.  
  90.     /*
  91.      * Screen positioning commands
  92.      */
  93.     case CTRL_D:
  94.         CLEAROP;
  95.         if (prenum)
  96.             PARAMETER_VALUE(PARAMETER_SCROLL) = (prenum > current_lines-1) ? current_lines-1 : prenum;
  97.         scroll_up(PARAMETER_VALUE(PARAMETER_SCROLL));
  98.         one_down(PARAMETER_VALUE(PARAMETER_SCROLL));
  99.         update_screen(0);
  100.         break;
  101.  
  102.     case CTRL_U:
  103.         CLEAROP;
  104.         if (prenum)
  105.             PARAMETER_VALUE(PARAMETER_SCROLL) = (prenum > current_lines-1) ? current_lines-1 : prenum;
  106.         scroll_down(PARAMETER_VALUE(PARAMETER_SCROLL));
  107.         one_up(PARAMETER_VALUE(PARAMETER_SCROLL));
  108.         update_screen(0);
  109.         break;
  110.  
  111.     /*
  112.      * This is kind of a hack. If we're moving by one page, the calls
  113.      * to put_string_into_input_buffer() do exactly the right thing in terms of leaving
  114.      * some context, and so on. If a count was given, we don't have
  115.      * to worry about these issues.
  116.      */
  117.     case CTRL_F:
  118.         CLEAROP;
  119.         n = DEFAULT1(prenum);
  120.         if (n > 1) {
  121.             if ( ! one_down(current_lines * n) )
  122.                 beep();
  123.             update_cursor(0);
  124.         } else {
  125.             /* clear_screen(); */
  126.             put_string_into_input_buffer("Lz\nM");
  127.         }
  128.         break;
  129.  
  130.     case CTRL_B:
  131.         CLEAROP;
  132.         n = DEFAULT1(prenum);
  133.         if (n > 1) {
  134.             if ( ! one_up(current_lines * n) )
  135.                 beep();
  136.             update_cursor(0);
  137.         } else {
  138.             /* clear_screen(); */
  139.             put_string_into_input_buffer("Hz-M");
  140.         }
  141.         break;
  142.  
  143.     case CTRL_E:
  144.         CLEAROP;
  145.         scroll_up(DEFAULT1(prenum));
  146.         update_screen(0);
  147.         break;
  148.  
  149.     case CTRL_Y:
  150.         CLEAROP;
  151.         scroll_down(DEFAULT1(prenum));
  152.         update_screen(0);
  153.         break;
  154.  
  155.     case 'z':
  156.         CLEAROP;
  157.         switch (get_char_from_input_buffer()) {
  158.         case CTRL_J:                /* put cursor_char at top of screen */
  159.         case CTRL_M:
  160.             *top_char = *cursor_char;
  161.             top_char->index = 0;
  162.             update_screen(0);
  163.             break;
  164.  
  165.         case '.':               /* put cursor_char in middle of screen */
  166.             n = current_lines/2;
  167.             goto dozcmd;
  168.  
  169.         case '-':               /* put cursor_char at bottom of screen */
  170.             n = current_lines-1;
  171.             /* fall through */
  172.  
  173.         dozcmd:
  174.             {
  175.                 register LPTR   *lp = cursor_char;
  176.                 register int    l = 0;
  177.  
  178.                 while ((l < n) && (lp != NULL)) {
  179.                     l += plines(lp);
  180.                     *top_char = *lp;
  181.                     lp = previous_line(lp);
  182.                 }
  183.             }
  184.             top_char->index = 0;
  185.             update_screen(0);
  186.             break;
  187.  
  188.         default:
  189.             beep();
  190.         }
  191.         break;
  192.  
  193.     /*
  194.      * Control commands
  195.      */
  196.     case ':':
  197.         CLEAROP;
  198.         if ((s = getcmdln(c)) != NULL)
  199.             do_command_line(s);
  200.         break;
  201.  
  202.     case CTRL_L:
  203.         CLEAROP;
  204.         clear_screen();
  205.         update_screen(0);
  206.         break;
  207.  
  208.  
  209.     case CTRL_O:                    /* ignored */
  210.         /*
  211.          * A command that's ignored can be useful. We use it at
  212.          * times when we want to postpone redraws. By put_string_into_input_bufferg
  213.          * in a control-o, redraws get suspended until the editor
  214.          * gets back around to processing input.
  215.          */
  216.         break;
  217.  
  218.     case CTRL_G:
  219.         CLEAROP;
  220.         file_info();
  221.         break;
  222.  
  223.     case CTRL_CIRCUMFLEX:                  /* shorthand command */
  224.         CLEAROP;
  225.             put_string_into_input_buffer(":e #\n");
  226.         break;
  227.  
  228.     case 'Z':                       /* write, if changed, and exit */
  229.         if (get_char_from_input_buffer() != 'Z') {
  230.             beep();
  231.             break;
  232.         }
  233.         do_exit();
  234.         break;
  235.  
  236.     /*
  237.      * Macro evaluates true if char 'c' is a valid identifier character
  238.      */
  239. #       define  IDCHAR(c)       (is_alpha(c) || is_digit(c) || (c) == '_')
  240.  
  241.     case CTRL_RIGHT_BRACKET:                        /* :ta to current identifier */
  242.         CLEAROP;
  243.         {
  244.             char    ch;
  245.             LPTR    save;
  246.  
  247.             save = *cursor_char;
  248.             /*
  249.              * First back up to start of identifier. This
  250.              * doesn't match the real vi but I like it a
  251.              * little better and it shouldn't bother anyone.
  252.              */
  253.             ch = gchar(cursor_char);
  254.             while (IDCHAR(ch)) {
  255.                 if (!one_left())
  256.                     break;
  257.                 ch = gchar(cursor_char);
  258.             }
  259.             if (!IDCHAR(ch))
  260.                 one_right();
  261.  
  262.             put_string_into_input_buffer(":ta ");
  263.             /*
  264.              * Now grab the chars in the identifier
  265.              */
  266.             ch = gchar(cursor_char);
  267.             while (IDCHAR(ch)) {
  268.                 put_string_into_input_buffer(mkstr(ch));
  269.                 if (!one_right())
  270.                     break;
  271.                 ch = gchar(cursor_char);
  272.             }
  273.             put_string_into_input_buffer("\n");
  274.  
  275.             *cursor_char = save;       /* restore, in case of error */
  276.         }
  277.         break;
  278.  
  279.     /*
  280.      * Character motion commands
  281.      */
  282.     case 'G':
  283.         mtype = MLINE;
  284.         *cursor_char = *goto_line(prenum);
  285.         begin_line((1));
  286.         break;
  287.  
  288.     case 'H':
  289.         mtype = MLINE;
  290.         *cursor_char = *top_char;
  291.         for (n = prenum; n && one_down(1) ;n--)
  292.             ;
  293.         begin_line((1));
  294.         break;
  295.  
  296.     case 'M':
  297.         mtype = MLINE;
  298.         *cursor_char = *top_char;
  299.         for (n = 0; n < current_lines/2 && one_down(1) ;n++)
  300.             ;
  301.         begin_line((1));
  302.         break;
  303.  
  304.     case 'L':
  305.         mtype = MLINE;
  306.         *cursor_char = *previous_line(bottom_char);
  307.         for (n = prenum; n && one_up(1) ;n--)
  308.             ;
  309.         begin_line((1));
  310.         break;
  311.  
  312.     case 'l':
  313.     case ' ':
  314.         mtype = MCHAR;
  315.         mincl = (0);
  316.         n = DEFAULT1(prenum);
  317.         while (n--) {
  318.             if ( ! one_right() )
  319.                 beep();
  320.         }
  321.         set_wanted_cursor_column = (1);
  322.         break;
  323.  
  324.     case 'h':
  325.     case CTRL_H:
  326.         mtype = MCHAR;
  327.         mincl = (0);
  328.         n = DEFAULT1(prenum);
  329.         while (n--) {
  330.             if ( ! one_left() )
  331.                 beep();
  332.         }
  333.         set_wanted_cursor_column = (1);
  334.         break;
  335.  
  336.     case '-':
  337.         flag = (1);
  338.         /* fall through */
  339.  
  340.     case 'k':
  341.     case CTRL_P:
  342.         mtype = MLINE;
  343.         if ( ! one_up(DEFAULT1(prenum)) )
  344.             beep();
  345.         if (flag)
  346.             begin_line((1));
  347.         break;
  348.  
  349.     case '+':
  350.     case CTRL_J:
  351.     case CTRL_M:
  352.         flag = (1);
  353.         /* fall through */
  354.  
  355.     case 'j':
  356.     case CTRL_N:
  357.         mtype = MLINE;
  358.         if ( ! one_down(DEFAULT1(prenum)) )
  359.             beep();
  360.         if (flag)
  361.             begin_line((1));
  362.         break;
  363.  
  364.     /*
  365.      * This is a strange motion command that helps make operators
  366.      * more logical. It is actually implemented, but not documented
  367.      * in the real 'vi'. This motion command actually refers to "the
  368.      * current line". Commands like "dd" and "yy" are really an alternate
  369.      * form of "d_" and "y_". It does accept a count, so "d3_" works to
  370.      * delete 3 lines.
  371.      */
  372.     case '_':
  373.     lineop:
  374.         mtype = MLINE;
  375.         one_down(DEFAULT1(prenum)-1);
  376.         break;
  377.  
  378.     case '|':
  379.         mtype = MCHAR;
  380.         mincl = (1);
  381.         begin_line((0));
  382.         if (prenum > 0)
  383.             *cursor_char = *advance_column(cursor_char, prenum-1);
  384.         wanted_cursor_column = prenum - 1;
  385.         break;
  386.         
  387.     /*
  388.      * Word Motions
  389.      */
  390.  
  391.     case 'B':
  392.         type = 1;
  393.         /* fall through */
  394.  
  395.     case 'b':
  396.         mtype = MCHAR;
  397.         mincl = (0);
  398.         set_wanted_cursor_column = (1);
  399.         for (n = DEFAULT1(prenum); n > 0 ;n--) {
  400.             LPTR    *pos;
  401.  
  402.             if ((pos = back_word(cursor_char, type)) == NULL) {
  403.                 beep();
  404.                 CLEAROP;
  405.                 break;
  406.             } else
  407.                 *cursor_char = *pos;
  408.         }
  409.         break;
  410.  
  411.     case 'W':
  412.         type = 1;
  413.         /* fall through */
  414.  
  415.     case 'w':
  416.         /*
  417.          * This is a little strange. To match what the real vi
  418.          * does, we effectively map 'cw' to 'ce', and 'cW' to 'cE'.
  419.          * This seems impolite at first, but it's really more
  420.          * what we mean when we say 'cw'.
  421.          */
  422.         if (operator == CHANGE)
  423.             goto do_e_command;
  424.  
  425.         mtype = MCHAR;
  426.         mincl = (0);
  427.         set_wanted_cursor_column = (1);
  428.         for (n = DEFAULT1(prenum); n > 0 ;n--) {
  429.             LPTR    *pos;
  430.  
  431.             if ((pos = forward_word(cursor_char, type)) == NULL) {
  432.                 beep();
  433.                 CLEAROP;
  434.                 break;
  435.             } else
  436.                 *cursor_char = *pos;
  437.         }
  438.         break;
  439.  
  440.     case 'E':
  441.         type = 1;
  442.         /* fall through */
  443.  
  444.     case 'e':
  445.     do_e_command:
  446.         mtype = MCHAR;
  447.         mincl = (1);
  448.         set_wanted_cursor_column = (1);
  449.         for (n = DEFAULT1(prenum); n > 0 ;n--) {
  450.             LPTR    *pos;
  451.  
  452.             /*
  453.              * The first motion gets special treatment if we're
  454.              * do a 'CHANGE'.
  455.              */
  456.             if (n == DEFAULT1(prenum))
  457.                 pos = end_word(cursor_char,type,operator==CHANGE);
  458.             else
  459.                 pos = end_word(cursor_char, type, (0));
  460.  
  461.             if (pos == NULL) {
  462.                 beep();
  463.                 CLEAROP;
  464.                 break;
  465.             } else
  466.                 *cursor_char = *pos;
  467.         }
  468.         break;
  469.  
  470.     case '$':
  471.         mtype = MCHAR;
  472.         mincl = (1);
  473.         while ( one_right() )
  474.             ;
  475.         wanted_cursor_column = 999;         /* so we stay at the end */
  476.         break;
  477.  
  478.     case '^':
  479.         mtype = MCHAR;
  480.         mincl = (0);
  481.         begin_line((1));
  482.         break;
  483.  
  484.     case '0':
  485.         mtype = MCHAR;
  486.         mincl = (1);
  487.         begin_line((0));
  488.         break;
  489.  
  490.     /*
  491.      * Searches of various kinds
  492.      */
  493.     case '?':
  494.     case '/':
  495.         s = getcmdln(c);        /* get the search string */
  496.  
  497.         /*
  498.          * If they backspaced out of the search command,
  499.          * just bag everything.
  500.          */
  501.         if (s == NULL) {
  502.             CLEAROP;
  503.             break;
  504.         }
  505.  
  506.         mtype = MCHAR;
  507.         mincl = (0);
  508.         set_wanted_cursor_column = (1);
  509.  
  510.         /*
  511.          * If no string given, pass NULL to repeat the prior search.
  512.          * If the search fails, abort any pending operator.
  513.          */
  514.         if (!do_search(
  515.                 (c == '/') ? SEARCH_FORWARD : SEARCH_BACKWARD,
  516.                 (*s == '\0') ? NULL : s
  517.                  ))
  518.             CLEAROP;
  519.         break;
  520.  
  521.     case 'n':
  522.         mtype = MCHAR;
  523.         mincl = (0);
  524.         set_wanted_cursor_column = (1);
  525.         if (!rep_search(0))
  526.             CLEAROP;
  527.         break;
  528.  
  529.     case 'N':
  530.         mtype = MCHAR;
  531.         mincl = (0);
  532.         set_wanted_cursor_column = (1);
  533.         if (!rep_search(1))
  534.             CLEAROP;
  535.         break;
  536.  
  537.     /*
  538.      * Character searches
  539.      */
  540.     case 'T':
  541.         dir = SEARCH_BACKWARD;
  542.         /* fall through */
  543.  
  544.     case 't':
  545.         type = 1;
  546.         goto docsearch;
  547.  
  548.     case 'F':
  549.         dir = SEARCH_BACKWARD;
  550.         /* fall through */
  551.  
  552.     case 'f':
  553.     docsearch:
  554.         mtype = MCHAR;
  555.         mincl = (1);
  556.         set_wanted_cursor_column = (1);
  557.         if ((nchar = get_char_from_input_buffer()) == ESC)   /* search char */
  558.             break;
  559.  
  560.         for (n = DEFAULT1(prenum); n > 0 ;n--) {
  561.             if (!search_char(nchar, dir, type)) {
  562.                 CLEAROP;
  563.                 beep();
  564.             }
  565.         }
  566.         break;
  567.  
  568.     case ',':
  569.         flag = 1;
  570.         /* fall through */
  571.  
  572.     case ';':
  573.         mtype = MCHAR;
  574.         mincl = (1);
  575.         set_wanted_cursor_column = (1);
  576.         for (n = DEFAULT1(prenum); n > 0 ;n--) {
  577.             if (!crep_search(flag)) {
  578.                 CLEAROP;
  579.                 beep();
  580.             }
  581.         }
  582.         break;
  583.  
  584.     case '(':                       /* sentence searches */
  585.         dir = SEARCH_BACKWARD;
  586.         /* fall through */
  587.  
  588.     case ')':
  589.         mtype = MCHAR;
  590.         mincl = (0);
  591.         set_wanted_cursor_column = (1);
  592.         if (find_sent(dir) == 0) {
  593.             beep();
  594.             CLEAROP;
  595.         }
  596.         break;
  597.  
  598.     case '{':                       /* paragraph searches */
  599.         dir = SEARCH_BACKWARD;
  600.         /* fall through */
  601.  
  602.     case '}':
  603.         mtype = MCHAR;
  604.         mincl = (0);
  605.         set_wanted_cursor_column = (1);
  606.         if (!find_param(dir)) {
  607.             beep();
  608.             CLEAROP;
  609.         }
  610.         break;
  611.  
  612.     case '[':                       /* function searches */
  613.         dir = SEARCH_BACKWARD;
  614.         /* fall through */
  615.  
  616.     case ']':
  617.         mtype = MLINE;
  618.         set_wanted_cursor_column = (1);
  619.         if (get_char_from_input_buffer() != c) {
  620.             beep();
  621.             CLEAROP;
  622.             break;
  623.         }
  624.  
  625.         if (!find_function(dir)) {
  626.             beep();
  627.             CLEAROP;
  628.         }
  629.         break;
  630.  
  631.     case '%':
  632.         mtype = MCHAR;
  633.         mincl = (1);
  634.         {
  635.             LPTR    *pos;
  636.  
  637.             if ((pos = show_match()) == NULL) {
  638.                 beep();
  639.                 CLEAROP;
  640.             } else {
  641.                 set_pc_mark();
  642.                 *cursor_char = *pos;
  643.                 set_wanted_cursor_column = (1);
  644.             }
  645.         }
  646.         break;
  647.         
  648.     /*
  649.      * Edits
  650.      */
  651.     case '.':               /* repeat last change (usually) */
  652.         /*
  653.          * If a delete is in effect, we let '.' help out the same
  654.          * way that '_' helps for some line operations. It's like
  655.          * an 'l', but subtracts one from the count and is inclusive.
  656.          */
  657.         if (operator == DELETE || operator == CHANGE) {
  658.             if (prenum != 0) {
  659.                 n = DEFAULT1(prenum) - 1;
  660.                 while (n--)
  661.                     if (! one_right())
  662.                         break;
  663.             }
  664.             mtype = MCHAR;
  665.             mincl = (1);
  666.         } else {                        /* a normal 'redo' */
  667.             CLEAROP;
  668.             put_string_into_input_buffer(redo_buffer);
  669.         }
  670.         break;
  671.  
  672.     case 'u':
  673.         CLEAROP;
  674.         u_undo();
  675.         break;
  676.  
  677.     case 'U':
  678.         CLEAROP;
  679.         u_l_undo();
  680.         break;
  681.  
  682.     case 'x':
  683.         CLEAROP;
  684.         if (line_empty())        /* can't do it on a blank line */
  685.             beep();
  686.         if (prenum)
  687.             put_int_into_input_buffer(prenum);
  688.         put_string_into_input_buffer("d.");
  689.         break;
  690.  
  691.     case 'X':
  692.         CLEAROP;
  693.         if (!one_left())
  694.             beep();
  695.         else {
  696.             strcpy(redo_buffer, "X");
  697.             u_save_line();
  698.             delete_char((1));
  699.             update_line();
  700.         }
  701.         break;
  702.  
  703.     case 'r':
  704.         CLEAROP;
  705.         if (line_empty()) {      /* Nothing to replace */
  706.             beep();
  707.             break;
  708.         }
  709.         if ((nchar = get_char_from_input_buffer()) == ESC)
  710.             break;
  711.  
  712.         if (nchar==CTRL_J || nchar==CTRL_M) {
  713.             put_string_into_input_buffer("R\n\033");
  714.             break;
  715.         }
  716.  
  717.         if (nchar & 0x80) {
  718.             beep();
  719.             break;
  720.         }
  721.         u_save_line();
  722.  
  723.         /* Change current character. */
  724.         pchar(cursor_char, nchar);
  725.  
  726.         /* Save stuff necessary to redo it */
  727.         sprintf(redo_buffer, "r%c", nchar);
  728.  
  729.         CHANGED;
  730.         update_line();
  731.         break;
  732.  
  733.     case '~':               /* swap case */
  734.         CLEAROP;
  735.         if (line_empty()) {
  736.             beep();
  737.             break;
  738.         }
  739.         c = gchar(cursor_char);
  740.  
  741.         if (is_alpha(c)) {
  742.             if (is_lower(c))
  743.                 c = to_upper(c);
  744.             else
  745.                 c = to_lower(c);
  746.         }
  747.         u_save_line();
  748.  
  749.         pchar(cursor_char, c);     /* Change current character. */
  750.         one_right();
  751.  
  752.         strcpy(redo_buffer, "~");
  753.  
  754.         CHANGED;
  755.         update_line();
  756.  
  757.         break;
  758.  
  759.     case 'J':
  760.         CLEAROP;
  761.  
  762.         u_save(cursor_char->linep->prev, cursor_char->linep->next->next);
  763.  
  764.         if (!do_join((1)))
  765.             beep();
  766.  
  767.         strcpy(redo_buffer, "J");
  768.         update_screen(0);
  769.         break;
  770.  
  771.     /*
  772.      * Inserts
  773.      */
  774.     case 'A':
  775.         set_wanted_cursor_column = (1);
  776.         while (one_right())
  777.             ;
  778.         /* fall through */
  779.  
  780.     case 'a':
  781.         CLEAROP;
  782.         /* Works just like an 'i'nsert on the next character. */
  783.         if (!line_empty())
  784.             inc(cursor_char);
  785.         u_save_line();
  786.         do_start_insert(mkstr(c), (0));
  787.         break;
  788.  
  789.     case 'I':
  790.         begin_line((1));
  791.         /* fall through */
  792.  
  793.     case 'i':
  794.         CLEAROP;
  795.         u_save_line();
  796.         do_start_insert(mkstr(c), (0));
  797.         break;
  798.  
  799.     case 'o':
  800.         CLEAROP;
  801.         u_save(cursor_char->linep, cursor_char->linep->next);
  802.         open_command(SEARCH_FORWARD, (1));
  803.         do_start_insert("o", (1));
  804.         break;
  805.  
  806.     case 'O':
  807.         CLEAROP;
  808.         u_save(cursor_char->linep->prev, cursor_char->linep);
  809.         open_command(SEARCH_BACKWARD, (1));
  810.         do_start_insert("O", (1));
  811.         break;
  812.  
  813.     case 'R':
  814.         CLEAROP;
  815.         u_save_line();
  816.         do_start_insert("R", (0));
  817.         break;
  818.  
  819.     /*
  820.      * Operators
  821.      */
  822.     case 'd':
  823.         if (operator == DELETE)         /* handle 'dd' */
  824.             goto lineop;
  825.         if (prenum != 0)
  826.             opnum = prenum;
  827.         startop = *cursor_char;
  828.         operator = DELETE;
  829.         break;
  830.  
  831.     case 'c':
  832.         if (operator == CHANGE)         /* handle 'cc' */
  833.             goto lineop;
  834.         if (prenum != 0)
  835.             opnum = prenum;
  836.         startop = *cursor_char;
  837.         operator = CHANGE;
  838.         break;
  839.  
  840.     case 'y':
  841.         if (operator == YANK)           /* handle 'yy' */
  842.             goto lineop;
  843.         if (prenum != 0)
  844.             opnum = prenum;
  845.         startop = *cursor_char;
  846.         operator = YANK;
  847.         break;
  848.  
  849.     case '>':
  850.         if (operator == RSHIFT)         /* handle >> */
  851.             goto lineop;
  852.         if (prenum != 0)
  853.             opnum = prenum;
  854.         startop = *cursor_char;
  855.         operator = RSHIFT;
  856.         break;
  857.  
  858.     case '<':
  859.         if (operator == LSHIFT)         /* handle << */
  860.             goto lineop;
  861.         if (prenum != 0)
  862.             opnum = prenum;
  863.         startop = *cursor_char;    /* save current position */
  864.         operator = LSHIFT;
  865.         break;
  866.  
  867.     case '!':
  868.         if (operator == FILTER)         /* handle '!!' */
  869.             goto lineop;
  870.         if (prenum != 0)
  871.             opnum = prenum;
  872.         startop = *cursor_char;
  873.         operator = FILTER;
  874.         break;
  875.  
  876.     case 'p':
  877.         do_put(SEARCH_FORWARD);
  878.         break;
  879.  
  880.     case 'P':
  881.         do_put(SEARCH_BACKWARD);
  882.         break;
  883.  
  884.     /*
  885.      * Abbreviations
  886.      */
  887.     case 'D':
  888.         put_string_into_input_buffer("d$");
  889.         break;
  890.  
  891.     case 'Y':
  892.         if (prenum)
  893.             put_int_into_input_buffer(prenum);
  894.         put_string_into_input_buffer("yy");
  895.         break;
  896.  
  897.     case 'C':
  898.         put_string_into_input_buffer("c$");
  899.         break;
  900.  
  901.     case 's':                               /* substitute characters */
  902.         if (prenum)
  903.             put_int_into_input_buffer(prenum);
  904.         put_string_into_input_buffer("c.");
  905.         break;
  906.  
  907.     /*
  908.      * Marks
  909.      */
  910.     case 'm':
  911.         CLEAROP;
  912.         if (!set_mark(get_char_from_input_buffer()))
  913.             beep();
  914.         break;
  915.  
  916.     case '\'':
  917.         flag = (1);
  918.         /* fall through */
  919.  
  920.     case '`':
  921.         {
  922.             LPTR    mtmp, *mark;
  923.  
  924.             mark = get_mark(get_char_from_input_buffer());
  925.             if (mark == NULL) {
  926.                 beep();
  927.                 CLEAROP;
  928.             } else {
  929.                 mtmp = *mark;
  930.                 set_pc_mark();
  931.                 *cursor_char = mtmp;
  932.                 if (flag)
  933.                     begin_line((1));
  934.             }
  935.             mtype = flag ? MLINE : MCHAR;
  936.             mincl = (0);            /* ignored if not MCHAR */
  937.             set_wanted_cursor_column = (1);
  938.         }
  939.         break;
  940.  
  941.     default:
  942.         CLEAROP;
  943.         beep();
  944.         break;
  945.     }
  946.  
  947.     /*
  948.      * If an operation is pending, handle it...
  949.      */
  950.     if (finish_op) {                /* we just finished an operator */
  951.         if (operator == NOP)    /* ... but it was cancelled */
  952.             return;
  953.  
  954.         switch (operator) {
  955.  
  956.         case LSHIFT:
  957.         case RSHIFT:
  958.             do_shift(operator, c, nchar, prenum);
  959.             break;
  960.  
  961.         case DELETE:
  962.             do_delete(c, nchar, prenum);
  963.             break;
  964.  
  965.         case YANK:
  966.             (void) do_yank();        /* no redo on yank... */
  967.             break;
  968.  
  969.         case CHANGE:
  970.             do_change(c, nchar, prenum);
  971.             break;
  972.  
  973.         case FILTER:
  974.             do_filter(c, nchar, prenum);
  975.             break;
  976.  
  977.         default:
  978.             beep();
  979.         }
  980.         operator = NOP;
  981.     }
  982. }
  983.