xref: /freebsd-12.1/lib/libedit/common.c (revision bb487d2b)
1 /*	$NetBSD: common.c,v 1.39 2016/02/24 14:25:38 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 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: common.c,v 1.39 2016/02/24 14:25:38 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45 
46 /*
47  * common.c: Common Editor functions
48  */
49 #include <ctype.h>
50 #include <string.h>
51 
52 #include "el.h"
53 #include "common.h"
54 #include "parse.h"
55 #include "vi.h"
56 
57 /* ed_end_of_file():
58  *	Indicate end of file
59  *	[^D]
60  */
61 protected el_action_t
62 /*ARGSUSED*/
63 ed_end_of_file(EditLine *el, wint_t c __attribute__((__unused__)))
64 {
65 
66 	re_goto_bottom(el);
67 	*el->el_line.lastchar = '\0';
68 	return CC_EOF;
69 }
70 
71 
72 /* ed_insert():
73  *	Add character to the line
74  *	Insert a character [bound to all insert keys]
75  */
76 protected el_action_t
77 ed_insert(EditLine *el, wint_t c)
78 {
79 	int count = el->el_state.argument;
80 
81 	if (c == '\0')
82 		return CC_ERROR;
83 
84 	if (el->el_line.lastchar + el->el_state.argument >=
85 	    el->el_line.limit) {
86 		/* end of buffer space, try to allocate more */
87 		if (!ch_enlargebufs(el, (size_t) count))
88 			return CC_ERROR;	/* error allocating more */
89 	}
90 
91 	if (count == 1) {
92 		if (el->el_state.inputmode == MODE_INSERT
93 		    || el->el_line.cursor >= el->el_line.lastchar)
94 			c_insert(el, 1);
95 
96 		*el->el_line.cursor++ = (Char)c;
97 		re_fastaddc(el);		/* fast refresh for one char. */
98 	} else {
99 		if (el->el_state.inputmode != MODE_REPLACE_1)
100 			c_insert(el, el->el_state.argument);
101 
102 		while (count-- && el->el_line.cursor < el->el_line.lastchar)
103 			*el->el_line.cursor++ = (Char)c;
104 		re_refresh(el);
105 	}
106 
107 	if (el->el_state.inputmode == MODE_REPLACE_1)
108 		return vi_command_mode(el, 0);
109 
110 	return CC_NORM;
111 }
112 
113 
114 /* ed_delete_prev_word():
115  *	Delete from beginning of current word to cursor
116  *	[M-^?] [^W]
117  */
118 protected el_action_t
119 /*ARGSUSED*/
120 ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
121 {
122 	Char *cp, *p, *kp;
123 
124 	if (el->el_line.cursor == el->el_line.buffer)
125 		return CC_ERROR;
126 
127 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
128 	    el->el_state.argument, ce__isword);
129 
130 	for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
131 		*kp++ = *p;
132 	el->el_chared.c_kill.last = kp;
133 
134 	c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */
135 	el->el_line.cursor = cp;
136 	if (el->el_line.cursor < el->el_line.buffer)
137 		el->el_line.cursor = el->el_line.buffer; /* bounds check */
138 	return CC_REFRESH;
139 }
140 
141 
142 /* ed_delete_next_char():
143  *	Delete character under cursor
144  *	[^D] [x]
145  */
146 protected el_action_t
147 /*ARGSUSED*/
148 ed_delete_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
149 {
150 #ifdef DEBUG_EDIT
151 #define	EL	el->el_line
152 	(void) fprintf(el->el_errlfile,
153 	    "\nD(b: %x(%s)  c: %x(%s) last: %x(%s) limit: %x(%s)\n",
154 	    EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
155 	    EL.lastchar, EL.limit, EL.limit);
156 #endif
157 	if (el->el_line.cursor == el->el_line.lastchar) {
158 			/* if I'm at the end */
159 		if (el->el_map.type == MAP_VI) {
160 			if (el->el_line.cursor == el->el_line.buffer) {
161 				/* if I'm also at the beginning */
162 #ifdef KSHVI
163 				return CC_ERROR;
164 #else
165 				/* then do an EOF */
166 				terminal_writec(el, c);
167 				return CC_EOF;
168 #endif
169 			} else {
170 #ifdef KSHVI
171 				el->el_line.cursor--;
172 #else
173 				return CC_ERROR;
174 #endif
175 			}
176 		} else
177 				return CC_ERROR;
178 	}
179 	c_delafter(el, el->el_state.argument);	/* delete after dot */
180 	if (el->el_map.type == MAP_VI &&
181 	    el->el_line.cursor >= el->el_line.lastchar &&
182 	    el->el_line.cursor > el->el_line.buffer)
183 			/* bounds check */
184 		el->el_line.cursor = el->el_line.lastchar - 1;
185 	return CC_REFRESH;
186 }
187 
188 
189 /* ed_kill_line():
190  *	Cut to the end of line
191  *	[^K] [^K]
192  */
193 protected el_action_t
194 /*ARGSUSED*/
195 ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
196 {
197 	Char *kp, *cp;
198 
199 	cp = el->el_line.cursor;
200 	kp = el->el_chared.c_kill.buf;
201 	while (cp < el->el_line.lastchar)
202 		*kp++ = *cp++;	/* copy it */
203 	el->el_chared.c_kill.last = kp;
204 			/* zap! -- delete to end */
205 	el->el_line.lastchar = el->el_line.cursor;
206 	return CC_REFRESH;
207 }
208 
209 
210 /* ed_move_to_end():
211  *	Move cursor to the end of line
212  *	[^E] [^E]
213  */
214 protected el_action_t
215 /*ARGSUSED*/
216 ed_move_to_end(EditLine *el, wint_t c __attribute__((__unused__)))
217 {
218 
219 	el->el_line.cursor = el->el_line.lastchar;
220 	if (el->el_map.type == MAP_VI) {
221 		if (el->el_chared.c_vcmd.action != NOP) {
222 			cv_delfini(el);
223 			return CC_REFRESH;
224 		}
225 #ifdef VI_MOVE
226 		el->el_line.cursor--;
227 #endif
228 	}
229 	return CC_CURSOR;
230 }
231 
232 
233 /* ed_move_to_beg():
234  *	Move cursor to the beginning of line
235  *	[^A] [^A]
236  */
237 protected el_action_t
238 /*ARGSUSED*/
239 ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
240 {
241 
242 	el->el_line.cursor = el->el_line.buffer;
243 
244 	if (el->el_map.type == MAP_VI) {
245 			/* We want FIRST non space character */
246 		while (Isspace(*el->el_line.cursor))
247 			el->el_line.cursor++;
248 		if (el->el_chared.c_vcmd.action != NOP) {
249 			cv_delfini(el);
250 			return CC_REFRESH;
251 		}
252 	}
253 	return CC_CURSOR;
254 }
255 
256 
257 /* ed_transpose_chars():
258  *	Exchange the character to the left of the cursor with the one under it
259  *	[^T] [^T]
260  */
261 protected el_action_t
262 ed_transpose_chars(EditLine *el, wint_t c)
263 {
264 
265 	if (el->el_line.cursor < el->el_line.lastchar) {
266 		if (el->el_line.lastchar <= &el->el_line.buffer[1])
267 			return CC_ERROR;
268 		else
269 			el->el_line.cursor++;
270 	}
271 	if (el->el_line.cursor > &el->el_line.buffer[1]) {
272 		/* must have at least two chars entered */
273 		c = el->el_line.cursor[-2];
274 		el->el_line.cursor[-2] = el->el_line.cursor[-1];
275 		el->el_line.cursor[-1] = (Char)c;
276 		return CC_REFRESH;
277 	} else
278 		return CC_ERROR;
279 }
280 
281 
282 /* ed_next_char():
283  *	Move to the right one character
284  *	[^F] [^F]
285  */
286 protected el_action_t
287 /*ARGSUSED*/
288 ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
289 {
290 	Char *lim = el->el_line.lastchar;
291 
292 	if (el->el_line.cursor >= lim ||
293 	    (el->el_line.cursor == lim - 1 &&
294 	    el->el_map.type == MAP_VI &&
295 	    el->el_chared.c_vcmd.action == NOP))
296 		return CC_ERROR;
297 
298 	el->el_line.cursor += el->el_state.argument;
299 	if (el->el_line.cursor > lim)
300 		el->el_line.cursor = lim;
301 
302 	if (el->el_map.type == MAP_VI)
303 		if (el->el_chared.c_vcmd.action != NOP) {
304 			cv_delfini(el);
305 			return CC_REFRESH;
306 		}
307 	return CC_CURSOR;
308 }
309 
310 
311 /* ed_prev_word():
312  *	Move to the beginning of the current word
313  *	[M-b] [b]
314  */
315 protected el_action_t
316 /*ARGSUSED*/
317 ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
318 {
319 
320 	if (el->el_line.cursor == el->el_line.buffer)
321 		return CC_ERROR;
322 
323 	el->el_line.cursor = c__prev_word(el->el_line.cursor,
324 	    el->el_line.buffer,
325 	    el->el_state.argument,
326 	    ce__isword);
327 
328 	if (el->el_map.type == MAP_VI)
329 		if (el->el_chared.c_vcmd.action != NOP) {
330 			cv_delfini(el);
331 			return CC_REFRESH;
332 		}
333 	return CC_CURSOR;
334 }
335 
336 
337 /* ed_prev_char():
338  *	Move to the left one character
339  *	[^B] [^B]
340  */
341 protected el_action_t
342 /*ARGSUSED*/
343 ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
344 {
345 
346 	if (el->el_line.cursor > el->el_line.buffer) {
347 		el->el_line.cursor -= el->el_state.argument;
348 		if (el->el_line.cursor < el->el_line.buffer)
349 			el->el_line.cursor = el->el_line.buffer;
350 
351 		if (el->el_map.type == MAP_VI)
352 			if (el->el_chared.c_vcmd.action != NOP) {
353 				cv_delfini(el);
354 				return CC_REFRESH;
355 			}
356 		return CC_CURSOR;
357 	} else
358 		return CC_ERROR;
359 }
360 
361 
362 /* ed_quoted_insert():
363  *	Add the next character typed verbatim
364  *	[^V] [^V]
365  */
366 protected el_action_t
367 ed_quoted_insert(EditLine *el, wint_t c)
368 {
369 	int num;
370 
371 	tty_quotemode(el);
372 	num = el_wgetc(el, &c);
373 	tty_noquotemode(el);
374 	if (num == 1)
375 		return ed_insert(el, c);
376 	else
377 		return ed_end_of_file(el, 0);
378 }
379 
380 
381 /* ed_digit():
382  *	Adds to argument or enters a digit
383  */
384 protected el_action_t
385 ed_digit(EditLine *el, wint_t c)
386 {
387 
388 	if (!Isdigit(c))
389 		return CC_ERROR;
390 
391 	if (el->el_state.doingarg) {
392 			/* if doing an arg, add this in... */
393 		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
394 			el->el_state.argument = c - '0';
395 		else {
396 			if (el->el_state.argument > 1000000)
397 				return CC_ERROR;
398 			el->el_state.argument =
399 			    (el->el_state.argument * 10) + (c - '0');
400 		}
401 		return CC_ARGHACK;
402 	}
403 
404 	return ed_insert(el, c);
405 }
406 
407 
408 /* ed_argument_digit():
409  *	Digit that starts argument
410  *	For ESC-n
411  */
412 protected el_action_t
413 ed_argument_digit(EditLine *el, wint_t c)
414 {
415 
416 	if (!Isdigit(c))
417 		return CC_ERROR;
418 
419 	if (el->el_state.doingarg) {
420 		if (el->el_state.argument > 1000000)
421 			return CC_ERROR;
422 		el->el_state.argument = (el->el_state.argument * 10) +
423 		    (c - '0');
424 	} else {		/* else starting an argument */
425 		el->el_state.argument = c - '0';
426 		el->el_state.doingarg = 1;
427 	}
428 	return CC_ARGHACK;
429 }
430 
431 
432 /* ed_unassigned():
433  *	Indicates unbound character
434  *	Bound to keys that are not assigned
435  */
436 protected el_action_t
437 /*ARGSUSED*/
438 ed_unassigned(EditLine *el __attribute__((__unused__)),
439     wint_t c __attribute__((__unused__)))
440 {
441 
442 	return CC_ERROR;
443 }
444 
445 
446 /**
447  ** TTY key handling.
448  **/
449 
450 /* ed_tty_sigint():
451  *	Tty interrupt character
452  *	[^C]
453  */
454 protected el_action_t
455 /*ARGSUSED*/
456 ed_tty_sigint(EditLine *el __attribute__((__unused__)),
457 	      wint_t c __attribute__((__unused__)))
458 {
459 
460 	return CC_NORM;
461 }
462 
463 
464 /* ed_tty_dsusp():
465  *	Tty delayed suspend character
466  *	[^Y]
467  */
468 protected el_action_t
469 /*ARGSUSED*/
470 ed_tty_dsusp(EditLine *el __attribute__((__unused__)),
471 	     wint_t c __attribute__((__unused__)))
472 {
473 
474 	return CC_NORM;
475 }
476 
477 
478 /* ed_tty_flush_output():
479  *	Tty flush output characters
480  *	[^O]
481  */
482 protected el_action_t
483 /*ARGSUSED*/
484 ed_tty_flush_output(EditLine *el __attribute__((__unused__)),
485 		    wint_t c __attribute__((__unused__)))
486 {
487 
488 	return CC_NORM;
489 }
490 
491 
492 /* ed_tty_sigquit():
493  *	Tty quit character
494  *	[^\]
495  */
496 protected el_action_t
497 /*ARGSUSED*/
498 ed_tty_sigquit(EditLine *el __attribute__((__unused__)),
499 	       wint_t c __attribute__((__unused__)))
500 {
501 
502 	return CC_NORM;
503 }
504 
505 
506 /* ed_tty_sigtstp():
507  *	Tty suspend character
508  *	[^Z]
509  */
510 protected el_action_t
511 /*ARGSUSED*/
512 ed_tty_sigtstp(EditLine *el __attribute__((__unused__)),
513 	       wint_t c __attribute__((__unused__)))
514 {
515 
516 	return CC_NORM;
517 }
518 
519 
520 /* ed_tty_stop_output():
521  *	Tty disallow output characters
522  *	[^S]
523  */
524 protected el_action_t
525 /*ARGSUSED*/
526 ed_tty_stop_output(EditLine *el __attribute__((__unused__)),
527 		   wint_t c __attribute__((__unused__)))
528 {
529 
530 	return CC_NORM;
531 }
532 
533 
534 /* ed_tty_start_output():
535  *	Tty allow output characters
536  *	[^Q]
537  */
538 protected el_action_t
539 /*ARGSUSED*/
540 ed_tty_start_output(EditLine *el __attribute__((__unused__)),
541 		    wint_t c __attribute__((__unused__)))
542 {
543 
544 	return CC_NORM;
545 }
546 
547 
548 /* ed_newline():
549  *	Execute command
550  *	[^J]
551  */
552 protected el_action_t
553 /*ARGSUSED*/
554 ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
555 {
556 
557 	re_goto_bottom(el);
558 	*el->el_line.lastchar++ = '\n';
559 	*el->el_line.lastchar = '\0';
560 	return CC_NEWLINE;
561 }
562 
563 
564 /* ed_delete_prev_char():
565  *	Delete the character to the left of the cursor
566  *	[^?]
567  */
568 protected el_action_t
569 /*ARGSUSED*/
570 ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
571 {
572 
573 	if (el->el_line.cursor <= el->el_line.buffer)
574 		return CC_ERROR;
575 
576 	c_delbefore(el, el->el_state.argument);
577 	el->el_line.cursor -= el->el_state.argument;
578 	if (el->el_line.cursor < el->el_line.buffer)
579 		el->el_line.cursor = el->el_line.buffer;
580 	return CC_REFRESH;
581 }
582 
583 
584 /* ed_clear_screen():
585  *	Clear screen leaving current line at the top
586  *	[^L]
587  */
588 protected el_action_t
589 /*ARGSUSED*/
590 ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
591 {
592 
593 	terminal_clear_screen(el);	/* clear the whole real screen */
594 	re_clear_display(el);	/* reset everything */
595 	return CC_REFRESH;
596 }
597 
598 
599 /* ed_redisplay():
600  *	Redisplay everything
601  *	^R
602  */
603 protected el_action_t
604 /*ARGSUSED*/
605 ed_redisplay(EditLine *el __attribute__((__unused__)),
606 	     wint_t c __attribute__((__unused__)))
607 {
608 
609 	return CC_REDISPLAY;
610 }
611 
612 
613 /* ed_start_over():
614  *	Erase current line and start from scratch
615  *	[^G]
616  */
617 protected el_action_t
618 /*ARGSUSED*/
619 ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
620 {
621 
622 	ch_reset(el, 0);
623 	return CC_REFRESH;
624 }
625 
626 
627 /* ed_sequence_lead_in():
628  *	First character in a bound sequence
629  *	Placeholder for external keys
630  */
631 protected el_action_t
632 /*ARGSUSED*/
633 ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
634 		    wint_t c __attribute__((__unused__)))
635 {
636 
637 	return CC_NORM;
638 }
639 
640 
641 /* ed_prev_history():
642  *	Move to the previous history line
643  *	[^P] [k]
644  */
645 protected el_action_t
646 /*ARGSUSED*/
647 ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
648 {
649 	char beep = 0;
650 	int sv_event = el->el_history.eventno;
651 
652 	el->el_chared.c_undo.len = -1;
653 	*el->el_line.lastchar = '\0';		/* just in case */
654 
655 	if (el->el_history.eventno == 0) {	/* save the current buffer
656 						 * away */
657 		(void) Strncpy(el->el_history.buf, el->el_line.buffer,
658 		    EL_BUFSIZ);
659 		el->el_history.last = el->el_history.buf +
660 		    (el->el_line.lastchar - el->el_line.buffer);
661 	}
662 	el->el_history.eventno += el->el_state.argument;
663 
664 	if (hist_get(el) == CC_ERROR) {
665 		if (el->el_map.type == MAP_VI) {
666 			el->el_history.eventno = sv_event;
667 		}
668 		beep = 1;
669 		/* el->el_history.eventno was fixed by first call */
670 		(void) hist_get(el);
671 	}
672 	if (beep)
673 		return CC_REFRESH_BEEP;
674 	return CC_REFRESH;
675 }
676 
677 
678 /* ed_next_history():
679  *	Move to the next history line
680  *	[^N] [j]
681  */
682 protected el_action_t
683 /*ARGSUSED*/
684 ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
685 {
686 	el_action_t beep = CC_REFRESH, rval;
687 
688 	el->el_chared.c_undo.len = -1;
689 	*el->el_line.lastchar = '\0';	/* just in case */
690 
691 	el->el_history.eventno -= el->el_state.argument;
692 
693 	if (el->el_history.eventno < 0) {
694 		el->el_history.eventno = 0;
695 		beep = CC_REFRESH_BEEP;
696 	}
697 	rval = hist_get(el);
698 	if (rval == CC_REFRESH)
699 		return beep;
700 	return rval;
701 
702 }
703 
704 
705 /* ed_search_prev_history():
706  *	Search previous in history for a line matching the current
707  *	next search history [M-P] [K]
708  */
709 protected el_action_t
710 /*ARGSUSED*/
711 ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
712 {
713 	const Char *hp;
714 	int h;
715 	int found = 0;
716 
717 	el->el_chared.c_vcmd.action = NOP;
718 	el->el_chared.c_undo.len = -1;
719 	*el->el_line.lastchar = '\0';	/* just in case */
720 	if (el->el_history.eventno < 0) {
721 #ifdef DEBUG_EDIT
722 		(void) fprintf(el->el_errfile,
723 		    "e_prev_search_hist(): eventno < 0;\n");
724 #endif
725 		el->el_history.eventno = 0;
726 		return CC_ERROR;
727 	}
728 	if (el->el_history.eventno == 0) {
729 		(void) Strncpy(el->el_history.buf, el->el_line.buffer,
730 		    EL_BUFSIZ);
731 		el->el_history.last = el->el_history.buf +
732 		    (el->el_line.lastchar - el->el_line.buffer);
733 	}
734 	if (el->el_history.ref == NULL)
735 		return CC_ERROR;
736 
737 	hp = HIST_FIRST(el);
738 	if (hp == NULL)
739 		return CC_ERROR;
740 
741 	c_setpat(el);		/* Set search pattern !! */
742 
743 	for (h = 1; h <= el->el_history.eventno; h++)
744 		hp = HIST_NEXT(el);
745 
746 	while (hp != NULL) {
747 #ifdef SDEBUG
748 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
749 #endif
750 		if ((Strncmp(hp, el->el_line.buffer, (size_t)
751 			    (el->el_line.lastchar - el->el_line.buffer)) ||
752 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
753 		    c_hmatch(el, hp)) {
754 			found = 1;
755 			break;
756 		}
757 		h++;
758 		hp = HIST_NEXT(el);
759 	}
760 
761 	if (!found) {
762 #ifdef SDEBUG
763 		(void) fprintf(el->el_errfile, "not found\n");
764 #endif
765 		return CC_ERROR;
766 	}
767 	el->el_history.eventno = h;
768 
769 	return hist_get(el);
770 }
771 
772 
773 /* ed_search_next_history():
774  *	Search next in history for a line matching the current
775  *	[M-N] [J]
776  */
777 protected el_action_t
778 /*ARGSUSED*/
779 ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
780 {
781 	const Char *hp;
782 	int h;
783 	int found = 0;
784 
785 	el->el_chared.c_vcmd.action = NOP;
786 	el->el_chared.c_undo.len = -1;
787 	*el->el_line.lastchar = '\0';	/* just in case */
788 
789 	if (el->el_history.eventno == 0)
790 		return CC_ERROR;
791 
792 	if (el->el_history.ref == NULL)
793 		return CC_ERROR;
794 
795 	hp = HIST_FIRST(el);
796 	if (hp == NULL)
797 		return CC_ERROR;
798 
799 	c_setpat(el);		/* Set search pattern !! */
800 
801 	for (h = 1; h < el->el_history.eventno && hp; h++) {
802 #ifdef SDEBUG
803 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
804 #endif
805 		if ((Strncmp(hp, el->el_line.buffer, (size_t)
806 			    (el->el_line.lastchar - el->el_line.buffer)) ||
807 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
808 		    c_hmatch(el, hp))
809 			found = h;
810 		hp = HIST_NEXT(el);
811 	}
812 
813 	if (!found) {		/* is it the current history number? */
814 		if (!c_hmatch(el, el->el_history.buf)) {
815 #ifdef SDEBUG
816 			(void) fprintf(el->el_errfile, "not found\n");
817 #endif
818 			return CC_ERROR;
819 		}
820 	}
821 	el->el_history.eventno = found;
822 
823 	return hist_get(el);
824 }
825 
826 
827 /* ed_prev_line():
828  *	Move up one line
829  *	Could be [k] [^p]
830  */
831 protected el_action_t
832 /*ARGSUSED*/
833 ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
834 {
835 	Char *ptr;
836 	int nchars = c_hpos(el);
837 
838 	/*
839          * Move to the line requested
840          */
841 	if (*(ptr = el->el_line.cursor) == '\n')
842 		ptr--;
843 
844 	for (; ptr >= el->el_line.buffer; ptr--)
845 		if (*ptr == '\n' && --el->el_state.argument <= 0)
846 			break;
847 
848 	if (el->el_state.argument > 0)
849 		return CC_ERROR;
850 
851 	/*
852          * Move to the beginning of the line
853          */
854 	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
855 		continue;
856 
857 	/*
858          * Move to the character requested
859          */
860 	for (ptr++;
861 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
862 	    ptr++)
863 		continue;
864 
865 	el->el_line.cursor = ptr;
866 	return CC_CURSOR;
867 }
868 
869 
870 /* ed_next_line():
871  *	Move down one line
872  *	Could be [j] [^n]
873  */
874 protected el_action_t
875 /*ARGSUSED*/
876 ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
877 {
878 	Char *ptr;
879 	int nchars = c_hpos(el);
880 
881 	/*
882          * Move to the line requested
883          */
884 	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
885 		if (*ptr == '\n' && --el->el_state.argument <= 0)
886 			break;
887 
888 	if (el->el_state.argument > 0)
889 		return CC_ERROR;
890 
891 	/*
892          * Move to the character requested
893          */
894 	for (ptr++;
895 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
896 	    ptr++)
897 		continue;
898 
899 	el->el_line.cursor = ptr;
900 	return CC_CURSOR;
901 }
902 
903 
904 /* ed_command():
905  *	Editline extended command
906  *	[M-X] [:]
907  */
908 protected el_action_t
909 /*ARGSUSED*/
910 ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
911 {
912 	Char tmpbuf[EL_BUFSIZ];
913 	int tmplen;
914 
915 	tmplen = c_gets(el, tmpbuf, STR("\n: "));
916 	terminal__putc(el, '\n');
917 
918 	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
919 		terminal_beep(el);
920 
921 	el->el_map.current = el->el_map.key;
922 	re_clear_display(el);
923 	return CC_REFRESH;
924 }
925