4408053f0f0977d982a591aaf307b158b72b792f
[platform/upstream/bash.git] / lib / 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 && _rl_vi_last_motion != 'd')     /* `dd' is special */
1238     {
1239       _rl_vimvcxt->motion = _rl_vi_last_motion;
1240       r = rl_domove_motion_callback (_rl_vimvcxt);
1241     }
1242   else if (vi_redoing)          /* handle redoing `dd' here */
1243     {
1244       _rl_vimvcxt->motion = _rl_vi_last_motion;
1245       rl_mark = rl_end;
1246       rl_beg_of_line (1, key);
1247       RL_UNSETSTATE (RL_STATE_VIMOTION);
1248       r = vidomove_dispatch (_rl_vimvcxt);
1249     }
1250 #if defined (READLINE_CALLBACKS)
1251   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1252     {
1253       RL_SETSTATE (RL_STATE_VIMOTION);
1254       return (0);
1255     }
1256 #endif
1257   else
1258     r = rl_vi_domove (key, &c);
1259
1260   if (r < 0)
1261     {
1262       rl_ding ();
1263       r = -1;
1264     }
1265
1266   _rl_mvcxt_dispose (_rl_vimvcxt);
1267   _rl_vimvcxt = 0;
1268
1269   return r;
1270 }
1271
1272 static int
1273 vi_change_dispatch (m)
1274      _rl_vimotion_cxt *m;
1275 {
1276   /* These are the motion commands that do not require adjusting the
1277      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1278      and already leave the mark at the correct location. */
1279   if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1280       (rl_mark < rl_end))
1281     rl_mark++;
1282
1283   /* The cursor never moves with c[wW]. */
1284   if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
1285     rl_point = m->start;
1286
1287   if (vi_redoing)
1288     {
1289       if (vi_insert_buffer && *vi_insert_buffer)
1290         rl_begin_undo_group ();
1291       rl_delete_text (rl_point, rl_mark);
1292       if (vi_insert_buffer && *vi_insert_buffer)
1293         {
1294           rl_insert_text (vi_insert_buffer);
1295           rl_end_undo_group ();
1296         }
1297     }
1298   else
1299     {
1300       rl_begin_undo_group ();           /* to make the `u' command work */
1301       rl_kill_text (rl_point, rl_mark);
1302       /* `C' does not save the text inserted for undoing or redoing. */
1303       if (_rl_uppercase_p (m->key) == 0)
1304         _rl_vi_doing_insert = 1;
1305       /* XXX -- TODO -- use m->numericarg? */
1306       rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
1307     }
1308
1309   return (0);
1310 }
1311
1312 int
1313 rl_vi_change_to (count, key)
1314      int count, key;
1315 {
1316   int c, r;
1317
1318   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
1319   _rl_vimvcxt->start = rl_point;
1320
1321   rl_mark = rl_point;
1322   if (_rl_uppercase_p (key))
1323     {
1324       _rl_vimvcxt->motion = '$';
1325       r = rl_domove_motion_callback (_rl_vimvcxt);
1326     }
1327   else if (vi_redoing && _rl_vi_last_motion != 'c')     /* `cc' is special */
1328     {
1329       _rl_vimvcxt->motion = _rl_vi_last_motion;
1330       r = rl_domove_motion_callback (_rl_vimvcxt);
1331     }
1332   else if (vi_redoing)          /* handle redoing `cc' here */
1333     {
1334       _rl_vimvcxt->motion = _rl_vi_last_motion;
1335       rl_mark = rl_end;
1336       rl_beg_of_line (1, key);
1337       RL_UNSETSTATE (RL_STATE_VIMOTION);
1338       r = vidomove_dispatch (_rl_vimvcxt);
1339     }
1340 #if defined (READLINE_CALLBACKS)
1341   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1342     {
1343       RL_SETSTATE (RL_STATE_VIMOTION);
1344       return (0);
1345     }
1346 #endif
1347   else
1348     r = rl_vi_domove (key, &c);
1349
1350   if (r < 0)
1351     {
1352       rl_ding ();
1353       r = -1;   /* normalize return value */
1354     }
1355
1356   _rl_mvcxt_dispose (_rl_vimvcxt);
1357   _rl_vimvcxt = 0;
1358
1359   return r;
1360 }
1361
1362 static int
1363 vi_yank_dispatch (m)
1364      _rl_vimotion_cxt *m;
1365 {
1366   /* These are the motion commands that do not require adjusting the
1367      mark. */
1368   if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1369       (rl_mark < rl_end))
1370     rl_mark++;
1371
1372   rl_begin_undo_group ();
1373   rl_kill_text (rl_point, rl_mark);
1374   rl_end_undo_group ();
1375   rl_do_undo ();
1376   rl_point = m->start;
1377
1378   return (0);
1379 }
1380
1381 int
1382 rl_vi_yank_to (count, key)
1383      int count, key;
1384 {
1385   int c, r;
1386
1387   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
1388   _rl_vimvcxt->start = rl_point;
1389
1390   rl_mark = rl_point;
1391   if (_rl_uppercase_p (key))
1392     {
1393       _rl_vimvcxt->motion = '$';
1394       r = rl_domove_motion_callback (_rl_vimvcxt);
1395     }
1396   else if (vi_redoing && _rl_vi_last_motion != 'y')     /* `yy' is special */
1397     {
1398       _rl_vimvcxt->motion = _rl_vi_last_motion;
1399       r = rl_domove_motion_callback (_rl_vimvcxt);
1400     }
1401   else if (vi_redoing)                  /* handle redoing `yy' here */
1402     {
1403       _rl_vimvcxt->motion = _rl_vi_last_motion;
1404       rl_mark = rl_end;
1405       rl_beg_of_line (1, key);
1406       RL_UNSETSTATE (RL_STATE_VIMOTION);
1407       r = vidomove_dispatch (_rl_vimvcxt);
1408     }
1409 #if defined (READLINE_CALLBACKS)
1410   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1411     {
1412       RL_SETSTATE (RL_STATE_VIMOTION);
1413       return (0);
1414     }
1415 #endif
1416   else
1417     r = rl_vi_domove (key, &c);
1418
1419   if (r < 0)
1420     {
1421       rl_ding ();
1422       r = -1;
1423     }
1424
1425   _rl_mvcxt_dispose (_rl_vimvcxt);
1426   _rl_vimvcxt = 0;
1427
1428   return r;
1429 }
1430
1431 static int
1432 vidomove_dispatch (m)
1433      _rl_vimotion_cxt *m;
1434 {
1435   int r;
1436
1437   switch (m->op)
1438     {
1439     case VIM_DELETE:
1440       r = vi_delete_dispatch (m);
1441       break;
1442     case VIM_CHANGE:
1443       r = vi_change_dispatch (m);
1444       break;
1445     case VIM_YANK:
1446       r = vi_yank_dispatch (m);
1447       break;
1448     default:
1449       _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
1450       r = 1;
1451       break;
1452     }
1453
1454   RL_UNSETSTATE (RL_STATE_VIMOTION);
1455   return r;
1456 }
1457
1458 int
1459 rl_vi_rubout (count, key)
1460      int count, key;
1461 {
1462   int opoint;
1463
1464   if (count < 0)
1465     return (rl_vi_delete (-count, key));
1466
1467   if (rl_point == 0)
1468     {
1469       rl_ding ();
1470       return -1;
1471     }
1472
1473   opoint = rl_point;
1474   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1475     rl_backward_char (count, key);
1476   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1477     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1478   else
1479     rl_point -= count;
1480
1481   if (rl_point < 0)
1482     rl_point = 0;
1483
1484   rl_kill_text (rl_point, opoint);
1485   
1486   return (0);
1487 }
1488
1489 int
1490 rl_vi_delete (count, key)
1491      int count, key;
1492 {
1493   int end;
1494
1495   if (count < 0)
1496     return (rl_vi_rubout (-count, key));
1497
1498   if (rl_end == 0)
1499     {
1500       rl_ding ();
1501       return -1;
1502     }
1503
1504   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1505     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1506   else
1507     end = rl_point + count;
1508
1509   if (end >= rl_end)
1510     end = rl_end;
1511
1512   rl_kill_text (rl_point, end);
1513   
1514   if (rl_point > 0 && rl_point == rl_end)
1515     rl_backward_char (1, key);
1516
1517   return (0);
1518 }
1519
1520 int
1521 rl_vi_back_to_indent (count, key)
1522      int count, key;
1523 {
1524   rl_beg_of_line (1, key);
1525   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1526     rl_point++;
1527   return (0);
1528 }
1529
1530 int
1531 rl_vi_first_print (count, key)
1532      int count, key;
1533 {
1534   return (rl_vi_back_to_indent (1, key));
1535 }
1536
1537 static int _rl_cs_dir, _rl_cs_orig_dir;
1538
1539 #if defined (READLINE_CALLBACKS)
1540 static int
1541 _rl_vi_callback_char_search (data)
1542      _rl_callback_generic_arg *data;
1543 {
1544   int c;
1545 #if defined (HANDLE_MULTIBYTE)
1546   c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1547 #else
1548   RL_SETSTATE(RL_STATE_MOREINPUT);
1549   c = rl_read_key ();
1550   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1551 #endif
1552
1553   if (c <= 0)
1554     return -1;
1555
1556 #if !defined (HANDLE_MULTIBYTE)
1557   _rl_vi_last_search_char = c;
1558 #endif
1559
1560   _rl_callback_func = 0;
1561   _rl_want_redisplay = 1;
1562
1563 #if defined (HANDLE_MULTIBYTE)
1564   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1565 #else
1566   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1567 #endif  
1568 }
1569 #endif
1570
1571 int
1572 rl_vi_char_search (count, key)
1573      int count, key;
1574 {
1575   int c;
1576 #if defined (HANDLE_MULTIBYTE)
1577   static char *target;
1578   static int tlen;
1579 #else
1580   static char target;
1581 #endif
1582
1583   if (key == ';' || key == ',')
1584     {
1585       if (_rl_cs_orig_dir == 0)
1586         return -1;
1587 #if defined (HANDLE_MULTIBYTE)
1588       if (_rl_vi_last_search_mblen == 0)
1589         return -1;
1590 #else
1591       if (_rl_vi_last_search_char == 0)
1592         return -1;
1593 #endif
1594       _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1595     }
1596   else
1597     {
1598       switch (key)
1599         {
1600         case 't':
1601           _rl_cs_orig_dir = _rl_cs_dir = FTO;
1602           break;
1603
1604         case 'T':
1605           _rl_cs_orig_dir = _rl_cs_dir = BTO;
1606           break;
1607
1608         case 'f':
1609           _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1610           break;
1611
1612         case 'F':
1613           _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1614           break;
1615         }
1616
1617       if (vi_redoing)
1618         {
1619           /* set target and tlen below */
1620         }
1621 #if defined (READLINE_CALLBACKS)
1622       else if (RL_ISSTATE (RL_STATE_CALLBACK))
1623         {
1624           _rl_callback_data = _rl_callback_data_alloc (count);
1625           _rl_callback_data->i1 = _rl_cs_dir;
1626           _rl_callback_func = _rl_vi_callback_char_search;
1627           return (0);
1628         }
1629 #endif
1630       else
1631         {
1632 #if defined (HANDLE_MULTIBYTE)
1633           c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1634           if (c <= 0)
1635             return -1;
1636           _rl_vi_last_search_mblen = c;
1637 #else
1638           RL_SETSTATE(RL_STATE_MOREINPUT);
1639           c = rl_read_key ();
1640           RL_UNSETSTATE(RL_STATE_MOREINPUT);
1641           if (c < 0)
1642             return -1;
1643           _rl_vi_last_search_char = c;
1644 #endif
1645         }
1646     }
1647
1648 #if defined (HANDLE_MULTIBYTE)
1649   target = _rl_vi_last_search_mbchar;
1650   tlen = _rl_vi_last_search_mblen;
1651 #else
1652   target = _rl_vi_last_search_char;
1653 #endif
1654
1655 #if defined (HANDLE_MULTIBYTE)
1656   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1657 #else
1658   return (_rl_char_search_internal (count, _rl_cs_dir, target));
1659 #endif
1660 }
1661
1662 /* Match brackets */
1663 int
1664 rl_vi_match (ignore, key)
1665      int ignore, key;
1666 {
1667   int count = 1, brack, pos, tmp, pre;
1668
1669   pos = rl_point;
1670   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1671     {
1672       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1673         {
1674           while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1675             {
1676               pre = rl_point;
1677               rl_forward_char (1, key);
1678               if (pre == rl_point)
1679                 break;
1680             }
1681         }
1682       else
1683         while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1684                 rl_point < rl_end - 1)
1685           rl_forward_char (1, key);
1686
1687       if (brack <= 0)
1688         {
1689           rl_point = pos;
1690           rl_ding ();
1691           return -1;
1692         }
1693     }
1694
1695   pos = rl_point;
1696
1697   if (brack < 0)
1698     {
1699       while (count)
1700         {
1701           tmp = pos;
1702           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1703             pos--;
1704           else
1705             {
1706               pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1707               if (tmp == pos)
1708                 pos--;
1709             }
1710           if (pos >= 0)
1711             {
1712               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1713               if (b == -brack)
1714                 count--;
1715               else if (b == brack)
1716                 count++;
1717             }
1718           else
1719             {
1720               rl_ding ();
1721               return -1;
1722             }
1723         }
1724     }
1725   else
1726     {                   /* brack > 0 */
1727       while (count)
1728         {
1729           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1730             pos++;
1731           else
1732             pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1733
1734           if (pos < rl_end)
1735             {
1736               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1737               if (b == -brack)
1738                 count--;
1739               else if (b == brack)
1740                 count++;
1741             }
1742           else
1743             {
1744               rl_ding ();
1745               return -1;
1746             }
1747         }
1748     }
1749   rl_point = pos;
1750   return (0);
1751 }
1752
1753 int
1754 rl_vi_bracktype (c)
1755      int c;
1756 {
1757   switch (c)
1758     {
1759     case '(': return  1;
1760     case ')': return -1;
1761     case '[': return  2;
1762     case ']': return -2;
1763     case '{': return  3;
1764     case '}': return -3;
1765     default:  return  0;
1766     }
1767 }
1768
1769 static int
1770 _rl_vi_change_char (count, c, mb)
1771      int count, c;
1772      char *mb;
1773 {
1774   int p;
1775
1776   if (c == '\033' || c == CTRL ('C'))
1777     return -1;
1778
1779   rl_begin_undo_group ();
1780   while (count-- && rl_point < rl_end)
1781     {
1782       p = rl_point;
1783       rl_vi_delete (1, c);
1784       if (rl_point < p)         /* Did we retreat at EOL? */
1785         rl_point++;
1786 #if defined (HANDLE_MULTIBYTE)
1787       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1788         rl_insert_text (mb);
1789       else
1790 #endif
1791         _rl_insert_char (1, c);
1792     }
1793
1794   /* The cursor shall be left on the last character changed. */
1795   rl_backward_char (1, c);
1796
1797   rl_end_undo_group ();
1798
1799   return (0);
1800 }
1801
1802 static int
1803 _rl_vi_callback_getchar (mb, mlen)
1804      char *mb;
1805      int mlen;
1806 {
1807   int c;
1808
1809   RL_SETSTATE(RL_STATE_MOREINPUT);
1810   c = rl_read_key ();
1811   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1812
1813   if (c < 0)
1814     return -1;
1815
1816 #if defined (HANDLE_MULTIBYTE)
1817   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1818     c = _rl_read_mbstring (c, mb, mlen);
1819 #endif
1820
1821   return c;
1822 }
1823
1824 #if defined (READLINE_CALLBACKS)
1825 static int
1826 _rl_vi_callback_change_char (data)
1827      _rl_callback_generic_arg *data;
1828 {
1829   int c;
1830   char mb[MB_LEN_MAX];
1831
1832   _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1833
1834   if (c < 0)
1835     return -1;
1836
1837   _rl_callback_func = 0;
1838   _rl_want_redisplay = 1;
1839
1840   return (_rl_vi_change_char (data->count, c, mb));
1841 }
1842 #endif
1843
1844 int
1845 rl_vi_change_char (count, key)
1846      int count, key;
1847 {
1848   int c;
1849   char mb[MB_LEN_MAX];
1850
1851   if (vi_redoing)
1852     {
1853       c = _rl_vi_last_replacement;
1854       mb[0] = c;
1855       mb[1] = '\0';
1856     }
1857 #if defined (READLINE_CALLBACKS)
1858   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1859     {
1860       _rl_callback_data = _rl_callback_data_alloc (count);
1861       _rl_callback_func = _rl_vi_callback_change_char;
1862       return (0);
1863     }
1864 #endif
1865   else
1866     _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1867
1868   if (c < 0)
1869     return -1;
1870
1871   return (_rl_vi_change_char (count, c, mb));
1872 }
1873
1874 int
1875 rl_vi_subst (count, key)
1876      int count, key;
1877 {
1878   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1879   if (vi_redoing == 0)
1880     rl_stuff_char ((key == 'S') ? 'c' : 'l');   /* `S' == `cc', `s' == `cl' */
1881
1882   return (rl_vi_change_to (count, 'c'));
1883 }
1884
1885 int
1886 rl_vi_overstrike (count, key)
1887      int count, key;
1888 {
1889   if (_rl_vi_doing_insert == 0)
1890     {
1891       _rl_vi_doing_insert = 1;
1892       rl_begin_undo_group ();
1893     }
1894
1895   if (count > 0)
1896     {
1897       _rl_overwrite_char (count, key);
1898       vi_replace_count += count;
1899     }
1900
1901   return (0);
1902 }
1903
1904 int
1905 rl_vi_overstrike_delete (count, key)
1906      int count, key;
1907 {
1908   int i, s;
1909
1910   for (i = 0; i < count; i++)
1911     {
1912       if (vi_replace_count == 0)
1913         {
1914           rl_ding ();
1915           break;
1916         }
1917       s = rl_point;
1918
1919       if (rl_do_undo ())
1920         vi_replace_count--;
1921
1922       if (rl_point == s)
1923         rl_backward_char (1, key);
1924     }
1925
1926   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1927     {
1928       rl_end_undo_group ();
1929       rl_do_undo ();
1930       _rl_vi_doing_insert = 0;
1931     }
1932   return (0);
1933 }
1934
1935 int
1936 rl_vi_replace (count, key)
1937      int count, key;
1938 {
1939   int i;
1940
1941   vi_replace_count = 0;
1942
1943   if (!vi_replace_map)
1944     {
1945       vi_replace_map = rl_make_bare_keymap ();
1946
1947       for (i = ' '; i < KEYMAP_SIZE; i++)
1948         vi_replace_map[i].function = rl_vi_overstrike;
1949
1950       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1951       vi_replace_map[ESC].function = rl_vi_movement_mode;
1952       vi_replace_map[RETURN].function = rl_newline;
1953       vi_replace_map[NEWLINE].function = rl_newline;
1954
1955       /* If the normal vi insertion keymap has ^H bound to erase, do the
1956          same here.  Probably should remove the assignment to RUBOUT up
1957          there, but I don't think it will make a difference in real life. */
1958       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1959           vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1960         vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1961
1962     }
1963   _rl_keymap = vi_replace_map;
1964   return (0);
1965 }
1966
1967 #if 0
1968 /* Try to complete the word we are standing on or the word that ends with
1969    the previous character.  A space matches everything.  Word delimiters are
1970    space and ;. */
1971 int
1972 rl_vi_possible_completions()
1973 {
1974   int save_pos = rl_point;
1975
1976   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1977     {
1978       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1979              rl_line_buffer[rl_point] != ';')
1980         rl_point++;
1981     }
1982   else if (rl_line_buffer[rl_point - 1] == ';')
1983     {
1984       rl_ding ();
1985       return (0);
1986     }
1987
1988   rl_possible_completions ();
1989   rl_point = save_pos;
1990
1991   return (0);
1992 }
1993 #endif
1994
1995 /* Functions to save and restore marks. */
1996 static int
1997 _rl_vi_set_mark ()
1998 {
1999   int ch;
2000
2001   RL_SETSTATE(RL_STATE_MOREINPUT);
2002   ch = rl_read_key ();
2003   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2004
2005   if (ch < 0 || ch < 'a' || ch > 'z')   /* make test against 0 explicit */
2006     {
2007       rl_ding ();
2008       return -1;
2009     }
2010   ch -= 'a';
2011   vi_mark_chars[ch] = rl_point;
2012   return 0;
2013 }
2014
2015 #if defined (READLINE_CALLBACKS)
2016 static int
2017 _rl_vi_callback_set_mark (data)
2018      _rl_callback_generic_arg *data;
2019 {
2020   _rl_callback_func = 0;
2021   _rl_want_redisplay = 1;
2022
2023   return (_rl_vi_set_mark ());
2024 }
2025 #endif
2026
2027 int
2028 rl_vi_set_mark (count, key)
2029      int count, key;
2030 {
2031 #if defined (READLINE_CALLBACKS)
2032   if (RL_ISSTATE (RL_STATE_CALLBACK))
2033     {
2034       _rl_callback_data = 0;
2035       _rl_callback_func = _rl_vi_callback_set_mark;
2036       return (0);
2037     }
2038 #endif
2039
2040   return (_rl_vi_set_mark ());
2041 }
2042
2043 static int
2044 _rl_vi_goto_mark ()
2045 {
2046   int ch;
2047
2048   RL_SETSTATE(RL_STATE_MOREINPUT);
2049   ch = rl_read_key ();
2050   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2051
2052   if (ch == '`')
2053     {
2054       rl_point = rl_mark;
2055       return 0;
2056     }
2057   else if (ch < 0 || ch < 'a' || ch > 'z')      /* make test against 0 explicit */
2058     {
2059       rl_ding ();
2060       return -1;
2061     }
2062
2063   ch -= 'a';
2064   if (vi_mark_chars[ch] == -1)
2065     {
2066       rl_ding ();
2067       return -1;
2068     }
2069   rl_point = vi_mark_chars[ch];
2070   return 0;
2071 }
2072
2073 #if defined (READLINE_CALLBACKS)
2074 static int
2075 _rl_vi_callback_goto_mark (data)
2076      _rl_callback_generic_arg *data;
2077 {
2078   _rl_callback_func = 0;
2079   _rl_want_redisplay = 1;
2080
2081   return (_rl_vi_goto_mark ());
2082 }
2083 #endif
2084
2085 int
2086 rl_vi_goto_mark (count, key)
2087      int count, key;
2088 {
2089 #if defined (READLINE_CALLBACKS)
2090   if (RL_ISSTATE (RL_STATE_CALLBACK))
2091     {
2092       _rl_callback_data = 0;
2093       _rl_callback_func = _rl_vi_callback_goto_mark;
2094       return (0);
2095     }
2096 #endif
2097
2098   return (_rl_vi_goto_mark ());
2099 }
2100 #endif /* VI_MODE */