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-2005 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 2, 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    51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA. */
23 #define READLINE_LIBRARY
24 
25 /* **************************************************************** */
26 /*								    */
27 /*			VI Emulation Mode			    */
28 /*								    */
29 /* **************************************************************** */
30 #include "rlconf.h"
31 
32 #if defined (VI_MODE)
33 
34 #if defined (HAVE_CONFIG_H)
35 #  include "config_readline.h"
36 #endif
37 
38 #include <sys/types.h>
39 
40 #if defined (HAVE_STDLIB_H)
41 #  include <stdlib.h>
42 #else
43 #  include "ansi_stdlib.h"
44 #endif /* HAVE_STDLIB_H */
45 
46 #if defined (HAVE_UNISTD_H)
47 #  include <unistd.h>
48 #endif
49 
50 #include <stdio.h>
51 
52 /* Some standard library routines. */
53 #include "rldefs.h"
54 #include "rlmbutil.h"
55 
56 #include "readline.h"
57 #include "history.h"
58 
59 #include "rlprivate.h"
60 #include "xmalloc.h"
61 
62 #ifndef member
63 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
64 #endif
65 
66 int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */
67 
68 /* Non-zero means enter insertion mode. */
69 static int _rl_vi_doing_insert;
70 
71 /* Command keys which do movement for xxx_to commands. */
72 static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|";
73 
74 /* Keymap used for vi replace characters.  Created dynamically since
75    rarely used. */
76 static Keymap vi_replace_map;
77 
78 /* The number of characters inserted in the last replace operation. */
79 static int vi_replace_count;
80 
81 /* If non-zero, we have text inserted after a c[motion] command that put
82    us implicitly into insert mode.  Some people want this text to be
83    attached to the command so that it is `redoable' with `.'. */
84 static int vi_continued_command;
85 static char *vi_insert_buffer;
86 static int vi_insert_buffer_size;
87 
88 static int _rl_vi_last_repeat = 1;
89 static int _rl_vi_last_arg_sign = 1;
90 static int _rl_vi_last_motion;
91 #if defined (HANDLE_MULTIBYTE)
92 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
93 static int _rl_vi_last_search_mblen;
94 #else
95 static int _rl_vi_last_search_char;
96 #endif
97 static int _rl_vi_last_replacement;
98 
99 static int _rl_vi_last_key_before_insert;
100 
101 static int vi_redoing;
102 
103 /* Text modification commands.  These are the `redoable' commands. */
104 static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
105 
106 /* Arrays for the saved marks. */
107 static int vi_mark_chars['z' - 'a' + 1];
108 
109 static void _rl_vi_stuff_insert PARAMS((int));
110 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
111 
112 static void _rl_vi_backup PARAMS((void));
113 
114 static int _rl_vi_arg_dispatch PARAMS((int));
115 static int rl_digit_loop1 PARAMS((void));
116 
117 static int _rl_vi_set_mark PARAMS((void));
118 static int _rl_vi_goto_mark PARAMS((void));
119 
120 static void _rl_vi_append_forward PARAMS((int));
121 
122 static int _rl_vi_callback_getchar PARAMS((char *, int));
123 
124 #if defined (READLINE_CALLBACKS)
125 static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
126 static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
127 static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
128 static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
129 #endif
130 
131 void
_rl_vi_initialize_line()132 _rl_vi_initialize_line ()
133 {
134   register size_t i;
135 
136   for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
137     vi_mark_chars[i] = -1;
138 
139   RL_UNSETSTATE(RL_STATE_VICMDONCE);
140 }
141 
142 void
_rl_vi_reset_last()143 _rl_vi_reset_last ()
144 {
145   _rl_vi_last_command = 'i';
146   _rl_vi_last_repeat = 1;
147   _rl_vi_last_arg_sign = 1;
148   _rl_vi_last_motion = 0;
149 }
150 
151 void
_rl_vi_set_last(key,repeat,sign)152 _rl_vi_set_last (key, repeat, sign)
153      int key, repeat, sign;
154 {
155   _rl_vi_last_command = key;
156   _rl_vi_last_repeat = repeat;
157   _rl_vi_last_arg_sign = sign;
158 }
159 
160 /* A convenience function that calls _rl_vi_set_last to save the last command
161    information and enters insertion mode. */
162 void
rl_vi_start_inserting(key,repeat,sign)163 rl_vi_start_inserting (key, repeat, sign)
164      int key, repeat, sign;
165 {
166   _rl_vi_set_last (key, repeat, sign);
167   rl_vi_insertion_mode (1, key);
168 }
169 
170 /* Is the command C a VI mode text modification command? */
171 int
_rl_vi_textmod_command(c)172 _rl_vi_textmod_command (c)
173      int c;
174 {
175   return (member (c, vi_textmod));
176 }
177 
178 static void
_rl_vi_stuff_insert(count)179 _rl_vi_stuff_insert (count)
180      int count;
181 {
182   rl_begin_undo_group ();
183   while (count--)
184     rl_insert_text (vi_insert_buffer);
185   rl_end_undo_group ();
186 }
187 
188 /* Bound to `.'.  Called from command mode, so we know that we have to
189    redo a text modification command.  The default for _rl_vi_last_command
190    puts you back into insert mode. */
191 int
rl_vi_redo(count,c)192 rl_vi_redo (count, c)
193      int count, c __attribute__((unused));
194 {
195   int r;
196 
197   if (!rl_explicit_arg)
198     {
199       rl_numeric_arg = _rl_vi_last_repeat;
200       rl_arg_sign = _rl_vi_last_arg_sign;
201     }
202 
203   r = 0;
204   vi_redoing = 1;
205   /* If we're redoing an insert with `i', stuff in the inserted text
206      and do not go into insertion mode. */
207   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
208     {
209       _rl_vi_stuff_insert (count);
210       /* And back up point over the last character inserted. */
211       if (rl_point > 0)
212 	_rl_vi_backup ();
213     }
214   /* Ditto for redoing an insert with `a', but move forward a character first
215      like the `a' command does. */
216   else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
217     {
218       _rl_vi_append_forward ('a');
219       _rl_vi_stuff_insert (count);
220       if (rl_point > 0)
221 	_rl_vi_backup ();
222     }
223   else
224     r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
225   vi_redoing = 0;
226 
227   return (r);
228 }
229 
230 /* A placeholder for further expansion. */
231 int
rl_vi_undo(count,key)232 rl_vi_undo (count, key)
233      int count, key;
234 {
235   return (rl_undo_command (count, key));
236 }
237 
238 /* Yank the nth arg from the previous line into this line at point. */
239 int
rl_vi_yank_arg(count,key)240 rl_vi_yank_arg (count, key)
241      int count, key __attribute__((unused));
242 {
243   /* Readline thinks that the first word on a line is the 0th, while vi
244      thinks the first word on a line is the 1st.  Compensate. */
245   if (rl_explicit_arg)
246     rl_yank_nth_arg (count - 1, 0);
247   else
248     rl_yank_nth_arg ('$', 0);
249 
250   return (0);
251 }
252 
253 /* With an argument, move back that many history lines, else move to the
254    beginning of history. */
255 int
rl_vi_fetch_history(count,c)256 rl_vi_fetch_history (count, c)
257      int count, c;
258 {
259   int wanted;
260 
261   /* Giving an argument of n means we want the nth command in the history
262      file.  The command number is interpreted the same way that the bash
263      `history' command does it -- that is, giving an argument count of 450
264      to this command would get the command listed as number 450 in the
265      output of `history'. */
266   if (rl_explicit_arg)
267     {
268       wanted = history_base + where_history () - count;
269       if (wanted <= 0)
270         rl_beginning_of_history (0, 0);
271       else
272         rl_get_previous_history (wanted, c);
273     }
274   else
275     rl_beginning_of_history (count, 0);
276   return (0);
277 }
278 
279 /* Search again for the last thing searched for. */
280 int
rl_vi_search_again(count,key)281 rl_vi_search_again (count, key)
282      int count, key;
283 {
284   switch (key)
285     {
286     case 'n':
287       rl_noninc_reverse_search_again (count, key);
288       break;
289 
290     case 'N':
291       rl_noninc_forward_search_again (count, key);
292       break;
293     }
294   return (0);
295 }
296 
297 /* Do a vi style search. */
298 int
rl_vi_search(count,key)299 rl_vi_search (count, key)
300      int count, key;
301 {
302   switch (key)
303     {
304     case '?':
305       _rl_free_saved_history_line ();
306       rl_noninc_forward_search (count, key);
307       break;
308 
309     case '/':
310       _rl_free_saved_history_line ();
311       rl_noninc_reverse_search (count, key);
312       break;
313 
314     default:
315       rl_ding ();
316       break;
317     }
318   return (0);
319 }
320 
321 /* Completion, from vi's point of view. */
322 int
rl_vi_complete(ignore,key)323 rl_vi_complete (ignore, key)
324      int ignore __attribute__((unused)), key;
325 {
326   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
327     {
328       if (!whitespace (rl_line_buffer[rl_point + 1]))
329 	rl_vi_end_word (1, 'E');
330       rl_point++;
331     }
332 
333   if (key == '*')
334     rl_complete_internal ('*');	/* Expansion and replacement. */
335   else if (key == '=')
336     rl_complete_internal ('?');	/* List possible completions. */
337   else if (key == '\\')
338     rl_complete_internal (TAB);	/* Standard Readline completion. */
339   else
340     rl_complete (0, key);
341 
342   if (key == '*' || key == '\\')
343     rl_vi_start_inserting (key, 1, rl_arg_sign);
344 
345   return (0);
346 }
347 
348 /* Tilde expansion for vi mode. */
349 int
rl_vi_tilde_expand(ignore,key)350 rl_vi_tilde_expand (ignore, key)
351      int ignore __attribute__((unused)), key;
352 {
353   rl_tilde_expand (0, key);
354   rl_vi_start_inserting (key, 1, rl_arg_sign);
355   return (0);
356 }
357 
358 /* Previous word in vi mode. */
359 int
rl_vi_prev_word(count,key)360 rl_vi_prev_word (count, key)
361      int count, key;
362 {
363   if (count < 0)
364     return (rl_vi_next_word (-count, key));
365 
366   if (rl_point == 0)
367     {
368       rl_ding ();
369       return (0);
370     }
371 
372   if (_rl_uppercase_p (key))
373     rl_vi_bWord (count, key);
374   else
375     rl_vi_bword (count, key);
376 
377   return (0);
378 }
379 
380 /* Next word in vi mode. */
381 int
rl_vi_next_word(count,key)382 rl_vi_next_word (count, key)
383      int count, key;
384 {
385   if (count < 0)
386     return (rl_vi_prev_word (-count, key));
387 
388   if (rl_point >= (rl_end - 1))
389     {
390       rl_ding ();
391       return (0);
392     }
393 
394   if (_rl_uppercase_p (key))
395     rl_vi_fWord (count, key);
396   else
397     rl_vi_fword (count, key);
398   return (0);
399 }
400 
401 /* Move to the end of the ?next? word. */
402 int
rl_vi_end_word(count,key)403 rl_vi_end_word (count, key)
404      int count, key;
405 {
406   if (count < 0)
407     {
408       rl_ding ();
409       return -1;
410     }
411 
412   if (_rl_uppercase_p (key))
413     rl_vi_eWord (count, key);
414   else
415     rl_vi_eword (count, key);
416   return (0);
417 }
418 
419 /* Move forward a word the way that 'W' does. */
420 int
rl_vi_fWord(count,ignore)421 rl_vi_fWord (count, ignore)
422      int count, ignore __attribute__((unused));
423 {
424   while (count-- && rl_point < (rl_end - 1))
425     {
426       /* Skip until whitespace. */
427       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
428 	rl_point++;
429 
430       /* Now skip whitespace. */
431       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
432 	rl_point++;
433     }
434   return (0);
435 }
436 
437 int
rl_vi_bWord(count,ignore)438 rl_vi_bWord (count, ignore)
439      int count, ignore __attribute__((unused));
440 {
441   while (count-- && rl_point > 0)
442     {
443       /* If we are at the start of a word, move back to whitespace so
444 	 we will go back to the start of the previous word. */
445       if (!whitespace (rl_line_buffer[rl_point]) &&
446 	  whitespace (rl_line_buffer[rl_point - 1]))
447 	rl_point--;
448 
449       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
450 	rl_point--;
451 
452       if (rl_point > 0)
453 	{
454 	  while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
455 	  rl_point++;
456 	}
457     }
458   return (0);
459 }
460 
461 int
rl_vi_eWord(count,ignore)462 rl_vi_eWord (count, ignore)
463      int count, ignore __attribute__((unused));
464 {
465   while (count-- && rl_point < (rl_end - 1))
466     {
467       if (!whitespace (rl_line_buffer[rl_point]))
468 	rl_point++;
469 
470       /* Move to the next non-whitespace character (to the start of the
471 	 next word). */
472       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
473 	rl_point++;
474 
475       if (rl_point && rl_point < rl_end)
476 	{
477 	  /* Skip whitespace. */
478 	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
479 	    rl_point++;
480 
481 	  /* Skip until whitespace. */
482 	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
483 	    rl_point++;
484 
485 	  /* Move back to the last character of the word. */
486 	  rl_point--;
487 	}
488     }
489   return (0);
490 }
491 
492 int
rl_vi_fword(count,ignore)493 rl_vi_fword (count, ignore)
494      int count, ignore __attribute__((unused));
495 {
496   while (count-- && rl_point < (rl_end - 1))
497     {
498       /* Move to white space (really non-identifer). */
499       if (_rl_isident (rl_line_buffer[rl_point]))
500 	{
501 	  while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
502 	    rl_point++;
503 	}
504       else /* if (!whitespace (rl_line_buffer[rl_point])) */
505 	{
506 	  while (!_rl_isident (rl_line_buffer[rl_point]) &&
507 		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
508 	    rl_point++;
509 	}
510 
511       /* Move past whitespace. */
512       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
513 	rl_point++;
514     }
515   return (0);
516 }
517 
518 int
rl_vi_bword(count,ignore)519 rl_vi_bword (count, ignore)
520      int count, ignore __attribute__((unused));
521 {
522   while (count-- && rl_point > 0)
523     {
524       int last_is_ident;
525 
526       /* If we are at the start of a word, move back to whitespace
527 	 so we will go back to the start of the previous word. */
528       if (!whitespace (rl_line_buffer[rl_point]) &&
529 	  whitespace (rl_line_buffer[rl_point - 1]))
530 	rl_point--;
531 
532       /* If this character and the previous character are `opposite', move
533 	 back so we don't get messed up by the rl_point++ down there in
534 	 the while loop.  Without this code, words like `l;' screw up the
535 	 function. */
536       last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
537       if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
538 	  (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
539 	rl_point--;
540 
541       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
542 	rl_point--;
543 
544       if (rl_point > 0)
545 	{
546 	  if (_rl_isident (rl_line_buffer[rl_point]))
547 	    while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
548 	  else
549 	    while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
550 		   !whitespace (rl_line_buffer[rl_point]));
551 	  rl_point++;
552 	}
553     }
554   return (0);
555 }
556 
557 int
rl_vi_eword(count,ignore)558 rl_vi_eword (count, ignore)
559      int count, ignore __attribute__((unused));
560 {
561   while (count-- && rl_point < rl_end - 1)
562     {
563       if (!whitespace (rl_line_buffer[rl_point]))
564 	rl_point++;
565 
566       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
567 	rl_point++;
568 
569       if (rl_point < rl_end)
570 	{
571 	  if (_rl_isident (rl_line_buffer[rl_point]))
572 	    while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
573 	  else
574 	    while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
575 		   && !whitespace (rl_line_buffer[rl_point]));
576 	}
577       rl_point--;
578     }
579   return (0);
580 }
581 
582 int
rl_vi_insert_beg(count,key)583 rl_vi_insert_beg (count, key)
584      int count __attribute__((unused)), key;
585 {
586   rl_beg_of_line (1, key);
587   rl_vi_insertion_mode (1, key);
588   return (0);
589 }
590 
591 static void
_rl_vi_append_forward(key)592 _rl_vi_append_forward (key)
593      int key;
594 {
595   int point;
596 
597   if (rl_point < rl_end)
598     {
599       if (MB_CUR_MAX == 1 || rl_byte_oriented)
600 	rl_point++;
601       else
602         {
603           point = rl_point;
604           rl_forward_char (1, key);
605           if (point == rl_point)
606             rl_point = rl_end;
607         }
608     }
609 }
610 
611 int
rl_vi_append_mode(count,key)612 rl_vi_append_mode (count, key)
613      int count __attribute__((unused)), key;
614 {
615   _rl_vi_append_forward (key);
616   rl_vi_start_inserting (key, 1, rl_arg_sign);
617   return (0);
618 }
619 
620 int
rl_vi_append_eol(count,key)621 rl_vi_append_eol (count, key)
622      int count __attribute__((unused)), key;
623 {
624   rl_end_of_line (1, key);
625   rl_vi_append_mode (1, key);
626   return (0);
627 }
628 
629 /* What to do in the case of C-d. */
630 int
rl_vi_eof_maybe(count,c)631 rl_vi_eof_maybe (count, c)
632      int count __attribute__((unused)), c __attribute__((unused));
633 {
634   return (rl_newline (1, '\n'));
635 }
636 
637 /* Insertion mode stuff. */
638 
639 /* Switching from one mode to the other really just involves
640    switching keymaps. */
641 int
rl_vi_insertion_mode(count,key)642 rl_vi_insertion_mode (count, key)
643      int count __attribute__((unused)), key;
644 {
645   _rl_keymap = vi_insertion_keymap;
646   _rl_vi_last_key_before_insert = key;
647   return (0);
648 }
649 
650 static void
_rl_vi_save_insert(up)651 _rl_vi_save_insert (up)
652       UNDO_LIST *up;
653 {
654   int len, start, end;
655 
656   if (up == 0 || up->what != UNDO_INSERT)
657     {
658       if (vi_insert_buffer_size >= 1)
659 	vi_insert_buffer[0] = '\0';
660       return;
661     }
662 
663   start = up->start;
664   end = up->end;
665   len = end - start + 1;
666   if (len >= vi_insert_buffer_size)
667     {
668       vi_insert_buffer_size += (len + 32) - (len % 32);
669       vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
670     }
671   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
672   vi_insert_buffer[len-1] = '\0';
673 }
674 
675 void
_rl_vi_done_inserting()676 _rl_vi_done_inserting ()
677 {
678   if (_rl_vi_doing_insert)
679     {
680       /* The `C', `s', and `S' commands set this. */
681       rl_end_undo_group ();
682       /* Now, the text between rl_undo_list->next->start and
683 	 rl_undo_list->next->end is what was inserted while in insert
684 	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
685 	 on absolute indices into the line which may change (though they
686 	 probably will not). */
687       _rl_vi_doing_insert = 0;
688       _rl_vi_save_insert (rl_undo_list->next);
689       vi_continued_command = 1;
690     }
691   else
692     {
693       if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list)
694         _rl_vi_save_insert (rl_undo_list);
695       /* XXX - Other keys probably need to be checked. */
696       else if (_rl_vi_last_key_before_insert == 'C')
697 	rl_end_undo_group ();
698       while (_rl_undo_group_level > 0)
699 	rl_end_undo_group ();
700       vi_continued_command = 0;
701     }
702 }
703 
704 int
rl_vi_movement_mode(count,key)705 rl_vi_movement_mode (count, key)
706      int count __attribute__((unused)), key;
707 {
708   if (rl_point > 0)
709     rl_backward_char (1, key);
710 
711   _rl_keymap = vi_movement_keymap;
712   _rl_vi_done_inserting ();
713 
714   /* This is how POSIX.2 says `U' should behave -- everything up until the
715      first time you go into command mode should not be undone. */
716   if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
717     rl_free_undo_list ();
718 
719   RL_SETSTATE (RL_STATE_VICMDONCE);
720   return (0);
721 }
722 
723 int
rl_vi_arg_digit(count,c)724 rl_vi_arg_digit (count, c)
725      int count, c;
726 {
727   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
728     return (rl_beg_of_line (1, c));
729   else
730     return (rl_digit_argument (count, c));
731 }
732 
733 /* Change the case of the next COUNT characters. */
734 #if defined (HANDLE_MULTIBYTE)
735 static int
_rl_vi_change_mbchar_case(count)736 _rl_vi_change_mbchar_case (count)
737      int count;
738 {
739   wchar_t wc;
740   char mb[MB_LEN_MAX+1];
741   int mlen, p;
742   mbstate_t ps;
743 
744   memset (&ps, 0, sizeof (mbstate_t));
745   if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
746     count--;
747   while (count-- && rl_point < rl_end)
748     {
749       mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
750       if (iswupper (wc))
751 	wc = towlower (wc);
752       else if (iswlower (wc))
753 	wc = towupper (wc);
754       else
755 	{
756 	  /* Just skip over chars neither upper nor lower case */
757 	  rl_forward_char (1, 0);
758 	  continue;
759 	}
760 
761       /* Vi is kind of strange here. */
762       if (wc)
763 	{
764 	  p = rl_point;
765 	  mlen = wcrtomb (mb, wc, &ps);
766 	  if (mlen >= 0)
767 	    mb[mlen] = '\0';
768 	  rl_begin_undo_group ();
769 	  rl_vi_delete (1, 0);
770 	  if (rl_point < p)	/* Did we retreat at EOL? */
771 	    rl_point++;	/* XXX - should we advance more than 1 for mbchar? */
772 	  rl_insert_text (mb);
773 	  rl_end_undo_group ();
774 	  rl_vi_check ();
775 	}
776       else
777         rl_forward_char (1, 0);
778     }
779 
780   return 0;
781 }
782 #endif
783 
784 int
rl_vi_change_case(count,ignore)785 rl_vi_change_case (count, ignore)
786      int count, ignore __attribute__((unused));
787 {
788   int c, p;
789 
790   /* Don't try this on an empty line. */
791   if (rl_point >= rl_end)
792     return (0);
793 
794   c = 0;
795 #if defined (HANDLE_MULTIBYTE)
796   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
797     return (_rl_vi_change_mbchar_case (count));
798 #endif
799 
800   while (count-- && rl_point < rl_end)
801     {
802       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
803 	c = _rl_to_lower (rl_line_buffer[rl_point]);
804       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
805 	c = _rl_to_upper (rl_line_buffer[rl_point]);
806       else
807 	{
808 	  /* Just skip over characters neither upper nor lower case. */
809 	  rl_forward_char (1, c);
810 	  continue;
811 	}
812 
813       /* Vi is kind of strange here. */
814       if (c)
815 	{
816 	  p = rl_point;
817 	  rl_begin_undo_group ();
818 	  rl_vi_delete (1, c);
819 	  if (rl_point < p)	/* Did we retreat at EOL? */
820 	    rl_point++;
821 	  _rl_insert_char (1, c);
822 	  rl_end_undo_group ();
823 	  rl_vi_check ();
824         }
825       else
826 	rl_forward_char (1, c);
827     }
828   return (0);
829 }
830 
831 int
rl_vi_put(count,key)832 rl_vi_put (count, key)
833      int count, key;
834 {
835   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
836     rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
837 
838   while (count--)
839     rl_yank (1, key);
840 
841   rl_backward_char (1, key);
842   return (0);
843 }
844 
845 static void
_rl_vi_backup()846 _rl_vi_backup ()
847 {
848   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
849     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
850   else
851     rl_point--;
852 }
853 
854 int
rl_vi_check()855 rl_vi_check ()
856 {
857   if (rl_point && rl_point == rl_end)
858     {
859       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
860 	rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
861       else
862         rl_point--;
863     }
864   return (0);
865 }
866 
867 int
rl_vi_column(count,key)868 rl_vi_column (count, key)
869      int count, key;
870 {
871   if (count > rl_end)
872     rl_end_of_line (1, key);
873   else
874     rl_point = count - 1;
875   return (0);
876 }
877 
878 int
rl_vi_domove(key,nextkey)879 rl_vi_domove (key, nextkey)
880      int key, *nextkey;
881 {
882   int c, save;
883   int old_end;
884 
885   rl_mark = rl_point;
886   RL_SETSTATE(RL_STATE_MOREINPUT);
887   c = rl_read_key ();
888   RL_UNSETSTATE(RL_STATE_MOREINPUT);
889   *nextkey = c;
890 
891   if (!member (c, vi_motion))
892     {
893       if (_rl_digit_p (c))
894 	{
895 	  save = rl_numeric_arg;
896 	  rl_numeric_arg = _rl_digit_value (c);
897 	  rl_explicit_arg = 1;
898 	  RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION);
899 	  rl_digit_loop1 ();
900 	  RL_UNSETSTATE (RL_STATE_VIMOTION);
901 	  rl_numeric_arg *= save;
902 	  RL_SETSTATE(RL_STATE_MOREINPUT);
903 	  c = rl_read_key ();	/* real command */
904 	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
905 	  *nextkey = c;
906 	}
907       else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
908 	{
909 	  rl_mark = rl_end;
910 	  rl_beg_of_line (1, c);
911 	  _rl_vi_last_motion = c;
912 	  return (0);
913 	}
914       else
915 	return (-1);
916     }
917 
918   _rl_vi_last_motion = c;
919 
920   /* Append a blank character temporarily so that the motion routines
921      work right at the end of the line. */
922   old_end = rl_end;
923   rl_line_buffer[rl_end++] = ' ';
924   rl_line_buffer[rl_end] = '\0';
925 
926   _rl_dispatch (c, _rl_keymap);
927 
928   /* Remove the blank that we added. */
929   rl_end = old_end;
930   rl_line_buffer[rl_end] = '\0';
931   if (rl_point > rl_end)
932     rl_point = rl_end;
933 
934   /* No change in position means the command failed. */
935   if (rl_mark == rl_point)
936     return (-1);
937 
938   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
939      word.  If we are not at the end of the line, and we are on a
940      non-whitespace character, move back one (presumably to whitespace). */
941   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
942       !whitespace (rl_line_buffer[rl_point]))
943     rl_point--;
944 
945   /* If cw or cW, back up to the end of a word, so the behaviour of ce
946      or cE is the actual result.  Brute-force, no subtlety. */
947   if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
948     {
949       /* Don't move farther back than where we started. */
950       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
951 	rl_point--;
952 
953       /* Posix.2 says that if cw or cW moves the cursor towards the end of
954 	 the line, the character under the cursor should be deleted. */
955       if (rl_point == rl_mark)
956         rl_point++;
957       else
958 	{
959 	  /* Move past the end of the word so that the kill doesn't
960 	     remove the last letter of the previous word.  Only do this
961 	     if we are not at the end of the line. */
962 	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
963 	    rl_point++;
964 	}
965     }
966 
967   if (rl_mark < rl_point)
968     SWAP (rl_point, rl_mark);
969 
970   return (0);
971 }
972 
973 /* Process C as part of the current numeric argument.  Return -1 if the
974    argument should be aborted, 0 if we should not read any more chars, and
975    1 if we should continue to read chars. */
976 static int
_rl_vi_arg_dispatch(c)977 _rl_vi_arg_dispatch (c)
978      int c;
979 {
980   int key;
981 
982   key = c;
983   if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
984     {
985       rl_numeric_arg *= 4;
986       return 1;
987     }
988 
989   c = UNMETA (c);
990 
991   if (_rl_digit_p (c))
992     {
993       if (rl_explicit_arg)
994 	rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
995       else
996 	rl_numeric_arg = _rl_digit_value (c);
997       rl_explicit_arg = 1;
998       return 1;
999     }
1000   else
1001     {
1002       rl_clear_message ();
1003       rl_stuff_char (key);
1004       return 0;
1005     }
1006 }
1007 
1008 /* A simplified loop for vi. Don't dispatch key at end.
1009    Don't recognize minus sign?
1010    Should this do rl_save_prompt/rl_restore_prompt? */
1011 static int
rl_digit_loop1()1012 rl_digit_loop1 ()
1013 {
1014   int c, r;
1015 
1016   while (1)
1017     {
1018       if (_rl_arg_overflow ())
1019 	return 1;
1020 
1021       c = _rl_arg_getchar ();
1022 
1023       r = _rl_vi_arg_dispatch (c);
1024       if (r <= 0)
1025 	break;
1026     }
1027 
1028   RL_UNSETSTATE(RL_STATE_NUMERICARG);
1029   return (0);
1030 }
1031 
1032 int
rl_vi_delete_to(count,key)1033 rl_vi_delete_to (count, key)
1034      int count __attribute__((unused)), key;
1035 {
1036   int c;
1037 
1038   if (_rl_uppercase_p (key))
1039     rl_stuff_char ('$');
1040   else if (vi_redoing)
1041     rl_stuff_char (_rl_vi_last_motion);
1042 
1043   if (rl_vi_domove (key, &c))
1044     {
1045       rl_ding ();
1046       return -1;
1047     }
1048 
1049   /* These are the motion commands that do not require adjusting the
1050      mark. */
1051   if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
1052     rl_mark++;
1053 
1054   rl_kill_text (rl_point, rl_mark);
1055   return (0);
1056 }
1057 
1058 int
rl_vi_change_to(count,key)1059 rl_vi_change_to (count, key)
1060      int count __attribute__((unused)), key;
1061 {
1062   int c, start_pos;
1063 
1064   if (_rl_uppercase_p (key))
1065     rl_stuff_char ('$');
1066   else if (vi_redoing)
1067     rl_stuff_char (_rl_vi_last_motion);
1068 
1069   start_pos = rl_point;
1070 
1071   if (rl_vi_domove (key, &c))
1072     {
1073       rl_ding ();
1074       return -1;
1075     }
1076 
1077   /* These are the motion commands that do not require adjusting the
1078      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1079      and already leave the mark at the correct location. */
1080   if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
1081     rl_mark++;
1082 
1083   /* The cursor never moves with c[wW]. */
1084   if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
1085     rl_point = start_pos;
1086 
1087   if (vi_redoing)
1088     {
1089       if (vi_insert_buffer && *vi_insert_buffer)
1090 	rl_begin_undo_group ();
1091       rl_delete_text (rl_point, rl_mark);
1092       if (vi_insert_buffer && *vi_insert_buffer)
1093 	{
1094 	  rl_insert_text (vi_insert_buffer);
1095 	  rl_end_undo_group ();
1096 	}
1097     }
1098   else
1099     {
1100       rl_begin_undo_group ();		/* to make the `u' command work */
1101       rl_kill_text (rl_point, rl_mark);
1102       /* `C' does not save the text inserted for undoing or redoing. */
1103       if (_rl_uppercase_p (key) == 0)
1104         _rl_vi_doing_insert = 1;
1105       rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
1106     }
1107 
1108   return (0);
1109 }
1110 
1111 int
rl_vi_yank_to(count,key)1112 rl_vi_yank_to (count, key)
1113      int count __attribute__((unused)), key;
1114 {
1115   int c, save;
1116 
1117   save = rl_point;
1118   if (_rl_uppercase_p (key))
1119     rl_stuff_char ('$');
1120 
1121   if (rl_vi_domove (key, &c))
1122     {
1123       rl_ding ();
1124       return -1;
1125     }
1126 
1127   /* These are the motion commands that do not require adjusting the
1128      mark. */
1129   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
1130     rl_mark++;
1131 
1132   rl_begin_undo_group ();
1133   rl_kill_text (rl_point, rl_mark);
1134   rl_end_undo_group ();
1135   rl_do_undo ();
1136   rl_point = save;
1137 
1138   return (0);
1139 }
1140 
1141 int
rl_vi_rubout(count,key)1142 rl_vi_rubout (count, key)
1143      int count, key;
1144 {
1145   int opoint;
1146 
1147   if (count < 0)
1148     return (rl_vi_delete (-count, key));
1149 
1150   if (rl_point == 0)
1151     {
1152       rl_ding ();
1153       return -1;
1154     }
1155 
1156   opoint = rl_point;
1157   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1158     rl_backward_char (count, key);
1159   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1160     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1161   else
1162     rl_point -= count;
1163 
1164   if (rl_point < 0)
1165     rl_point = 0;
1166 
1167   rl_kill_text (rl_point, opoint);
1168 
1169   return (0);
1170 }
1171 
1172 int
rl_vi_delete(count,key)1173 rl_vi_delete (count, key)
1174      int count, key;
1175 {
1176   int end;
1177 
1178   if (count < 0)
1179     return (rl_vi_rubout (-count, key));
1180 
1181   if (rl_end == 0)
1182     {
1183       rl_ding ();
1184       return -1;
1185     }
1186 
1187   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1188     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1189   else
1190     end = rl_point + count;
1191 
1192   if (end >= rl_end)
1193     end = rl_end;
1194 
1195   rl_kill_text (rl_point, end);
1196 
1197   if (rl_point > 0 && rl_point == rl_end)
1198     rl_backward_char (1, key);
1199 
1200   return (0);
1201 }
1202 
1203 int
rl_vi_back_to_indent(count,key)1204 rl_vi_back_to_indent (count, key)
1205      int count __attribute__((unused)), key;
1206 {
1207   rl_beg_of_line (1, key);
1208   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1209     rl_point++;
1210   return (0);
1211 }
1212 
1213 int
rl_vi_first_print(count,key)1214 rl_vi_first_print (count, key)
1215      int count __attribute__((unused)), key;
1216 {
1217   return (rl_vi_back_to_indent (1, key));
1218 }
1219 
1220 static int _rl_cs_dir, _rl_cs_orig_dir;
1221 
1222 #if defined (READLINE_CALLBACKS)
1223 static int
_rl_vi_callback_char_search(data)1224 _rl_vi_callback_char_search (data)
1225      _rl_callback_generic_arg *data;
1226 {
1227 #if defined (HANDLE_MULTIBYTE)
1228   _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1229 #else
1230   RL_SETSTATE(RL_STATE_MOREINPUT);
1231   _rl_vi_last_search_char = rl_read_key ();
1232   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1233 #endif
1234 
1235   _rl_callback_func = 0;
1236   _rl_want_redisplay = 1;
1237 
1238 #if defined (HANDLE_MULTIBYTE)
1239   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1240 #else
1241   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1242 #endif
1243 }
1244 #endif
1245 
1246 int
rl_vi_char_search(count,key)1247 rl_vi_char_search (count, key)
1248      int count, key;
1249 {
1250 #if defined (HANDLE_MULTIBYTE)
1251   static char *target;
1252   static int tlen;
1253 #else
1254   static char target;
1255 #endif
1256 
1257   if (key == ';' || key == ',')
1258     _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1259   else
1260     {
1261       switch (key)
1262         {
1263         case 't':
1264           _rl_cs_orig_dir = _rl_cs_dir = FTO;
1265           break;
1266 
1267         case 'T':
1268           _rl_cs_orig_dir = _rl_cs_dir = BTO;
1269           break;
1270 
1271         case 'f':
1272           _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1273           break;
1274 
1275         case 'F':
1276           _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1277           break;
1278         }
1279 
1280       if (vi_redoing)
1281 	{
1282 	  /* set target and tlen below */
1283 	}
1284 #if defined (READLINE_CALLBACKS)
1285       else if (RL_ISSTATE (RL_STATE_CALLBACK))
1286         {
1287           _rl_callback_data = _rl_callback_data_alloc (count);
1288           _rl_callback_data->i1 = _rl_cs_dir;
1289           _rl_callback_func = _rl_vi_callback_char_search;
1290           return (0);
1291         }
1292 #endif
1293       else
1294 	{
1295 #if defined (HANDLE_MULTIBYTE)
1296 	  _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1297 #else
1298 	  RL_SETSTATE(RL_STATE_MOREINPUT);
1299 	  _rl_vi_last_search_char = rl_read_key ();
1300 	  RL_UNSETSTATE(RL_STATE_MOREINPUT);
1301 #endif
1302 	}
1303     }
1304 
1305 #if defined (HANDLE_MULTIBYTE)
1306   target = _rl_vi_last_search_mbchar;
1307   tlen = _rl_vi_last_search_mblen;
1308 #else
1309   target = _rl_vi_last_search_char;
1310 #endif
1311 
1312 #if defined (HANDLE_MULTIBYTE)
1313   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1314 #else
1315   return (_rl_char_search_internal (count, _rl_cs_dir, target));
1316 #endif
1317 }
1318 
1319 /* Match brackets */
1320 int
rl_vi_match(ignore,key)1321 rl_vi_match (ignore, key)
1322      int ignore __attribute__((unused)), key;
1323 {
1324   int count = 1, brack, pos, tmp, pre;
1325 
1326   pos = rl_point;
1327   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1328     {
1329       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1330 	{
1331 	  while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1332 	    {
1333 	      pre = rl_point;
1334 	      rl_forward_char (1, key);
1335 	      if (pre == rl_point)
1336 	        break;
1337 	    }
1338 	}
1339       else
1340 	while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1341 		rl_point < rl_end - 1)
1342 	  rl_forward_char (1, key);
1343 
1344       if (brack <= 0)
1345 	{
1346 	  rl_point = pos;
1347 	  rl_ding ();
1348 	  return -1;
1349 	}
1350     }
1351 
1352   pos = rl_point;
1353 
1354   if (brack < 0)
1355     {
1356       while (count)
1357 	{
1358 	  tmp = pos;
1359 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
1360 	    pos--;
1361 	  else
1362 	    {
1363 	      pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1364 	      if (tmp == pos)
1365 	        pos--;
1366 	    }
1367 	  if (pos >= 0)
1368 	    {
1369 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1370 	      if (b == -brack)
1371 		count--;
1372 	      else if (b == brack)
1373 		count++;
1374 	    }
1375 	  else
1376 	    {
1377 	      rl_ding ();
1378 	      return -1;
1379 	    }
1380 	}
1381     }
1382   else
1383     {			/* brack > 0 */
1384       while (count)
1385 	{
1386 	  if (MB_CUR_MAX == 1 || rl_byte_oriented)
1387 	    pos++;
1388 	  else
1389 	    pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1390 
1391 	  if (pos < rl_end)
1392 	    {
1393 	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1394 	      if (b == -brack)
1395 		count--;
1396 	      else if (b == brack)
1397 		count++;
1398 	    }
1399 	  else
1400 	    {
1401 	      rl_ding ();
1402 	      return -1;
1403 	    }
1404 	}
1405     }
1406   rl_point = pos;
1407   return (0);
1408 }
1409 
1410 int
rl_vi_bracktype(c)1411 rl_vi_bracktype (c)
1412      int c;
1413 {
1414   switch (c)
1415     {
1416     case '(': return  1;
1417     case ')': return -1;
1418     case '[': return  2;
1419     case ']': return -2;
1420     case '{': return  3;
1421     case '}': return -3;
1422     default:  return  0;
1423     }
1424 }
1425 
1426 static int
_rl_vi_change_char(count,c,mb)1427 _rl_vi_change_char (count, c, mb)
1428      int count, c;
1429      char *mb __attribute__((unused));
1430 {
1431   int p;
1432 
1433   if (c == '\033' || c == CTRL ('C'))
1434     return -1;
1435 
1436   rl_begin_undo_group ();
1437   while (count-- && rl_point < rl_end)
1438     {
1439       p = rl_point;
1440       rl_vi_delete (1, c);
1441       if (rl_point < p)		/* Did we retreat at EOL? */
1442 	rl_point++;
1443 #if defined (HANDLE_MULTIBYTE)
1444       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1445 	rl_insert_text (mb);
1446       else
1447 #endif
1448 	_rl_insert_char (1, c);
1449     }
1450 
1451   /* The cursor shall be left on the last character changed. */
1452   rl_backward_char (1, c);
1453 
1454   rl_end_undo_group ();
1455 
1456   return (0);
1457 }
1458 
1459 static int
_rl_vi_callback_getchar(mb,mlen)1460 _rl_vi_callback_getchar (mb, mlen)
1461      char *mb __attribute__((unused));
1462      int mlen __attribute__((unused));
1463 {
1464   int c;
1465 
1466   RL_SETSTATE(RL_STATE_MOREINPUT);
1467   c = rl_read_key ();
1468   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1469 
1470 #if defined (HANDLE_MULTIBYTE)
1471   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1472     c = _rl_read_mbstring (c, mb, mlen);
1473 #endif
1474 
1475   return c;
1476 }
1477 
1478 #if defined (READLINE_CALLBACKS)
1479 static int
_rl_vi_callback_change_char(data)1480 _rl_vi_callback_change_char (data)
1481      _rl_callback_generic_arg *data;
1482 {
1483   int c;
1484   char mb[MB_LEN_MAX];
1485 
1486   _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1487 
1488   _rl_callback_func = 0;
1489   _rl_want_redisplay = 1;
1490 
1491   return (_rl_vi_change_char (data->count, c, mb));
1492 }
1493 #endif
1494 
1495 int
rl_vi_change_char(count,key)1496 rl_vi_change_char (count, key)
1497      int count, key __attribute__((unused));
1498 {
1499   int c;
1500   char mb[MB_LEN_MAX];
1501 
1502   if (vi_redoing)
1503     {
1504       c = _rl_vi_last_replacement;
1505       mb[0] = c;
1506       mb[1] = '\0';
1507     }
1508 #if defined (READLINE_CALLBACKS)
1509   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1510     {
1511       _rl_callback_data = _rl_callback_data_alloc (count);
1512       _rl_callback_func = _rl_vi_callback_change_char;
1513       return (0);
1514     }
1515 #endif
1516   else
1517     _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1518 
1519   return (_rl_vi_change_char (count, c, mb));
1520 }
1521 
1522 int
rl_vi_subst(count,key)1523 rl_vi_subst (count, key)
1524      int count, key;
1525 {
1526   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1527   if (vi_redoing == 0)
1528     rl_stuff_char ((key == 'S') ? 'c' : 'l');	/* `S' == `cc', `s' == `cl' */
1529 
1530   return (rl_vi_change_to (count, 'c'));
1531 }
1532 
1533 int
rl_vi_overstrike(count,key)1534 rl_vi_overstrike (count, key)
1535      int count, key;
1536 {
1537   if (_rl_vi_doing_insert == 0)
1538     {
1539       _rl_vi_doing_insert = 1;
1540       rl_begin_undo_group ();
1541     }
1542 
1543   if (count > 0)
1544     {
1545       _rl_overwrite_char (count, key);
1546       vi_replace_count += count;
1547     }
1548 
1549   return (0);
1550 }
1551 
1552 int
rl_vi_overstrike_delete(count,key)1553 rl_vi_overstrike_delete (count, key)
1554      int count, key;
1555 {
1556   int i, s;
1557 
1558   for (i = 0; i < count; i++)
1559     {
1560       if (vi_replace_count == 0)
1561 	{
1562 	  rl_ding ();
1563 	  break;
1564 	}
1565       s = rl_point;
1566 
1567       if (rl_do_undo ())
1568 	vi_replace_count--;
1569 
1570       if (rl_point == s)
1571 	rl_backward_char (1, key);
1572     }
1573 
1574   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1575     {
1576       rl_end_undo_group ();
1577       rl_do_undo ();
1578       _rl_vi_doing_insert = 0;
1579     }
1580   return (0);
1581 }
1582 
1583 int
rl_vi_replace(count,key)1584 rl_vi_replace (count, key)
1585      int count __attribute__((unused)), key __attribute__((unused));
1586 {
1587   int i;
1588 
1589   vi_replace_count = 0;
1590 
1591   if (!vi_replace_map)
1592     {
1593       vi_replace_map = rl_make_bare_keymap ();
1594 
1595       for (i = ' '; i < KEYMAP_SIZE; i++)
1596 	vi_replace_map[i].function = rl_vi_overstrike;
1597 
1598       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1599       vi_replace_map[ESC].function = rl_vi_movement_mode;
1600       vi_replace_map[RETURN].function = rl_newline;
1601       vi_replace_map[NEWLINE].function = rl_newline;
1602 
1603       /* If the normal vi insertion keymap has ^H bound to erase, do the
1604          same here.  Probably should remove the assignment to RUBOUT up
1605          there, but I don't think it will make a difference in real life. */
1606       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1607 	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1608 	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1609 
1610     }
1611   _rl_keymap = vi_replace_map;
1612   return (0);
1613 }
1614 
1615 #if 0
1616 /* Try to complete the word we are standing on or the word that ends with
1617    the previous character.  A space matches everything.  Word delimiters are
1618    space and ;. */
1619 int
1620 rl_vi_possible_completions()
1621 {
1622   int save_pos = rl_point;
1623 
1624   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1625     {
1626       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1627 	     rl_line_buffer[rl_point] != ';')
1628 	rl_point++;
1629     }
1630   else if (rl_line_buffer[rl_point - 1] == ';')
1631     {
1632       rl_ding ();
1633       return (0);
1634     }
1635 
1636   rl_possible_completions ();
1637   rl_point = save_pos;
1638 
1639   return (0);
1640 }
1641 #endif
1642 
1643 /* Functions to save and restore marks. */
1644 static int
_rl_vi_set_mark()1645 _rl_vi_set_mark ()
1646 {
1647   int ch;
1648 
1649   RL_SETSTATE(RL_STATE_MOREINPUT);
1650   ch = rl_read_key ();
1651   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1652 
1653   if (ch < 'a' || ch > 'z')
1654     {
1655       rl_ding ();
1656       return -1;
1657     }
1658   ch -= 'a';
1659   vi_mark_chars[ch] = rl_point;
1660   return 0;
1661 }
1662 
1663 #if defined (READLINE_CALLBACKS)
1664 static int
_rl_vi_callback_set_mark(data)1665 _rl_vi_callback_set_mark (data)
1666      _rl_callback_generic_arg *data __attribute__((unused));
1667 {
1668   _rl_callback_func = 0;
1669   _rl_want_redisplay = 1;
1670 
1671   return (_rl_vi_set_mark ());
1672 }
1673 #endif
1674 
1675 int
rl_vi_set_mark(count,key)1676 rl_vi_set_mark (count, key)
1677      int count __attribute__((unused)), key __attribute__((unused));
1678 {
1679 #if defined (READLINE_CALLBACKS)
1680   if (RL_ISSTATE (RL_STATE_CALLBACK))
1681     {
1682       _rl_callback_data = 0;
1683       _rl_callback_func = _rl_vi_callback_set_mark;
1684       return (0);
1685     }
1686 #endif
1687 
1688   return (_rl_vi_set_mark ());
1689 }
1690 
1691 static int
_rl_vi_goto_mark()1692 _rl_vi_goto_mark ()
1693 {
1694   int ch;
1695 
1696   RL_SETSTATE(RL_STATE_MOREINPUT);
1697   ch = rl_read_key ();
1698   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1699 
1700   if (ch == '`')
1701     {
1702       rl_point = rl_mark;
1703       return 0;
1704     }
1705   else if (ch < 'a' || ch > 'z')
1706     {
1707       rl_ding ();
1708       return -1;
1709     }
1710 
1711   ch -= 'a';
1712   if (vi_mark_chars[ch] == -1)
1713     {
1714       rl_ding ();
1715       return -1;
1716     }
1717   rl_point = vi_mark_chars[ch];
1718   return 0;
1719 }
1720 
1721 #if defined (READLINE_CALLBACKS)
1722 static int
_rl_vi_callback_goto_mark(data)1723 _rl_vi_callback_goto_mark (data)
1724      _rl_callback_generic_arg *data __attribute__((unused));
1725 {
1726   _rl_callback_func = 0;
1727   _rl_want_redisplay = 1;
1728 
1729   return (_rl_vi_goto_mark ());
1730 }
1731 #endif
1732 
1733 int
rl_vi_goto_mark(count,key)1734 rl_vi_goto_mark (count, key)
1735      int count __attribute__((unused)), key __attribute__((unused));
1736 {
1737 #if defined (READLINE_CALLBACKS)
1738   if (RL_ISSTATE (RL_STATE_CALLBACK))
1739     {
1740       _rl_callback_data = 0;
1741       _rl_callback_func = _rl_vi_callback_goto_mark;
1742       return (0);
1743     }
1744 #endif
1745 
1746   return (_rl_vi_goto_mark ());
1747 }
1748 #endif /* VI_MODE */
1749