home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / readline / vi_mode.c < prev    next >
C/C++ Source or Header  |  1994-01-26  |  27KB  |  1,333 lines

  1. /* vi_mode.c -- A vi emulation mode for Bash.
  2.    Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
  3.  
  4. /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
  5.  
  6.    This file is part of the GNU Readline Library, a library for
  7.    reading lines of text with interactive input and history editing.
  8.  
  9.    The GNU Readline Library is free software; you can redistribute it
  10.    and/or modify it under the terms of the GNU General Public License
  11.    as published by the Free Software Foundation; either version 1, or
  12.    (at your option) any later version.
  13.  
  14.    The GNU Readline Library is distributed in the hope that it will be
  15.    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  16.    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    The GNU General Public License is often shipped with GNU software, and
  20.    is generally kept in a file called COPYING or LICENSE.  If you do not
  21.    have a copy of the license, write to the Free Software Foundation,
  22.    675 Mass Ave, Cambridge, MA 02139, USA. */
  23.  
  24. /* **************************************************************** */
  25. /*                                    */
  26. /*            VI Emulation Mode                */
  27. /*                                    */
  28. /* **************************************************************** */
  29. #if defined (VI_MODE)
  30.  
  31. #include <sys/types.h>
  32.  
  33. #if defined (HAVE_STDLIB_H)
  34. #  include <stdlib.h>
  35. #else
  36. #  include "ansi_stdlib.h"
  37. #endif /* HAVE_STDLIB_H */
  38.  
  39. #if defined (STATIC_MALLOC)
  40. static char *xmalloc (), *xrealloc ();
  41. #else
  42. extern char *xmalloc (), *xrealloc ();
  43. #endif /* STATIC_MALLOC */
  44.  
  45. #include <stdio.h>
  46.  
  47. /* Some standard library routines. */
  48. #include "rldefs.h"
  49. #include "readline.h"
  50. #include "history.h"
  51.  
  52. #ifndef digit
  53. #define digit(c)  ((c) >= '0' && (c) <= '9')
  54. #endif
  55.  
  56. #ifndef isletter
  57. #define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
  58. #endif
  59.  
  60. #ifndef digit_value
  61. #define digit_value(c) ((c) - '0')
  62. #endif
  63.  
  64. #ifndef member
  65. #define member(c, s) ((c) ? (char *)strchr ((s), (c)) : 0)
  66. #endif
  67.  
  68. #ifndef isident
  69. #define isident(c) ((isletter(c) || digit(c) || c == '_'))
  70. #endif
  71.  
  72. #ifndef exchange
  73. #define exchange(x, y) {int temp = x; x = y; y = temp;}
  74. #endif
  75.  
  76. #ifndef VI_COMMENT_BEGIN_DEFAULT
  77. #define VI_COMMENT_BEGIN_DEFAULT "#"
  78. #endif
  79.  
  80. /* Variables imported from readline.c */
  81. extern int rl_point, rl_end, rl_mark, rl_done;
  82. extern FILE *rl_instream;
  83. extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
  84. extern Keymap _rl_keymap;
  85. extern char *rl_prompt;
  86. extern char *rl_line_buffer;
  87. extern int rl_arg_sign;
  88.  
  89. extern void rl_extend_line_buffer ();
  90. extern int rl_vi_check (), rl_digit_loop1 ();
  91.  
  92. /* Non-zero means enter insertion mode. */
  93. int _rl_vi_doing_insert = 0;
  94.  
  95. /* String inserted into the line by rl_vi_comment (). */
  96. char *rl_vi_comment_begin = (char *)NULL;
  97.  
  98. /* *** UNCLEAN *** */
  99. /* Command keys which do movement for xxx_to commands. */
  100. static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
  101.  
  102. /* Keymap used for vi replace characters.  Created dynamically since
  103.    rarely used. */
  104. static Keymap vi_replace_map = (Keymap)NULL;
  105.  
  106. /* The number of characters inserted in the last replace operation. */
  107. static int vi_replace_count = 0;
  108.  
  109. /* Defined in this file */
  110. int rl_vi_char_search ();
  111.  
  112. /* Defined in display.c */
  113. extern int rl_message (), rl_clear_message ();
  114. extern void rl_redisplay ();
  115.  
  116. /* Defined in complete.c */
  117. extern int rl_complete_internal ();
  118.  
  119. int _rl_vi_last_command = 'i';    /* default `.' puts you in insert mode */
  120. int _rl_vi_last_repeat = 1;
  121. int _rl_vi_last_arg_sign = 1;
  122. static int _rl_vi_last_motion = 0;
  123. static int _rl_vi_last_search_char = 0;
  124. static int _rl_vi_last_replacement = 0;
  125.  
  126. static int vi_redoing = 0;
  127.  
  128. /* Text modification commands.  These are the `redoable' commands. */
  129. static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
  130.  
  131. void
  132. rl_vi_set_last ()
  133. {
  134.   _rl_vi_last_command = 'i';
  135.   _rl_vi_last_repeat = 1;
  136.   _rl_vi_last_arg_sign = 1;
  137.   _rl_vi_last_motion = 0;
  138. }
  139.  
  140. /* Is the command C a VI mode text modification command? */
  141. int
  142. rl_vi_textmod_command (c)
  143.      int c;
  144. {
  145.   return (member (c, vi_textmod) != (char *)NULL);
  146. }
  147.  
  148. /* Bound to `.'.  Called from command mode, so we know that we have to
  149.    redo a text modification command.  The default for _rl_vi_last_command
  150.    puts you back into insert mode. */
  151. int
  152. rl_vi_redo (count, c)
  153.      int count, c;
  154. {
  155.   if (!rl_explicit_arg)
  156.     {
  157.       rl_numeric_arg = _rl_vi_last_repeat;
  158.       rl_arg_sign = _rl_vi_last_arg_sign;
  159.     }
  160.  
  161.   vi_redoing = 1;
  162.   rl_dispatch (_rl_vi_last_command, _rl_keymap);
  163.   vi_redoing = 0;
  164.  
  165.   return (0);
  166. }
  167.     
  168. /* Yank the nth arg from the previous line into this line at point. */
  169. int
  170. rl_vi_yank_arg (count)
  171.      int count;
  172. {
  173.   /* vi mode is defined to insert a space before the last argument. */
  174.   rl_insert (1, ' ');
  175.  
  176.   /* Readline thinks that the first word on a line is the 0th, while vi
  177.      thinks the first word on a line is the 1st.  Compensate. */
  178.   if (rl_explicit_arg)
  179.     rl_yank_nth_arg (count - 1, 0);
  180.   else
  181.     rl_yank_nth_arg ('$', 0);
  182.  
  183.   rl_vi_insertion_mode ();
  184.   return (0);
  185. }
  186.  
  187. /* With an argument, move back that many history lines, else move to the
  188.    beginning of history. */
  189. int
  190. rl_vi_fetch_history (count, c)
  191.      int count, c;
  192. {
  193.   int current = where_history ();
  194.  
  195.   /* Giving an argument of n means we want the nth command in the history
  196.      file.  The command number is interpreted the same way that the bash
  197.      `history' command does it -- that is, giving an argument count of 450
  198.      to this command would get the command listed as number 450 in the
  199.      output of `history'. */
  200.   if (rl_explicit_arg)
  201.     {
  202.       int wanted = history_base + current - count;
  203.       if (wanted <= 0)
  204.         rl_beginning_of_history (0, 0);
  205.       else
  206.         rl_get_previous_history (wanted);
  207.     }
  208.   else
  209.     rl_beginning_of_history (count, 0);
  210.   return (0);
  211. }
  212.  
  213. /* Search again for the last thing searched for. */
  214. int
  215. rl_vi_search_again (count, key)
  216.      int count, key;
  217. {
  218.   switch (key)
  219.     {
  220.     case 'n':
  221.       rl_noninc_reverse_search_again (count, key);
  222.       break;
  223.  
  224.     case 'N':
  225.       rl_noninc_forward_search_again (count, key);
  226.       break;
  227.     }
  228.   return (0);
  229. }
  230.  
  231. /* Do a vi style search. */
  232. int
  233. rl_vi_search (count, key)
  234.      int count, key;
  235. {
  236.   switch (key)
  237.     {
  238.     case '?':
  239.       rl_noninc_forward_search (count, key);
  240.       break;
  241.  
  242.     case '/':
  243.       rl_noninc_reverse_search (count, key);
  244.       break;
  245.  
  246.     default:
  247.       ding ();
  248.       break;
  249.     }
  250.   return (0);
  251. }
  252.  
  253. /* Completion, from vi's point of view. */
  254. int
  255. rl_vi_complete (ignore, key)
  256.      int ignore, key;
  257. {
  258.   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
  259.     {
  260.       if (!whitespace (rl_line_buffer[rl_point + 1]))
  261.     rl_vi_end_word (1, 'E');
  262.       rl_point++;
  263.     }
  264.  
  265.   if (key == '*')
  266.     rl_complete_internal ('*');    /* Expansion and replacement. */
  267.   else if (key == '=')
  268.     rl_complete_internal ('?');    /* List possible completions. */
  269.   else if (key == '\\')
  270.     rl_complete_internal (TAB);    /* Standard Readline completion. */
  271.   else
  272.     rl_complete (0, key);
  273.  
  274.   if (key == '*' || key == '\\')
  275.     rl_vi_insertion_mode ();
  276.   return (0);
  277. }
  278.  
  279. /* Tilde expansion for vi mode. */
  280. int
  281. rl_vi_tilde_expand (ignore, key)
  282.      int ignore, key;
  283. {
  284.   rl_tilde_expand (0, key);
  285.   rl_vi_insertion_mode ();
  286.   return (0);
  287. }
  288.  
  289. /* Previous word in vi mode. */
  290. int
  291. rl_vi_prev_word (count, key)
  292.      int count, key;
  293. {
  294.   if (count < 0)
  295.     return (rl_vi_next_word (-count, key));
  296.  
  297.   if (rl_point == 0)
  298.     {
  299.       ding ();
  300.       return (0);
  301.     }
  302.  
  303.   if (uppercase_p (key))
  304.     rl_vi_bWord (count);
  305.   else
  306.     rl_vi_bword (count);
  307.  
  308.   return (0);
  309. }
  310.  
  311. /* Next word in vi mode. */
  312. int
  313. rl_vi_next_word (count, key)
  314.      int count, key;
  315. {
  316.   if (count < 0)
  317.     return (rl_vi_prev_word (-count, key));
  318.  
  319.   if (rl_point >= (rl_end - 1))
  320.     {
  321.       ding ();
  322.       return (0);
  323.     }
  324.  
  325.   if (uppercase_p (key))
  326.     rl_vi_fWord (count);
  327.   else
  328.     rl_vi_fword (count);
  329.   return (0);
  330. }
  331.  
  332. /* Move to the end of the ?next? word. */
  333. int
  334. rl_vi_end_word (count, key)
  335.      int count, key;
  336. {
  337.   if (count < 0)
  338.     {
  339.       ding ();
  340.       return -1;
  341.     }
  342.  
  343.   if (uppercase_p (key))
  344.     rl_vi_eWord (count);
  345.   else
  346.     rl_vi_eword (count);
  347.   return (0);
  348. }
  349.  
  350. /* Move forward a word the way that 'W' does. */
  351. int
  352. rl_vi_fWord (count)
  353.      int count;
  354. {
  355.   while (count-- && rl_point < (rl_end - 1))
  356.     {
  357.       /* Skip until whitespace. */
  358.       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  359.     rl_point++;
  360.  
  361.       /* Now skip whitespace. */
  362.       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  363.     rl_point++;
  364.     }
  365.   return (0);
  366. }
  367.  
  368. int
  369. rl_vi_bWord (count)
  370.      int count;
  371. {
  372.   while (count-- && rl_point > 0)
  373.     {
  374.       /* If we are at the start of a word, move back to whitespace so
  375.      we will go back to the start of the previous word. */
  376.       if (!whitespace (rl_line_buffer[rl_point]) &&
  377.       whitespace (rl_line_buffer[rl_point - 1]))
  378.     rl_point--;
  379.  
  380.       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  381.     rl_point--;
  382.  
  383.       if (rl_point > 0)
  384.     {
  385.       while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
  386.       rl_point++;
  387.     }
  388.     }
  389.   return (0);
  390. }
  391.  
  392. int
  393. rl_vi_eWord (count)
  394.      int count;
  395. {
  396.   while (count-- && rl_point < (rl_end - 1))
  397.     {
  398.       if (!whitespace (rl_line_buffer[rl_point]))
  399.     rl_point++;
  400.  
  401.       /* Move to the next non-whitespace character (to the start of the
  402.      next word). */
  403.       while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
  404.  
  405.       if (rl_point && rl_point < rl_end)
  406.     {
  407.       /* Skip whitespace. */
  408.       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  409.         rl_point++;
  410.  
  411.       /* Skip until whitespace. */
  412.       while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
  413.         rl_point++;
  414.  
  415.       /* Move back to the last character of the word. */
  416.       rl_point--;
  417.     }
  418.     }
  419.   return (0);
  420. }
  421.  
  422. int
  423. rl_vi_fword (count)
  424.      int count;
  425. {
  426.   while (count-- && rl_point < (rl_end - 1))
  427.     {
  428.       /* Move to white space (really non-identifer). */
  429.       if (isident (rl_line_buffer[rl_point]))
  430.     {
  431.       while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
  432.         rl_point++;
  433.     }
  434.       else /* if (!whitespace (rl_line_buffer[rl_point])) */
  435.     {
  436.       while (!isident (rl_line_buffer[rl_point]) &&
  437.          !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  438.         rl_point++;
  439.     }
  440.  
  441.       /* Move past whitespace. */
  442.       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
  443.     rl_point++;
  444.     }
  445.   return (0);
  446. }
  447.  
  448. int
  449. rl_vi_bword (count)
  450.      int count;
  451. {
  452.   while (count-- && rl_point > 0)
  453.     {
  454.       int last_is_ident;
  455.  
  456.       /* If we are at the start of a word, move back to whitespace
  457.      so we will go back to the start of the previous word. */
  458.       if (!whitespace (rl_line_buffer[rl_point]) &&
  459.       whitespace (rl_line_buffer[rl_point - 1]))
  460.     rl_point--;
  461.  
  462.       /* If this character and the previous character are `opposite', move
  463.      back so we don't get messed up by the rl_point++ down there in
  464.      the while loop.  Without this code, words like `l;' screw up the
  465.      function. */
  466.       last_is_ident = isident (rl_line_buffer[rl_point - 1]);
  467.       if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
  468.       (!isident (rl_line_buffer[rl_point]) && last_is_ident))
  469.     rl_point--;
  470.  
  471.       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
  472.     rl_point--;
  473.  
  474.       if (rl_point > 0)
  475.     {
  476.       if (isident (rl_line_buffer[rl_point]))
  477.         while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
  478.       else
  479.         while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
  480.            !whitespace (rl_line_buffer[rl_point]));
  481.       rl_point++;
  482.     }
  483.     }
  484.   return (0);
  485. }
  486.  
  487. int
  488. rl_vi_eword (count)
  489.      int count;
  490. {
  491.   while (count-- && rl_point < rl_end - 1)
  492.     {
  493.       if (!whitespace (rl_line_buffer[rl_point]))
  494.     rl_point++;
  495.  
  496.       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  497.     rl_point++;
  498.  
  499.       if (rl_point < rl_end)
  500.     {
  501.       if (isident (rl_line_buffer[rl_point]))
  502.         while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
  503.       else
  504.         while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
  505.            && !whitespace (rl_line_buffer[rl_point]));
  506.     }
  507.       rl_point--;
  508.     }
  509.   return (0);
  510. }
  511.  
  512. int
  513. rl_vi_insert_beg ()
  514. {
  515.   rl_beg_of_line ();
  516.   rl_vi_insertion_mode ();
  517.   return (0);
  518. }
  519.  
  520. int
  521. rl_vi_append_mode ()
  522. {
  523.   if (rl_point < rl_end)
  524.     rl_point += 1;
  525.   rl_vi_insertion_mode ();
  526.   return (0);
  527. }
  528.  
  529. int
  530. rl_vi_append_eol ()
  531. {
  532.   rl_end_of_line ();
  533.   rl_vi_append_mode ();
  534.   return (0);
  535. }
  536.  
  537. /* What to do in the case of C-d. */
  538. int
  539. rl_vi_eof_maybe (count, c)
  540.      int count, c;
  541. {
  542.   return (rl_newline (1, '\n'));
  543. }
  544.  
  545. /* Insertion mode stuff. */
  546.  
  547. /* Switching from one mode to the other really just involves
  548.    switching keymaps. */
  549. int
  550. rl_vi_insertion_mode ()
  551. {
  552.   _rl_keymap = vi_insertion_keymap;
  553.   return (0);
  554. }
  555.  
  556. int
  557. vi_done_inserting ()
  558. {
  559.   if (_rl_vi_doing_insert)
  560.     {
  561.       rl_end_undo_group ();
  562.       _rl_vi_doing_insert = 0;
  563.     }
  564.   return (0);
  565. }
  566.  
  567. int
  568. rl_vi_movement_mode ()
  569. {
  570.   if (rl_point > 0)
  571.     rl_backward (1);
  572.  
  573.   rl_vi_set_last ();
  574.  
  575.   _rl_keymap = vi_movement_keymap;
  576.   vi_done_inserting ();
  577.   return (0);
  578. }
  579.  
  580. int
  581. rl_vi_arg_digit (count, c)
  582.      int count, c;
  583. {
  584.   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
  585.     return (rl_beg_of_line ());
  586.   else
  587.     return (rl_digit_argument (count, c));
  588. }
  589.  
  590. int
  591. rl_vi_change_case (count, ignore)
  592.      int count, ignore;
  593. {
  594.   char c = 0;
  595.  
  596.   /* Don't try this on an empty line. */
  597.   if (rl_point >= rl_end)
  598.     return (0);
  599.  
  600.   while (count-- && rl_point < rl_end)
  601.     {
  602.       if (uppercase_p (rl_line_buffer[rl_point]))
  603.     c = to_lower (rl_line_buffer[rl_point]);
  604.       else if (lowercase_p (rl_line_buffer[rl_point]))
  605.     c = to_upper (rl_line_buffer[rl_point]);
  606.       else
  607.     {
  608.       /* Just skip over characters neither upper nor lower case. */
  609.       rl_forward (1);
  610.       continue;
  611.     }
  612.  
  613.       /* Vi is kind of strange here. */
  614.       if (c)
  615.     {
  616.       rl_begin_undo_group ();
  617.       rl_delete (1, c);
  618.       rl_insert (1, c);
  619.       rl_end_undo_group ();
  620.       rl_vi_check ();
  621.         }
  622.       else
  623.     rl_forward (1);
  624.     }
  625.   return (0);
  626. }
  627.  
  628. int
  629. rl_vi_put (count, key)
  630.      int count, key;
  631. {
  632.   if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
  633.     rl_point++;
  634.  
  635.   rl_yank ();
  636.   rl_backward (1);
  637.   return (0);
  638. }
  639.  
  640. int
  641. rl_vi_check ()
  642. {
  643.   if (rl_point && rl_point == rl_end)
  644.     rl_point--;
  645.   return (0);
  646. }
  647.  
  648. int
  649. rl_vi_column (count)
  650.      int count;
  651. {
  652.   if (count > rl_end)
  653.     rl_end_of_line ();
  654.   else
  655.     rl_point = count - 1;
  656.   return (0);
  657. }
  658.  
  659. int
  660. rl_vi_domove (key, nextkey)
  661.      int key, *nextkey;
  662. {
  663.   int c, save;
  664.   int old_end;
  665.  
  666.   rl_mark = rl_point;
  667.   c = rl_read_key ();
  668.   *nextkey = c;
  669.  
  670.   if (!member (c, vi_motion))
  671.     {
  672.       if (digit (c))
  673.     {
  674.       save = rl_numeric_arg;
  675.       rl_numeric_arg = digit_value (c);
  676.       rl_digit_loop1 ();
  677.       rl_numeric_arg *= save;
  678.       c = rl_read_key ();    /* real command */
  679.       *nextkey = c;
  680.     }
  681.       else if ((key == 'd' && c == 'd') ||
  682.            (key == 'y' && c == 'y') ||
  683.            (key == 'c' && c == 'c'))
  684.     {
  685.       rl_mark = rl_end;
  686.       rl_beg_of_line ();
  687.       _rl_vi_last_motion = c;
  688.       return (0);
  689.     }
  690.       else
  691.     return (-1);
  692.     }
  693.  
  694.   _rl_vi_last_motion = c;
  695.  
  696.   /* Append a blank character temporarily so that the motion routines
  697.      work right at the end of the line. */
  698.   old_end = rl_end;
  699.   rl_line_buffer[rl_end++] = ' ';
  700.   rl_line_buffer[rl_end] = '\0';
  701.  
  702.   rl_dispatch (c, _rl_keymap);
  703.  
  704.   /* Remove the blank that we added. */
  705.   rl_end = old_end;
  706.   rl_line_buffer[rl_end] = '\0';
  707.   if (rl_point > rl_end)
  708.     rl_point = rl_end;
  709.  
  710.   /* No change in position means the command failed. */
  711.   if (rl_mark == rl_point)
  712.     return (-1);
  713.  
  714.   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
  715.      word.  If we are not at the end of the line, and we are on a
  716.      non-whitespace character, move back one (presumably to whitespace). */
  717.   if ((c == 'w' || c == 'W') && (rl_point < rl_end) &&
  718.       !whitespace (rl_line_buffer[rl_point]))
  719.     rl_point--;
  720.  
  721.   /* If cw or cW, back up to the end of a word, so the behaviour of ce
  722.      or cE is the actual result.  Brute-force, no subtlety. */
  723.   if (key == 'c' && (to_upper (c) == 'W'))
  724.     {
  725.       while (rl_point && whitespace (rl_line_buffer[rl_point]))
  726.     rl_point--;
  727.  
  728.       /* Move past the end of the word so that the kill doesn't remove the
  729.      last letter of the previous word.  Only do this if we are not at
  730.      the end of the line. */
  731.       if ((rl_point >= 0) && (rl_point < (rl_end - 1)) &&
  732.       !whitespace (rl_line_buffer[rl_point]))
  733.     rl_point++;
  734.     }
  735.  
  736.   if (rl_mark < rl_point)
  737.     exchange (rl_point, rl_mark);
  738.  
  739.   return (0);
  740. }
  741.  
  742. /* A simplified loop for vi. Don't dispatch key at end.
  743.    Don't recognize minus sign? */
  744. int
  745. rl_digit_loop1 ()
  746. {
  747.   int key, c;
  748.  
  749.   while (1)
  750.     {
  751.       rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
  752.       key = c = rl_read_key ();
  753.  
  754.       if (_rl_keymap[c].type == ISFUNC &&
  755.       _rl_keymap[c].function == rl_universal_argument)
  756.     {
  757.       rl_numeric_arg *= 4;
  758.       continue;
  759.     }
  760.  
  761.       c = UNMETA (c);
  762.       if (numeric (c))
  763.     {
  764.       if (rl_explicit_arg)
  765.         rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
  766.       else
  767.         rl_numeric_arg = digit_value (c);
  768.       rl_explicit_arg = 1;
  769.     }
  770.       else
  771.     {
  772.       rl_clear_message ();
  773.       rl_stuff_char (key);
  774.       break;
  775.     }
  776.     }
  777.   return (0);
  778. }
  779.  
  780. int
  781. rl_vi_delete_to (count, key)
  782.      int count, key;
  783. {
  784.   int c;
  785.  
  786.   if (uppercase_p (key))
  787.     rl_stuff_char ('$');
  788.   else if (vi_redoing)
  789.     rl_stuff_char (_rl_vi_last_motion);
  790.  
  791.   if (rl_vi_domove (key, &c))
  792.     {
  793.       ding ();
  794.       return -1;
  795.     }
  796.  
  797.   /* These are the motion commands that do not require adjusting the
  798.      mark. */
  799.   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
  800.     rl_mark++;
  801.  
  802.   rl_kill_text (rl_point, rl_mark);
  803.   return (0);
  804. }
  805.  
  806. int
  807. rl_vi_change_to (count, key)
  808.      int count, key;
  809. {
  810.   int c, start_pos;
  811.  
  812.   if (uppercase_p (key))
  813.     rl_stuff_char ('$');
  814.   else if (vi_redoing)
  815.     rl_stuff_char (_rl_vi_last_motion);
  816.  
  817.   start_pos = rl_point;
  818.  
  819.   if (rl_vi_domove (key, &c))
  820.     {
  821.       ding ();
  822.       return -1;
  823.     }
  824.  
  825.   /* These are the motion commands that do not require adjusting the
  826.      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
  827.      and already leave the mark at the correct location. */
  828.   if ((strchr (" l|hwW^0%bB", c) == 0) && (rl_mark < rl_end))
  829.     rl_mark++;
  830.  
  831.   /* The cursor never moves with c[wW]. */
  832.   if ((to_upper (c) == 'W') && rl_point < start_pos)
  833.     rl_point = start_pos;
  834.  
  835.   rl_begin_undo_group ();
  836.   _rl_vi_doing_insert = 1;
  837.   rl_kill_text (rl_point, rl_mark);
  838.   rl_vi_insertion_mode ();
  839.  
  840.   return (0);
  841. }
  842.  
  843. int
  844. rl_vi_yank_to (count, key)
  845.      int count, key;
  846. {
  847.   int c, save = rl_point;
  848.  
  849.   if (uppercase_p (key))
  850.     rl_stuff_char ('$');
  851.  
  852.   if (rl_vi_domove (key, &c))
  853.     {
  854.       ding ();
  855.       return -1;
  856.     }
  857.  
  858.   /* These are the motion commands that do not require adjusting the
  859.      mark. */
  860.   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
  861.     rl_mark++;
  862.  
  863.   rl_begin_undo_group ();
  864.   rl_kill_text (rl_point, rl_mark);
  865.   rl_end_undo_group ();
  866.   rl_do_undo ();
  867.   rl_point = save;
  868.  
  869.   return (0);
  870. }
  871.  
  872. int
  873. rl_vi_delete (count)
  874.      int count;
  875. {
  876.   int end;
  877.  
  878.   if (rl_end == 0)
  879.     {
  880.       ding ();
  881.       return -1;
  882.     }
  883.  
  884.   end = rl_point + count;
  885.  
  886.   if (end >= rl_end)
  887.     end = rl_end;
  888.  
  889.   rl_kill_text (rl_point, end);
  890.   
  891.   if (rl_point > 0 && rl_point == rl_end)
  892.     rl_backward (1);
  893.   return (0);
  894. }
  895.  
  896. /* Turn the current line into a comment in shell history.
  897.    A K*rn shell style function. */
  898. int
  899. rl_vi_comment ()
  900. {
  901.   rl_beg_of_line ();
  902.  
  903.   if (rl_vi_comment_begin != (char *)NULL)
  904.     rl_insert_text (rl_vi_comment_begin);
  905.   else
  906.     rl_insert_text (VI_COMMENT_BEGIN_DEFAULT);    /* Default. */
  907.  
  908.   rl_redisplay ();
  909.   rl_newline (1, '\010');
  910.   return (0);
  911. }
  912.  
  913. int
  914. rl_back_to_indent (ignore1, ignore2)
  915.      int ignore1, ignore2;
  916. {
  917.   rl_beg_of_line ();
  918.   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
  919.     rl_point++;
  920.   return (0);
  921. }
  922.  
  923. int
  924. rl_vi_first_print ()
  925. {
  926.   return (rl_back_to_indent ());
  927. }
  928.  
  929. /* NOTE: it is necessary that opposite directions are inverses */
  930. #define    FTO     1        /* forward to */
  931. #define BTO    -1        /* backward to */
  932. #define FFIND     2        /* forward find */
  933. #define BFIND    -2        /* backward find */
  934.  
  935. int
  936. rl_vi_char_search (count, key)
  937.      int count, key;
  938. {
  939.   static char target;
  940.   static int orig_dir, dir;
  941.   int pos;
  942.  
  943.   if (key == ';' || key == ',')
  944.     dir = (key == ';' ? orig_dir : -orig_dir);
  945.   else
  946.     {
  947.       if (vi_redoing)
  948.     target = _rl_vi_last_search_char;
  949.       else
  950.     _rl_vi_last_search_char = target = rl_getc (rl_instream);
  951.  
  952.       switch (key)
  953.         {
  954.         case 't':
  955.           orig_dir = dir = FTO;
  956.           break;
  957.  
  958.         case 'T':
  959.           orig_dir = dir = BTO;
  960.           break;
  961.  
  962.         case 'f':
  963.           orig_dir = dir = FFIND;
  964.           break;
  965.  
  966.         case 'F':
  967.           orig_dir = dir = BFIND;
  968.           break;
  969.         }
  970.     }
  971.  
  972.   pos = rl_point;
  973.  
  974.   while (count--)
  975.     {
  976.       if (dir < 0)
  977.     {
  978.       if (pos == 0)
  979.         {
  980.           ding ();
  981.           return 0;
  982.         }
  983.  
  984.       pos--;
  985.       do
  986.         {
  987.           if (rl_line_buffer[pos] == target)
  988.         {
  989.           if (dir == BTO)
  990.             rl_point = pos + 1;
  991.           else
  992.             rl_point = pos;
  993.           break;
  994.         }
  995.         }
  996.       while (pos--);
  997.  
  998.       if (pos < 0)
  999.         {
  1000.           ding ();
  1001.           return -1;
  1002.         }
  1003.     }
  1004.       else
  1005.     {            /* dir > 0 */
  1006.       if (pos >= rl_end)
  1007.         {
  1008.           ding ();
  1009.           return -1;
  1010.         }
  1011.  
  1012.       pos++;
  1013.       do
  1014.         {
  1015.           if (rl_line_buffer[pos] == target)
  1016.         {
  1017.           if (dir == FTO)
  1018.             rl_point = pos - 1;
  1019.           else
  1020.             rl_point = pos;
  1021.           break;
  1022.         }
  1023.         }
  1024.       while (++pos < rl_end);
  1025.  
  1026.       if (pos >= (rl_end - 1))
  1027.         {
  1028.           ding ();
  1029.           return -1;
  1030.         }
  1031.     }
  1032.     }
  1033.   return (0);
  1034. }
  1035.  
  1036. /* Match brackets */
  1037. int
  1038. rl_vi_match ()
  1039. {
  1040.   int count = 1, brack, pos;
  1041.  
  1042.   pos = rl_point;
  1043.   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
  1044.     {
  1045.       while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
  1046.          rl_point < rl_end - 1)
  1047.     rl_forward (1);
  1048.  
  1049.       if (brack <= 0)
  1050.     {
  1051.       rl_point = pos;
  1052.       ding ();
  1053.       return -1;
  1054.     }
  1055.     }
  1056.  
  1057.   pos = rl_point;
  1058.  
  1059.   if (brack < 0)
  1060.     {
  1061.       while (count)
  1062.     {
  1063.       if (--pos >= 0)
  1064.         {
  1065.           int b = rl_vi_bracktype (rl_line_buffer[pos]);
  1066.           if (b == -brack)
  1067.         count--;
  1068.           else if (b == brack)
  1069.         count++;
  1070.         }
  1071.       else
  1072.         {
  1073.           ding ();
  1074.           return -1;
  1075.         }
  1076.     }
  1077.     }
  1078.   else
  1079.     {            /* brack > 0 */
  1080.       while (count)
  1081.     {
  1082.       if (++pos < rl_end)
  1083.         {
  1084.           int b = rl_vi_bracktype (rl_line_buffer[pos]);
  1085.           if (b == -brack)
  1086.         count--;
  1087.           else if (b == brack)
  1088.         count++;
  1089.         }
  1090.       else
  1091.         {
  1092.           ding ();
  1093.           return -1;
  1094.         }
  1095.     }
  1096.     }
  1097.   rl_point = pos;
  1098.   return (0);
  1099. }
  1100.  
  1101. int
  1102. rl_vi_bracktype (c)
  1103.      int c;
  1104. {
  1105.   switch (c)
  1106.     {
  1107.     case '(': return  1;
  1108.     case ')': return -1;
  1109.     case '[': return  2;
  1110.     case ']': return -2;
  1111.     case '{': return  3;
  1112.     case '}': return -3;
  1113.     default:  return  0;
  1114.     }
  1115. }
  1116.  
  1117. int
  1118. rl_vi_change_char (count, key)
  1119.      int count, key;
  1120. {
  1121.   int c;
  1122.  
  1123.   if (vi_redoing)
  1124.     c = _rl_vi_last_replacement;
  1125.   else
  1126.     _rl_vi_last_replacement = c = rl_getc (rl_instream);
  1127.  
  1128.   if (c == '\033' || c == CTRL ('C'))
  1129.     return -1;
  1130.  
  1131.   while (count-- && rl_point < rl_end)
  1132.     {
  1133.       rl_begin_undo_group ();
  1134.  
  1135.       rl_delete (1, c);
  1136.       rl_insert (1, c);
  1137.       if (count == 0)
  1138.     rl_backward (1);
  1139.  
  1140.       rl_end_undo_group ();
  1141.     }
  1142.   return (0);
  1143. }
  1144.  
  1145. int
  1146. rl_vi_subst (count, key)
  1147.      int count, key;
  1148. {
  1149.   rl_begin_undo_group ();
  1150.   _rl_vi_doing_insert = 1;
  1151.  
  1152.   if (uppercase_p (key))
  1153.     {
  1154.       rl_beg_of_line ();
  1155.       rl_kill_line (1);
  1156.     }
  1157.   else
  1158.     rl_delete (count, key);
  1159.  
  1160.   rl_end_undo_group ();
  1161.  
  1162.   rl_vi_insertion_mode ();
  1163.   return (0);
  1164. }
  1165.  
  1166. int
  1167. rl_vi_overstrike (count, key)
  1168.      int count, key;
  1169. {
  1170.   int i;
  1171.  
  1172.   if (_rl_vi_doing_insert == 0)
  1173.     {
  1174.       _rl_vi_doing_insert = 1;
  1175.       rl_begin_undo_group ();
  1176.     }
  1177.  
  1178.   for (i = 0; i < count; i++)
  1179.     {
  1180.       vi_replace_count++;
  1181.       rl_begin_undo_group ();
  1182.  
  1183.       if (rl_point < rl_end)
  1184.     {
  1185.       rl_delete (1, key);
  1186.       rl_insert (1, key);
  1187.     }
  1188.       else
  1189.     rl_insert (1, key);
  1190.  
  1191.       rl_end_undo_group ();
  1192.     }
  1193.   return (0);
  1194. }
  1195.  
  1196. int
  1197. rl_vi_overstrike_delete (count)
  1198.      int count;
  1199. {
  1200.   int i, s;
  1201.  
  1202.   for (i = 0; i < count; i++)
  1203.     {
  1204.       if (vi_replace_count == 0)
  1205.     {
  1206.       ding ();
  1207.       break;
  1208.     }
  1209.       s = rl_point;
  1210.  
  1211.       if (rl_do_undo ())
  1212.     vi_replace_count--;
  1213.  
  1214.       if (rl_point == s)
  1215.     rl_backward (1);
  1216.     }
  1217.  
  1218.   if (vi_replace_count == 0 && _rl_vi_doing_insert)
  1219.     {
  1220.       rl_end_undo_group ();
  1221.       rl_do_undo ();
  1222.       _rl_vi_doing_insert = 0;
  1223.     }
  1224.   return (0);
  1225. }
  1226.  
  1227. int
  1228. rl_vi_replace (count, key)
  1229.      int count, key;
  1230. {
  1231.   int i;
  1232.  
  1233.   vi_replace_count = 0;
  1234.  
  1235.   if (!vi_replace_map)
  1236.     {
  1237.       vi_replace_map = rl_make_bare_keymap ();
  1238.  
  1239.       for (i = ' '; i < 127; i++)
  1240.     vi_replace_map[i].function = rl_vi_overstrike;
  1241.  
  1242.       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
  1243.       vi_replace_map[ESC].function = rl_vi_movement_mode;
  1244.       vi_replace_map[RETURN].function = rl_newline;
  1245.       vi_replace_map[NEWLINE].function = rl_newline;
  1246.  
  1247.       /* If the normal vi insertion keymap has ^H bound to erase, do the
  1248.          same here.  Probably should remove the assignment to RUBOUT up
  1249.          there, but I don't think it will make a difference in real life. */
  1250.       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
  1251.       vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
  1252.     vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
  1253.  
  1254.     }
  1255.   _rl_keymap = vi_replace_map;
  1256.   return (0);
  1257. }
  1258.  
  1259. /* Try to complete the word we are standing on or the word that ends with
  1260.    the previous character.  A space matches everything.  Word delimiters are
  1261.    space and ;. */
  1262. int
  1263. rl_vi_possible_completions ()
  1264. {
  1265.   int save_pos = rl_point;
  1266.  
  1267.   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
  1268.     {
  1269.       while (rl_line_buffer[rl_point] != ' ' &&
  1270.          rl_line_buffer[rl_point] != ';')
  1271.     ;
  1272.     }
  1273.   else if (rl_line_buffer[rl_point - 1] == ';')
  1274.     {
  1275.       ding ();
  1276.       return (0);
  1277.     }
  1278.  
  1279.   rl_possible_completions ();
  1280.   rl_point = save_pos;
  1281.  
  1282.   return (0);
  1283. }
  1284.  
  1285. #if defined (STATIC_MALLOC)
  1286.  
  1287. /* **************************************************************** */
  1288. /*                                    */
  1289. /*            xmalloc and xrealloc ()                     */
  1290. /*                                    */
  1291. /* **************************************************************** */
  1292.  
  1293. static void memory_error_and_abort ();
  1294.  
  1295. static char *
  1296. xmalloc (bytes)
  1297.      int bytes;
  1298. {
  1299.   char *temp = (char *)malloc (bytes);
  1300.  
  1301.   if (!temp)
  1302.     memory_error_and_abort ();
  1303.   return (temp);
  1304. }
  1305.  
  1306. static char *
  1307. xrealloc (pointer, bytes)
  1308.      char *pointer;
  1309.      int bytes;
  1310. {
  1311.   char *temp;
  1312.  
  1313.   if (!pointer)
  1314.     temp = (char *)xmalloc (bytes);
  1315.   else
  1316.     temp = (char *)realloc (pointer, bytes);
  1317.  
  1318.   if (!temp)
  1319.     memory_error_and_abort ();
  1320.  
  1321.   return (temp);
  1322. }
  1323.  
  1324. static void
  1325. memory_error_and_abort ()
  1326. {
  1327.   fprintf (stderr, "readline: Out of virtual memory!\n");
  1328.   abort ();
  1329. }
  1330. #endif /* STATIC_MALLOC */
  1331.  
  1332. #endif /* VI_MODE */
  1333.