MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vi.c
1 /* $NetBSD: vi.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 1992, 1993
5  * The Regents of the University of California. All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <sys/wait.h>
40 
41 #if !defined(lint) && !defined(SCCSID)
42 #if 0
43 static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93";
44 #else
45 #endif
46 #endif /* not lint && not SCCSID */
47 
48 /*
49  * vi.c: Vi mode commands.
50  */
51 #include "el.h"
52 
53 private el_action_t cv_action(EditLine *, Int);
54 private el_action_t cv_paste(EditLine *, Int);
55 
56 /* cv_action():
57  * Handle vi actions.
58  */
59 private el_action_t
60 cv_action(EditLine *el, Int c)
61 {
62 
63  if (el->el_chared.c_vcmd.action != NOP) {
64  /* 'cc', 'dd' and (possibly) friends */
65  if (c != (Int)el->el_chared.c_vcmd.action)
66  return CC_ERROR;
67 
68  if (!(c & YANK))
69  cv_undo(el);
70  cv_yank(el, el->el_line.buffer,
71  (int)(el->el_line.lastchar - el->el_line.buffer));
72  el->el_chared.c_vcmd.action = NOP;
73  el->el_chared.c_vcmd.pos = 0;
74  if (!(c & YANK)) {
75  el->el_line.lastchar = el->el_line.buffer;
76  el->el_line.cursor = el->el_line.buffer;
77  }
78  if (c & INSERT)
79  el->el_map.current = el->el_map.key;
80 
81  return CC_REFRESH;
82  }
83  el->el_chared.c_vcmd.pos = el->el_line.cursor;
84  el->el_chared.c_vcmd.action = c;
85  return CC_ARGHACK;
86 }
87 
88 /* cv_paste():
89  * Paste previous deletion before or after the cursor
90  */
91 private el_action_t
92 cv_paste(EditLine *el, Int c)
93 {
94  c_kill_t *k = &el->el_chared.c_kill;
95  size_t len = (size_t)(k->last - k->buf);
96 
97  if (k->buf == NULL || len == 0)
98  return CC_ERROR;
99 #ifdef DEBUG_PASTE
100  (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf);
101 #endif
102 
103  cv_undo(el);
104 
105  if (!c && el->el_line.cursor < el->el_line.lastchar)
106  el->el_line.cursor++;
107 
108  c_insert(el, (int)len);
109  if (el->el_line.cursor + len > el->el_line.lastchar)
110  return CC_ERROR;
111  (void) memcpy(el->el_line.cursor, k->buf, len *
112  sizeof(*el->el_line.cursor));
113 
114  return CC_REFRESH;
115 }
116 
117 
118 /* vi_paste_next():
119  * Vi paste previous deletion to the right of the cursor
120  * [p]
121  */
122 protected el_action_t
123 /*ARGSUSED*/
124 vi_paste_next(EditLine *el, Int c __attribute__((__unused__)))
125 {
126 
127  return cv_paste(el, 0);
128 }
129 
130 
131 /* vi_paste_prev():
132  * Vi paste previous deletion to the left of the cursor
133  * [P]
134  */
135 protected el_action_t
136 /*ARGSUSED*/
137 vi_paste_prev(EditLine *el, Int c __attribute__((__unused__)))
138 {
139 
140  return cv_paste(el, 1);
141 }
142 
143 
144 /* vi_prev_big_word():
145  * Vi move to the previous space delimited word
146  * [B]
147  */
148 protected el_action_t
149 /*ARGSUSED*/
150 vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__)))
151 {
152 
153  if (el->el_line.cursor == el->el_line.buffer)
154  return CC_ERROR;
155 
156  el->el_line.cursor = cv_prev_word(el->el_line.cursor,
157  el->el_line.buffer,
158  el->el_state.argument,
159  cv__isWord);
160 
161  if (el->el_chared.c_vcmd.action != NOP) {
162  cv_delfini(el);
163  return CC_REFRESH;
164  }
165  return CC_CURSOR;
166 }
167 
168 
169 /* vi_prev_word():
170  * Vi move to the previous word
171  * [b]
172  */
173 protected el_action_t
174 /*ARGSUSED*/
175 vi_prev_word(EditLine *el, Int c __attribute__((__unused__)))
176 {
177 
178  if (el->el_line.cursor == el->el_line.buffer)
179  return CC_ERROR;
180 
181  el->el_line.cursor = cv_prev_word(el->el_line.cursor,
182  el->el_line.buffer,
183  el->el_state.argument,
184  cv__isword);
185 
186  if (el->el_chared.c_vcmd.action != NOP) {
187  cv_delfini(el);
188  return CC_REFRESH;
189  }
190  return CC_CURSOR;
191 }
192 
193 
194 /* vi_next_big_word():
195  * Vi move to the next space delimited word
196  * [W]
197  */
198 protected el_action_t
199 /*ARGSUSED*/
200 vi_next_big_word(EditLine *el, Int c __attribute__((__unused__)))
201 {
202 
203  if (el->el_line.cursor >= el->el_line.lastchar - 1)
204  return CC_ERROR;
205 
206  el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
207  el->el_line.lastchar, el->el_state.argument, cv__isWord);
208 
209  if (el->el_map.type == MAP_VI)
210  if (el->el_chared.c_vcmd.action != NOP) {
211  cv_delfini(el);
212  return CC_REFRESH;
213  }
214  return CC_CURSOR;
215 }
216 
217 
218 /* vi_next_word():
219  * Vi move to the next word
220  * [w]
221  */
222 protected el_action_t
223 /*ARGSUSED*/
224 vi_next_word(EditLine *el, Int c __attribute__((__unused__)))
225 {
226 
227  if (el->el_line.cursor >= el->el_line.lastchar - 1)
228  return CC_ERROR;
229 
230  el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
231  el->el_line.lastchar, el->el_state.argument, cv__isword);
232 
233  if (el->el_map.type == MAP_VI)
234  if (el->el_chared.c_vcmd.action != NOP) {
235  cv_delfini(el);
236  return CC_REFRESH;
237  }
238  return CC_CURSOR;
239 }
240 
241 
242 /* vi_change_case():
243  * Vi change case of character under the cursor and advance one character
244  * [~]
245  */
246 protected el_action_t
247 vi_change_case(EditLine *el, Int c)
248 {
249  int i;
250 
251  if (el->el_line.cursor >= el->el_line.lastchar)
252  return CC_ERROR;
253  cv_undo(el);
254  for (i = 0; i < el->el_state.argument; i++) {
255 
256  c = *el->el_line.cursor;
257  if (Isupper(c))
258  *el->el_line.cursor = Tolower(c);
259  else if (Islower(c))
260  *el->el_line.cursor = Toupper(c);
261 
262  if (++el->el_line.cursor >= el->el_line.lastchar) {
263  el->el_line.cursor--;
264  re_fastaddc(el);
265  break;
266  }
267  re_fastaddc(el);
268  }
269  return CC_NORM;
270 }
271 
272 
273 /* vi_change_meta():
274  * Vi change prefix command
275  * [c]
276  */
277 protected el_action_t
278 /*ARGSUSED*/
279 vi_change_meta(EditLine *el, Int c __attribute__((__unused__)))
280 {
281 
282  /*
283  * Delete with insert == change: first we delete and then we leave in
284  * insert mode.
285  */
286  return cv_action(el, DELETE | INSERT);
287 }
288 
289 
290 /* vi_insert_at_bol():
291  * Vi enter insert mode at the beginning of line
292  * [I]
293  */
294 protected el_action_t
295 /*ARGSUSED*/
296 vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__)))
297 {
298 
299  el->el_line.cursor = el->el_line.buffer;
300  cv_undo(el);
301  el->el_map.current = el->el_map.key;
302  return CC_CURSOR;
303 }
304 
305 
306 /* vi_replace_char():
307  * Vi replace character under the cursor with the next character typed
308  * [r]
309  */
310 protected el_action_t
311 /*ARGSUSED*/
312 vi_replace_char(EditLine *el, Int c __attribute__((__unused__)))
313 {
314 
315  if (el->el_line.cursor >= el->el_line.lastchar)
316  return CC_ERROR;
317 
318  el->el_map.current = el->el_map.key;
319  el->el_state.inputmode = MODE_REPLACE_1;
320  cv_undo(el);
321  return CC_ARGHACK;
322 }
323 
324 
325 /* vi_replace_mode():
326  * Vi enter replace mode
327  * [R]
328  */
329 protected el_action_t
330 /*ARGSUSED*/
331 vi_replace_mode(EditLine *el, Int c __attribute__((__unused__)))
332 {
333 
334  el->el_map.current = el->el_map.key;
335  el->el_state.inputmode = MODE_REPLACE;
336  cv_undo(el);
337  return CC_NORM;
338 }
339 
340 
341 /* vi_substitute_char():
342  * Vi replace character under the cursor and enter insert mode
343  * [s]
344  */
345 protected el_action_t
346 /*ARGSUSED*/
347 vi_substitute_char(EditLine *el, Int c __attribute__((__unused__)))
348 {
349 
350  c_delafter(el, el->el_state.argument);
351  el->el_map.current = el->el_map.key;
352  return CC_REFRESH;
353 }
354 
355 
356 /* vi_substitute_line():
357  * Vi substitute entire line
358  * [S]
359  */
360 protected el_action_t
361 /*ARGSUSED*/
362 vi_substitute_line(EditLine *el, Int c __attribute__((__unused__)))
363 {
364 
365  cv_undo(el);
366  cv_yank(el, el->el_line.buffer,
367  (int)(el->el_line.lastchar - el->el_line.buffer));
368  (void) em_kill_line(el, 0);
369  el->el_map.current = el->el_map.key;
370  return CC_REFRESH;
371 }
372 
373 
374 /* vi_change_to_eol():
375  * Vi change to end of line
376  * [C]
377  */
378 protected el_action_t
379 /*ARGSUSED*/
380 vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__)))
381 {
382 
383  cv_undo(el);
384  cv_yank(el, el->el_line.cursor,
385  (int)(el->el_line.lastchar - el->el_line.cursor));
386  (void) ed_kill_line(el, 0);
387  el->el_map.current = el->el_map.key;
388  return CC_REFRESH;
389 }
390 
391 
392 /* vi_insert():
393  * Vi enter insert mode
394  * [i]
395  */
396 protected el_action_t
397 /*ARGSUSED*/
398 vi_insert(EditLine *el, Int c __attribute__((__unused__)))
399 {
400 
401  el->el_map.current = el->el_map.key;
402  cv_undo(el);
403  return CC_NORM;
404 }
405 
406 
407 /* vi_add():
408  * Vi enter insert mode after the cursor
409  * [a]
410  */
411 protected el_action_t
412 /*ARGSUSED*/
413 vi_add(EditLine *el, Int c __attribute__((__unused__)))
414 {
415  int ret;
416 
417  el->el_map.current = el->el_map.key;
418  if (el->el_line.cursor < el->el_line.lastchar) {
419  el->el_line.cursor++;
420  if (el->el_line.cursor > el->el_line.lastchar)
421  el->el_line.cursor = el->el_line.lastchar;
422  ret = CC_CURSOR;
423  } else
424  ret = CC_NORM;
425 
426  cv_undo(el);
427 
428  return (el_action_t)ret;
429 }
430 
431 
432 /* vi_add_at_eol():
433  * Vi enter insert mode at end of line
434  * [A]
435  */
436 protected el_action_t
437 /*ARGSUSED*/
438 vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__)))
439 {
440 
441  el->el_map.current = el->el_map.key;
442  el->el_line.cursor = el->el_line.lastchar;
443  cv_undo(el);
444  return CC_CURSOR;
445 }
446 
447 
448 /* vi_delete_meta():
449  * Vi delete prefix command
450  * [d]
451  */
452 protected el_action_t
453 /*ARGSUSED*/
454 vi_delete_meta(EditLine *el, Int c __attribute__((__unused__)))
455 {
456 
457  return cv_action(el, DELETE);
458 }
459 
460 
461 /* vi_end_big_word():
462  * Vi move to the end of the current space delimited word
463  * [E]
464  */
465 protected el_action_t
466 /*ARGSUSED*/
467 vi_end_big_word(EditLine *el, Int c __attribute__((__unused__)))
468 {
469 
470  if (el->el_line.cursor == el->el_line.lastchar)
471  return CC_ERROR;
472 
473  el->el_line.cursor = cv__endword(el->el_line.cursor,
474  el->el_line.lastchar, el->el_state.argument, cv__isWord);
475 
476  if (el->el_chared.c_vcmd.action != NOP) {
477  el->el_line.cursor++;
478  cv_delfini(el);
479  return CC_REFRESH;
480  }
481  return CC_CURSOR;
482 }
483 
484 
485 /* vi_end_word():
486  * Vi move to the end of the current word
487  * [e]
488  */
489 protected el_action_t
490 /*ARGSUSED*/
491 vi_end_word(EditLine *el, Int c __attribute__((__unused__)))
492 {
493 
494  if (el->el_line.cursor == el->el_line.lastchar)
495  return CC_ERROR;
496 
497  el->el_line.cursor = cv__endword(el->el_line.cursor,
498  el->el_line.lastchar, el->el_state.argument, cv__isword);
499 
500  if (el->el_chared.c_vcmd.action != NOP) {
501  el->el_line.cursor++;
502  cv_delfini(el);
503  return CC_REFRESH;
504  }
505  return CC_CURSOR;
506 }
507 
508 
509 /* vi_undo():
510  * Vi undo last change
511  * [u]
512  */
513 protected el_action_t
514 /*ARGSUSED*/
515 vi_undo(EditLine *el, Int c __attribute__((__unused__)))
516 {
517  c_undo_t un = el->el_chared.c_undo;
518 
519  if (un.len == -1)
520  return CC_ERROR;
521 
522  /* switch line buffer and undo buffer */
523  el->el_chared.c_undo.buf = el->el_line.buffer;
524  el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
525  el->el_chared.c_undo.cursor =
526  (int)(el->el_line.cursor - el->el_line.buffer);
527  el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
528  el->el_line.buffer = un.buf;
529  el->el_line.cursor = un.buf + un.cursor;
530  el->el_line.lastchar = un.buf + un.len;
531 
532  return CC_REFRESH;
533 }
534 
535 
536 /* vi_command_mode():
537  * Vi enter command mode (use alternative key bindings)
538  * [<ESC>]
539  */
540 protected el_action_t
541 /*ARGSUSED*/
542 vi_command_mode(EditLine *el, Int c __attribute__((__unused__)))
543 {
544 
545  /* [Esc] cancels pending action */
546  el->el_chared.c_vcmd.action = NOP;
547  el->el_chared.c_vcmd.pos = 0;
548 
549  el->el_state.doingarg = 0;
550 
551  el->el_state.inputmode = MODE_INSERT;
552  el->el_map.current = el->el_map.alt;
553 #ifdef VI_MOVE
554  if (el->el_line.cursor > el->el_line.buffer)
555  el->el_line.cursor--;
556 #endif
557  return CC_CURSOR;
558 }
559 
560 
561 /* vi_zero():
562  * Vi move to the beginning of line
563  * [0]
564  */
565 protected el_action_t
566 vi_zero(EditLine *el, Int c)
567 {
568 
569  if (el->el_state.doingarg)
570  return ed_argument_digit(el, c);
571 
572  el->el_line.cursor = el->el_line.buffer;
573  if (el->el_chared.c_vcmd.action != NOP) {
574  cv_delfini(el);
575  return CC_REFRESH;
576  }
577  return CC_CURSOR;
578 }
579 
580 
581 /* vi_delete_prev_char():
582  * Vi move to previous character (backspace)
583  * [^H] in insert mode only
584  */
585 protected el_action_t
586 /*ARGSUSED*/
587 vi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__)))
588 {
589 
590  if (el->el_line.cursor <= el->el_line.buffer)
591  return CC_ERROR;
592 
593  c_delbefore1(el);
594  el->el_line.cursor--;
595  return CC_REFRESH;
596 }
597 
598 
599 /* vi_list_or_eof():
600  * Vi list choices for completion or indicate end of file if empty line
601  * [^D]
602  */
603 protected el_action_t
604 /*ARGSUSED*/
605 vi_list_or_eof(EditLine *el, Int c)
606 {
607 
608  if (el->el_line.cursor == el->el_line.lastchar) {
609  if (el->el_line.cursor == el->el_line.buffer) {
610  terminal_writec(el, c); /* then do a EOF */
611  return CC_EOF;
612  } else {
613  /*
614  * Here we could list completions, but it is an
615  * error right now
616  */
617  terminal_beep(el);
618  return CC_ERROR;
619  }
620  } else {
621 #ifdef notyet
622  re_goto_bottom(el);
623  *el->el_line.lastchar = '\0'; /* just in case */
624  return CC_LIST_CHOICES;
625 #else
626  /*
627  * Just complain for now.
628  */
629  terminal_beep(el);
630  return CC_ERROR;
631 #endif
632  }
633 }
634 
635 
636 /* vi_kill_line_prev():
637  * Vi cut from beginning of line to cursor
638  * [^U]
639  */
640 protected el_action_t
641 /*ARGSUSED*/
642 vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__)))
643 {
644  Char *kp, *cp;
645 
646  cp = el->el_line.buffer;
647  kp = el->el_chared.c_kill.buf;
648  while (cp < el->el_line.cursor)
649  *kp++ = *cp++; /* copy it */
650  el->el_chared.c_kill.last = kp;
651  c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
652  el->el_line.cursor = el->el_line.buffer; /* zap! */
653  return CC_REFRESH;
654 }
655 
656 
657 /* vi_search_prev():
658  * Vi search history previous
659  * [?]
660  */
661 protected el_action_t
662 /*ARGSUSED*/
663 vi_search_prev(EditLine *el, Int c __attribute__((__unused__)))
664 {
665 
666  return cv_search(el, ED_SEARCH_PREV_HISTORY);
667 }
668 
669 
670 /* vi_search_next():
671  * Vi search history next
672  * [/]
673  */
674 protected el_action_t
675 /*ARGSUSED*/
676 vi_search_next(EditLine *el, Int c __attribute__((__unused__)))
677 {
678 
679  return cv_search(el, ED_SEARCH_NEXT_HISTORY);
680 }
681 
682 
683 /* vi_repeat_search_next():
684  * Vi repeat current search in the same search direction
685  * [n]
686  */
687 protected el_action_t
688 /*ARGSUSED*/
689 vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__)))
690 {
691 
692  if (el->el_search.patlen == 0)
693  return CC_ERROR;
694  else
695  return cv_repeat_srch(el, el->el_search.patdir);
696 }
697 
698 
699 /* vi_repeat_search_prev():
700  * Vi repeat current search in the opposite search direction
701  * [N]
702  */
703 /*ARGSUSED*/
704 protected el_action_t
705 vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__)))
706 {
707 
708  if (el->el_search.patlen == 0)
709  return CC_ERROR;
710  else
711  return (cv_repeat_srch(el,
712  el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
713  ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
714 }
715 
716 
717 /* vi_next_char():
718  * Vi move to the character specified next
719  * [f]
720  */
721 protected el_action_t
722 /*ARGSUSED*/
723 vi_next_char(EditLine *el, Int c __attribute__((__unused__)))
724 {
725  return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
726 }
727 
728 
729 /* vi_prev_char():
730  * Vi move to the character specified previous
731  * [F]
732  */
733 protected el_action_t
734 /*ARGSUSED*/
735 vi_prev_char(EditLine *el, Int c __attribute__((__unused__)))
736 {
737  return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
738 }
739 
740 
741 /* vi_to_next_char():
742  * Vi move up to the character specified next
743  * [t]
744  */
745 protected el_action_t
746 /*ARGSUSED*/
747 vi_to_next_char(EditLine *el, Int c __attribute__((__unused__)))
748 {
749  return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
750 }
751 
752 
753 /* vi_to_prev_char():
754  * Vi move up to the character specified previous
755  * [T]
756  */
757 protected el_action_t
758 /*ARGSUSED*/
759 vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__)))
760 {
761  return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
762 }
763 
764 
765 /* vi_repeat_next_char():
766  * Vi repeat current character search in the same search direction
767  * [;]
768  */
769 protected el_action_t
770 /*ARGSUSED*/
771 vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__)))
772 {
773 
774  return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
775  el->el_state.argument, el->el_search.chatflg);
776 }
777 
778 
779 /* vi_repeat_prev_char():
780  * Vi repeat current character search in the opposite search direction
781  * [,]
782  */
783 protected el_action_t
784 /*ARGSUSED*/
785 vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__)))
786 {
787  el_action_t r;
788  int dir = el->el_search.chadir;
789 
790  r = cv_csearch(el, -dir, el->el_search.chacha,
791  el->el_state.argument, el->el_search.chatflg);
792  el->el_search.chadir = dir;
793  return r;
794 }
795 
796 
797 /* vi_match():
798  * Vi go to matching () {} or []
799  * [%]
800  */
801 protected el_action_t
802 /*ARGSUSED*/
803 vi_match(EditLine *el, Int c __attribute__((__unused__)))
804 {
805  const Char match_chars[] = STR("()[]{}");
806  Char *cp;
807  size_t delta, i, count;
808  Char o_ch, c_ch;
809 
810  *el->el_line.lastchar = '\0'; /* just in case */
811 
812  i = Strcspn(el->el_line.cursor, match_chars);
813  o_ch = el->el_line.cursor[i];
814  if (o_ch == 0)
815  return CC_ERROR;
816  delta = (size_t)(Strchr(match_chars, o_ch) - match_chars);
817  c_ch = match_chars[delta ^ 1];
818  count = 1;
819  delta = 1 - (delta & 1) * 2;
820 
821  for (cp = &el->el_line.cursor[i]; count; ) {
822  cp += delta;
823  if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
824  return CC_ERROR;
825  if (*cp == o_ch)
826  count++;
827  else if (*cp == c_ch)
828  count--;
829  }
830 
831  el->el_line.cursor = cp;
832 
833  if (el->el_chared.c_vcmd.action != NOP) {
834  /* NB posix says char under cursor should NOT be deleted
835  for -ve delta - this is different to netbsd vi. */
836  if (delta > 0)
837  el->el_line.cursor++;
838  cv_delfini(el);
839  return CC_REFRESH;
840  }
841  return CC_CURSOR;
842 }
843 
844 /* vi_undo_line():
845  * Vi undo all changes to line
846  * [U]
847  */
848 protected el_action_t
849 /*ARGSUSED*/
850 vi_undo_line(EditLine *el, Int c __attribute__((__unused__)))
851 {
852 
853  cv_undo(el);
854  return hist_get(el);
855 }
856 
857 /* vi_to_column():
858  * Vi go to specified column
859  * [|]
860  * NB netbsd vi goes to screen column 'n', posix says nth character
861  */
862 protected el_action_t
863 /*ARGSUSED*/
864 vi_to_column(EditLine *el, Int c __attribute__((__unused__)))
865 {
866 
867  el->el_line.cursor = el->el_line.buffer;
868  el->el_state.argument--;
869  return ed_next_char(el, 0);
870 }
871 
872 /* vi_yank_end():
873  * Vi yank to end of line
874  * [Y]
875  */
876 protected el_action_t
877 /*ARGSUSED*/
878 vi_yank_end(EditLine *el, Int c __attribute__((__unused__)))
879 {
880 
881  cv_yank(el, el->el_line.cursor,
882  (int)(el->el_line.lastchar - el->el_line.cursor));
883  return CC_REFRESH;
884 }
885 
886 /* vi_yank():
887  * Vi yank
888  * [y]
889  */
890 protected el_action_t
891 /*ARGSUSED*/
892 vi_yank(EditLine *el, Int c __attribute__((__unused__)))
893 {
894 
895  return cv_action(el, YANK);
896 }
897 
898 /* vi_comment_out():
899  * Vi comment out current command
900  * [#]
901  */
902 protected el_action_t
903 /*ARGSUSED*/
904 vi_comment_out(EditLine *el, Int c __attribute__((__unused__)))
905 {
906 
907  el->el_line.cursor = el->el_line.buffer;
908  c_insert(el, 1);
909  *el->el_line.cursor = '#';
910  re_refresh(el);
911  return ed_newline(el, 0);
912 }
913 
914 /* vi_alias():
915  * Vi include shell alias
916  * [@]
917  * NB: posix implies that we should enter insert mode, however
918  * this is against historical precedent...
919  */
920 #if defined(__weak_reference) && !defined(__FreeBSD__)
921 __weakref_visible char *my_get_alias_text(const char *)
922  __weak_reference(get_alias_text);
923 #endif
924 protected el_action_t
925 /*ARGSUSED*/
926 vi_alias(EditLine *el __attribute__((__unused__)),
927  Int c __attribute__((__unused__)))
928 {
929 #if defined(__weak_reference) && !defined(__FreeBSD__)
930  char alias_name[3];
931  char *alias_text;
932 
933  if (my_get_alias_text == 0) {
934  return CC_ERROR;
935  }
936 
937  alias_name[0] = '_';
938  alias_name[2] = 0;
939  if (el_getc(el, &alias_name[1]) != 1)
940  return CC_ERROR;
941 
942  alias_text = my_get_alias_text(alias_name);
943  if (alias_text != NULL)
944  FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch));
945  return CC_NORM;
946 #else
947  return CC_ERROR;
948 #endif
949 }
950 
951 /* vi_to_history_line():
952  * Vi go to specified history file line.
953  * [G]
954  */
955 protected el_action_t
956 /*ARGSUSED*/
957 vi_to_history_line(EditLine *el, Int c __attribute__((__unused__)))
958 {
959  int sv_event_no = el->el_history.eventno;
960  el_action_t rval;
961 
962 
963  if (el->el_history.eventno == 0) {
964  (void) Strncpy(el->el_history.buf, el->el_line.buffer,
965  EL_BUFSIZ);
966  el->el_history.last = el->el_history.buf +
967  (el->el_line.lastchar - el->el_line.buffer);
968  }
969 
970  /* Lack of a 'count' means oldest, not 1 */
971  if (!el->el_state.doingarg) {
972  el->el_history.eventno = 0x7fffffff;
973  hist_get(el);
974  } else {
975  /* This is brain dead, all the rest of this code counts
976  * upwards going into the past. Here we need count in the
977  * other direction (to match the output of fc -l).
978  * I could change the world, but this seems to suffice.
979  */
980  el->el_history.eventno = 1;
981  if (hist_get(el) == CC_ERROR)
982  return CC_ERROR;
983  el->el_history.eventno = 1 + el->el_history.ev.num
984  - el->el_state.argument;
985  if (el->el_history.eventno < 0) {
986  el->el_history.eventno = sv_event_no;
987  return CC_ERROR;
988  }
989  }
990  rval = hist_get(el);
991  if (rval == CC_ERROR)
992  el->el_history.eventno = sv_event_no;
993  return rval;
994 }
995 
996 /* vi_histedit():
997  * Vi edit history line with vi
998  * [v]
999  */
1000 protected el_action_t
1001 /*ARGSUSED*/
1002 vi_histedit(EditLine *el, Int c __attribute__((__unused__)))
1003 {
1004  int fd;
1005  pid_t pid;
1006  ssize_t st;
1007  int status;
1008  char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
1009  char *cp;
1010  size_t len;
1011  Char *line;
1012  mbstate_t state;
1013 
1014  memset(&state, 0, sizeof(mbstate_t));
1015  if (el->el_state.doingarg) {
1016  if (vi_to_history_line(el, 0) == CC_ERROR)
1017  return CC_ERROR;
1018  }
1019 
1020  fd = mkstemp(tempfile);
1021  if (fd < 0)
1022  return CC_ERROR;
1023  len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
1024 #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
1025  cp = el_malloc(TMP_BUFSIZ * sizeof(*cp));
1026  if (cp == NULL) {
1027  unlink(tempfile);
1028  close(fd);
1029  return CC_ERROR;
1030  }
1031  /* XXXMYSQL: Make static analyzer happy */
1032  line = el_malloc((len+1) * sizeof(*line));
1033  if (line == NULL) {
1034  el_free(cp);
1035  return CC_ERROR;
1036  }
1037  Strncpy(line, el->el_line.buffer, len);
1038  line[len] = '\0';
1039  wcsrtombs(cp, (const wchar_t **) &line, TMP_BUFSIZ - 1, &state);
1040  cp[TMP_BUFSIZ - 1] = '\0';
1041  len = strlen(cp);
1042  if (write(fd, cp, len) == -1)
1043  goto error;
1044  if (write(fd, "\n", (size_t)1) == -1)
1045  goto error;
1046  pid = fork();
1047  switch (pid) {
1048  case -1:
1049  close(fd);
1050  unlink(tempfile);
1051  el_free(cp);
1052  el_free(line);
1053  return CC_ERROR;
1054  case 0:
1055  close(fd);
1056  execlp("vi", "vi", tempfile, (char *)NULL);
1057  exit(0);
1058  /*NOTREACHED*/
1059  default:
1060  while (waitpid(pid, &status, 0) != pid)
1061  continue;
1062  lseek(fd, (off_t)0, SEEK_SET);
1063  st = read(fd, cp, TMP_BUFSIZ);
1064  if (st > 0) {
1065  len = (size_t)(el->el_line.lastchar -
1066  el->el_line.buffer);
1067  memset(&state, 0, sizeof(mbstate_t));
1068  len = mbsrtowcs(el->el_line.buffer,
1069  (const char**) &cp, len, &state);
1070  if (len > 0 && el->el_line.buffer[len -1] == '\n')
1071  --len;
1072  }
1073  else
1074  len = 0;
1075  el->el_line.cursor = el->el_line.buffer;
1076  el->el_line.lastchar = el->el_line.buffer + len;
1077  el_free(cp);
1078  el_free(line);
1079  break;
1080  }
1081 
1082  close(fd);
1083  unlink(tempfile);
1084  /* return CC_REFRESH; */
1085  return ed_newline(el, 0);
1086 
1087 /* XXXMYSQL: Avoid compiler warnings. */
1088 error:
1089  close(fd);
1090  unlink(tempfile);
1091  return CC_ERROR;
1092 }
1093 
1094 /* vi_history_word():
1095  * Vi append word from previous input line
1096  * [_]
1097  * Who knows where this one came from!
1098  * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
1099  */
1100 protected el_action_t
1101 /*ARGSUSED*/
1102 vi_history_word(EditLine *el, Int c __attribute__((__unused__)))
1103 {
1104  const Char *wp = HIST_FIRST(el);
1105  const Char *wep, *wsp;
1106  int len;
1107  Char *cp;
1108  const Char *lim;
1109 
1110  if (wp == NULL)
1111  return CC_ERROR;
1112 
1113  wep = wsp = 0;
1114  do {
1115  while (Isspace(*wp))
1116  wp++;
1117  if (*wp == 0)
1118  break;
1119  wsp = wp;
1120  while (*wp && !Isspace(*wp))
1121  wp++;
1122  wep = wp;
1123  } while ((!el->el_state.doingarg || --el->el_state.argument > 0)
1124  && *wp != 0);
1125 
1126  if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0))
1127  return CC_ERROR;
1128 
1129  cv_undo(el);
1130  len = (int)(wep - wsp);
1131  if (el->el_line.cursor < el->el_line.lastchar)
1132  el->el_line.cursor++;
1133  c_insert(el, len + 1);
1134  cp = el->el_line.cursor;
1135  lim = el->el_line.limit;
1136  if (cp < lim)
1137  *cp++ = ' ';
1138  while (wsp < wep && cp < lim)
1139  *cp++ = *wsp++;
1140  el->el_line.cursor = cp;
1141 
1142  el->el_map.current = el->el_map.key;
1143  return CC_REFRESH;
1144 }
1145 
1146 /* vi_redo():
1147  * Vi redo last non-motion command
1148  * [.]
1149  */
1150 protected el_action_t
1151 /*ARGSUSED*/
1152 vi_redo(EditLine *el, Int c __attribute__((__unused__)))
1153 {
1154  c_redo_t *r = &el->el_chared.c_redo;
1155 
1156  if (!el->el_state.doingarg && r->count) {
1157  el->el_state.doingarg = 1;
1158  el->el_state.argument = r->count;
1159  }
1160 
1161  el->el_chared.c_vcmd.pos = el->el_line.cursor;
1162  el->el_chared.c_vcmd.action = r->action;
1163  if (r->pos != r->buf) {
1164  if (r->pos + 1 > r->lim)
1165  /* sanity */
1166  r->pos = r->lim - 1;
1167  r->pos[0] = 0;
1168  FUN(el,push)(el, r->buf);
1169  }
1170 
1171  el->el_state.thiscmd = r->cmd;
1172  el->el_state.thisch = r->ch;
1173  return (*el->el_map.func[r->cmd])(el, r->ch);
1174 }