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