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