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