Revert 415fa612
[external/binutils.git] / readline / vi_mode.c
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 */