xref: /netbsd-src/lib/libedit/common.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: common.c,v 1.15 2003/06/19 15:55:05 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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include "config.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: common.c,v 1.15 2003/06/19 15:55:05 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47 
48 /*
49  * common.c: Common Editor functions
50  */
51 #include "el.h"
52 
53 /* ed_end_of_file():
54  *	Indicate end of file
55  *	[^D]
56  */
57 protected el_action_t
58 /*ARGSUSED*/
59 ed_end_of_file(EditLine *el, int c __attribute__((__unused__)))
60 {
61 
62 	re_goto_bottom(el);
63 	*el->el_line.lastchar = '\0';
64 	return (CC_EOF);
65 }
66 
67 
68 /* ed_insert():
69  *	Add character to the line
70  *	Insert a character [bound to all insert keys]
71  */
72 protected el_action_t
73 ed_insert(EditLine *el, int c)
74 {
75 	int count = el->el_state.argument;
76 
77 	if (c == '\0')
78 		return (CC_ERROR);
79 
80 	if (el->el_line.lastchar + el->el_state.argument >=
81 	    el->el_line.limit) {
82 		/* end of buffer space, try to allocate more */
83 		if (!ch_enlargebufs(el, (size_t) count))
84 			return CC_ERROR;	/* error allocating more */
85 	}
86 
87 	if (count == 1) {
88 		if (el->el_state.inputmode == MODE_INSERT
89 		    || el->el_line.cursor >= el->el_line.lastchar)
90 			c_insert(el, 1);
91 
92 		*el->el_line.cursor++ = c;
93 		re_fastaddc(el);		/* fast refresh for one char. */
94 	} else {
95 		if (el->el_state.inputmode != MODE_REPLACE_1)
96 			c_insert(el, el->el_state.argument);
97 
98 		while (count-- && el->el_line.cursor < el->el_line.lastchar)
99 			*el->el_line.cursor++ = c;
100 		re_refresh(el);
101 	}
102 
103 	if (el->el_state.inputmode == MODE_REPLACE_1)
104 		return vi_command_mode(el, 0);
105 
106 	return (CC_NORM);
107 }
108 
109 
110 /* ed_delete_prev_word():
111  *	Delete from beginning of current word to cursor
112  *	[M-^?] [^W]
113  */
114 protected el_action_t
115 /*ARGSUSED*/
116 ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__)))
117 {
118 	char *cp, *p, *kp;
119 
120 	if (el->el_line.cursor == el->el_line.buffer)
121 		return (CC_ERROR);
122 
123 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
124 	    el->el_state.argument, ce__isword);
125 
126 	for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
127 		*kp++ = *p;
128 	el->el_chared.c_kill.last = kp;
129 
130 	c_delbefore(el, el->el_line.cursor - cp);	/* delete before dot */
131 	el->el_line.cursor = cp;
132 	if (el->el_line.cursor < el->el_line.buffer)
133 		el->el_line.cursor = el->el_line.buffer; /* bounds check */
134 	return (CC_REFRESH);
135 }
136 
137 
138 /* ed_delete_next_char():
139  *	Delete character under cursor
140  *	[^D] [x]
141  */
142 protected el_action_t
143 /*ARGSUSED*/
144 ed_delete_next_char(EditLine *el, int c __attribute__((__unused__)))
145 {
146 #ifdef notdef			/* XXX */
147 #define	EL	el->el_line
148 	(void) fprintf(el->el_errlfile,
149 	    "\nD(b: %x(%s)  c: %x(%s) last: %x(%s) limit: %x(%s)\n",
150 	    EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
151 	    EL.lastchar, EL.limit, EL.limit);
152 #endif
153 	if (el->el_line.cursor == el->el_line.lastchar) {
154 			/* if I'm at the end */
155 		if (el->el_map.type == MAP_VI) {
156 			if (el->el_line.cursor == el->el_line.buffer) {
157 				/* if I'm also at the beginning */
158 #ifdef KSHVI
159 				return (CC_ERROR);
160 #else
161 				term_overwrite(el, STReof, 4);
162 					/* then do a EOF */
163 				term__flush();
164 				return (CC_EOF);
165 #endif
166 			} else {
167 #ifdef KSHVI
168 				el->el_line.cursor--;
169 #else
170 				return (CC_ERROR);
171 #endif
172 			}
173 		} else {
174 			if (el->el_line.cursor != el->el_line.buffer)
175 				el->el_line.cursor--;
176 			else
177 				return (CC_ERROR);
178 		}
179 	}
180 	c_delafter(el, el->el_state.argument);	/* delete after dot */
181 	if (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, int 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, int c __attribute__((__unused__)))
217 {
218 
219 	el->el_line.cursor = el->el_line.lastchar;
220 	if (el->el_map.type == MAP_VI) {
221 #ifdef VI_MOVE
222 		el->el_line.cursor--;
223 #endif
224 		if (el->el_chared.c_vcmd.action != NOP) {
225 			cv_delfini(el);
226 			return (CC_REFRESH);
227 		}
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, int 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((unsigned char) *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, int 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] = 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, int 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, int 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, int 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, int c)
368 {
369 	int num;
370 	char tc;
371 
372 	tty_quotemode(el);
373 	num = el_getc(el, &tc);
374 	c = (unsigned char) tc;
375 	tty_noquotemode(el);
376 	if (num == 1)
377 		return (ed_insert(el, c));
378 	else
379 		return (ed_end_of_file(el, 0));
380 }
381 
382 
383 /* ed_digit():
384  *	Adds to argument or enters a digit
385  */
386 protected el_action_t
387 ed_digit(EditLine *el, int c)
388 {
389 
390 	if (!isdigit(c))
391 		return (CC_ERROR);
392 
393 	if (el->el_state.doingarg) {
394 			/* if doing an arg, add this in... */
395 		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
396 			el->el_state.argument = c - '0';
397 		else {
398 			if (el->el_state.argument > 1000000)
399 				return (CC_ERROR);
400 			el->el_state.argument =
401 			    (el->el_state.argument * 10) + (c - '0');
402 		}
403 		return (CC_ARGHACK);
404 	}
405 
406 	return ed_insert(el, c);
407 }
408 
409 
410 /* ed_argument_digit():
411  *	Digit that starts argument
412  *	For ESC-n
413  */
414 protected el_action_t
415 ed_argument_digit(EditLine *el, int c)
416 {
417 
418 	if (!isdigit(c))
419 		return (CC_ERROR);
420 
421 	if (el->el_state.doingarg) {
422 		if (el->el_state.argument > 1000000)
423 			return (CC_ERROR);
424 		el->el_state.argument = (el->el_state.argument * 10) +
425 		    (c - '0');
426 	} else {		/* else starting an argument */
427 		el->el_state.argument = c - '0';
428 		el->el_state.doingarg = 1;
429 	}
430 	return (CC_ARGHACK);
431 }
432 
433 
434 /* ed_unassigned():
435  *	Indicates unbound character
436  *	Bound to keys that are not assigned
437  */
438 protected el_action_t
439 /*ARGSUSED*/
440 ed_unassigned(EditLine *el, int c __attribute__((__unused__)))
441 {
442 
443 	return (CC_ERROR);
444 }
445 
446 
447 /**
448  ** TTY key handling.
449  **/
450 
451 /* ed_tty_sigint():
452  *	Tty interrupt character
453  *	[^C]
454  */
455 protected el_action_t
456 /*ARGSUSED*/
457 ed_tty_sigint(EditLine *el __attribute__((__unused__)),
458 	      int c __attribute__((__unused__)))
459 {
460 
461 	return (CC_NORM);
462 }
463 
464 
465 /* ed_tty_dsusp():
466  *	Tty delayed suspend character
467  *	[^Y]
468  */
469 protected el_action_t
470 /*ARGSUSED*/
471 ed_tty_dsusp(EditLine *el __attribute__((__unused__)),
472 	     int c __attribute__((__unused__)))
473 {
474 
475 	return (CC_NORM);
476 }
477 
478 
479 /* ed_tty_flush_output():
480  *	Tty flush output characters
481  *	[^O]
482  */
483 protected el_action_t
484 /*ARGSUSED*/
485 ed_tty_flush_output(EditLine *el __attribute__((__unused__)),
486 		    int c __attribute__((__unused__)))
487 {
488 
489 	return (CC_NORM);
490 }
491 
492 
493 /* ed_tty_sigquit():
494  *	Tty quit character
495  *	[^\]
496  */
497 protected el_action_t
498 /*ARGSUSED*/
499 ed_tty_sigquit(EditLine *el __attribute__((__unused__)),
500 	       int c __attribute__((__unused__)))
501 {
502 
503 	return (CC_NORM);
504 }
505 
506 
507 /* ed_tty_sigtstp():
508  *	Tty suspend character
509  *	[^Z]
510  */
511 protected el_action_t
512 /*ARGSUSED*/
513 ed_tty_sigtstp(EditLine *el __attribute__((__unused__)),
514 	       int c __attribute__((__unused__)))
515 {
516 
517 	return (CC_NORM);
518 }
519 
520 
521 /* ed_tty_stop_output():
522  *	Tty disallow output characters
523  *	[^S]
524  */
525 protected el_action_t
526 /*ARGSUSED*/
527 ed_tty_stop_output(EditLine *el __attribute__((__unused__)),
528 		   int c __attribute__((__unused__)))
529 {
530 
531 	return (CC_NORM);
532 }
533 
534 
535 /* ed_tty_start_output():
536  *	Tty allow output characters
537  *	[^Q]
538  */
539 protected el_action_t
540 /*ARGSUSED*/
541 ed_tty_start_output(EditLine *el __attribute__((__unused__)),
542 		    int c __attribute__((__unused__)))
543 {
544 
545 	return (CC_NORM);
546 }
547 
548 
549 /* ed_newline():
550  *	Execute command
551  *	[^J]
552  */
553 protected el_action_t
554 /*ARGSUSED*/
555 ed_newline(EditLine *el, int c __attribute__((__unused__)))
556 {
557 
558 	re_goto_bottom(el);
559 	*el->el_line.lastchar++ = '\n';
560 	*el->el_line.lastchar = '\0';
561 	return (CC_NEWLINE);
562 }
563 
564 
565 /* ed_delete_prev_char():
566  *	Delete the character to the left of the cursor
567  *	[^?]
568  */
569 protected el_action_t
570 /*ARGSUSED*/
571 ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__)))
572 {
573 
574 	if (el->el_line.cursor <= el->el_line.buffer)
575 		return (CC_ERROR);
576 
577 	c_delbefore(el, el->el_state.argument);
578 	el->el_line.cursor -= el->el_state.argument;
579 	if (el->el_line.cursor < el->el_line.buffer)
580 		el->el_line.cursor = el->el_line.buffer;
581 	return (CC_REFRESH);
582 }
583 
584 
585 /* ed_clear_screen():
586  *	Clear screen leaving current line at the top
587  *	[^L]
588  */
589 protected el_action_t
590 /*ARGSUSED*/
591 ed_clear_screen(EditLine *el, int c __attribute__((__unused__)))
592 {
593 
594 	term_clear_screen(el);	/* clear the whole real screen */
595 	re_clear_display(el);	/* reset everything */
596 	return (CC_REFRESH);
597 }
598 
599 
600 /* ed_redisplay():
601  *	Redisplay everything
602  *	^R
603  */
604 protected el_action_t
605 /*ARGSUSED*/
606 ed_redisplay(EditLine *el __attribute__((__unused__)),
607 	     int c __attribute__((__unused__)))
608 {
609 
610 	return (CC_REDISPLAY);
611 }
612 
613 
614 /* ed_start_over():
615  *	Erase current line and start from scratch
616  *	[^G]
617  */
618 protected el_action_t
619 /*ARGSUSED*/
620 ed_start_over(EditLine *el, int c __attribute__((__unused__)))
621 {
622 
623 	ch_reset(el);
624 	return (CC_REFRESH);
625 }
626 
627 
628 /* ed_sequence_lead_in():
629  *	First character in a bound sequence
630  *	Placeholder for external keys
631  */
632 protected el_action_t
633 /*ARGSUSED*/
634 ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
635 		    int c __attribute__((__unused__)))
636 {
637 
638 	return (CC_NORM);
639 }
640 
641 
642 /* ed_prev_history():
643  *	Move to the previous history line
644  *	[^P] [k]
645  */
646 protected el_action_t
647 /*ARGSUSED*/
648 ed_prev_history(EditLine *el, int c __attribute__((__unused__)))
649 {
650 	char beep = 0;
651 	int sv_event = el->el_history.eventno;
652 
653 	el->el_chared.c_undo.len = -1;
654 	*el->el_line.lastchar = '\0';		/* just in case */
655 
656 	if (el->el_history.eventno == 0) {	/* save the current buffer
657 						 * away */
658 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
659 		    EL_BUFSIZ);
660 		el->el_history.last = el->el_history.buf +
661 		    (el->el_line.lastchar - el->el_line.buffer);
662 	}
663 	el->el_history.eventno += el->el_state.argument;
664 
665 	if (hist_get(el) == CC_ERROR) {
666 		if (el->el_map.type == MAP_VI) {
667 			el->el_history.eventno = sv_event;
668 			return CC_ERROR;
669 		}
670 		beep = 1;
671 		/* el->el_history.eventno was fixed by first call */
672 		(void) hist_get(el);
673 	}
674 	if (beep)
675 		return CC_REFRESH_BEEP;
676 	return CC_REFRESH;
677 }
678 
679 
680 /* ed_next_history():
681  *	Move to the next history line
682  *	[^N] [j]
683  */
684 protected el_action_t
685 /*ARGSUSED*/
686 ed_next_history(EditLine *el, int c __attribute__((__unused__)))
687 {
688 	el_action_t beep = CC_REFRESH, rval;
689 
690 	el->el_chared.c_undo.len = -1;
691 	*el->el_line.lastchar = '\0';	/* just in case */
692 
693 	el->el_history.eventno -= el->el_state.argument;
694 
695 	if (el->el_history.eventno < 0) {
696 		el->el_history.eventno = 0;
697 		beep = CC_REFRESH_BEEP;
698 	}
699 	rval = hist_get(el);
700 	if (rval == CC_REFRESH)
701 		return beep;
702 	return rval;
703 
704 }
705 
706 
707 /* ed_search_prev_history():
708  *	Search previous in history for a line matching the current
709  *	next search history [M-P] [K]
710  */
711 protected el_action_t
712 /*ARGSUSED*/
713 ed_search_prev_history(EditLine *el, int c __attribute__((__unused__)))
714 {
715 	const char *hp;
716 	int h;
717 	bool_t found = 0;
718 
719 	el->el_chared.c_vcmd.action = NOP;
720 	el->el_chared.c_undo.len = -1;
721 	*el->el_line.lastchar = '\0';	/* just in case */
722 	if (el->el_history.eventno < 0) {
723 #ifdef DEBUG_EDIT
724 		(void) fprintf(el->el_errfile,
725 		    "e_prev_search_hist(): eventno < 0;\n");
726 #endif
727 		el->el_history.eventno = 0;
728 		return (CC_ERROR);
729 	}
730 	if (el->el_history.eventno == 0) {
731 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
732 		    EL_BUFSIZ);
733 		el->el_history.last = el->el_history.buf +
734 		    (el->el_line.lastchar - el->el_line.buffer);
735 	}
736 	if (el->el_history.ref == NULL)
737 		return (CC_ERROR);
738 
739 	hp = HIST_FIRST(el);
740 	if (hp == NULL)
741 		return (CC_ERROR);
742 
743 	c_setpat(el);		/* Set search pattern !! */
744 
745 	for (h = 1; h <= el->el_history.eventno; h++)
746 		hp = HIST_NEXT(el);
747 
748 	while (hp != NULL) {
749 #ifdef SDEBUG
750 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
751 #endif
752 		if ((strncmp(hp, el->el_line.buffer, (size_t)
753 			    (el->el_line.lastchar - el->el_line.buffer)) ||
754 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
755 		    c_hmatch(el, hp)) {
756 			found++;
757 			break;
758 		}
759 		h++;
760 		hp = HIST_NEXT(el);
761 	}
762 
763 	if (!found) {
764 #ifdef SDEBUG
765 		(void) fprintf(el->el_errfile, "not found\n");
766 #endif
767 		return (CC_ERROR);
768 	}
769 	el->el_history.eventno = h;
770 
771 	return (hist_get(el));
772 }
773 
774 
775 /* ed_search_next_history():
776  *	Search next in history for a line matching the current
777  *	[M-N] [J]
778  */
779 protected el_action_t
780 /*ARGSUSED*/
781 ed_search_next_history(EditLine *el, int c __attribute__((__unused__)))
782 {
783 	const char *hp;
784 	int h;
785 	bool_t found = 0;
786 
787 	el->el_chared.c_vcmd.action = NOP;
788 	el->el_chared.c_undo.len = -1;
789 	*el->el_line.lastchar = '\0';	/* just in case */
790 
791 	if (el->el_history.eventno == 0)
792 		return (CC_ERROR);
793 
794 	if (el->el_history.ref == NULL)
795 		return (CC_ERROR);
796 
797 	hp = HIST_FIRST(el);
798 	if (hp == NULL)
799 		return (CC_ERROR);
800 
801 	c_setpat(el);		/* Set search pattern !! */
802 
803 	for (h = 1; h < el->el_history.eventno && hp; h++) {
804 #ifdef SDEBUG
805 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
806 #endif
807 		if ((strncmp(hp, el->el_line.buffer, (size_t)
808 			    (el->el_line.lastchar - el->el_line.buffer)) ||
809 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
810 		    c_hmatch(el, hp))
811 			found = h;
812 		hp = HIST_NEXT(el);
813 	}
814 
815 	if (!found) {		/* is it the current history number? */
816 		if (!c_hmatch(el, el->el_history.buf)) {
817 #ifdef SDEBUG
818 			(void) fprintf(el->el_errfile, "not found\n");
819 #endif
820 			return (CC_ERROR);
821 		}
822 	}
823 	el->el_history.eventno = found;
824 
825 	return (hist_get(el));
826 }
827 
828 
829 /* ed_prev_line():
830  *	Move up one line
831  *	Could be [k] [^p]
832  */
833 protected el_action_t
834 /*ARGSUSED*/
835 ed_prev_line(EditLine *el, int c __attribute__((__unused__)))
836 {
837 	char *ptr;
838 	int nchars = c_hpos(el);
839 
840 	/*
841          * Move to the line requested
842          */
843 	if (*(ptr = el->el_line.cursor) == '\n')
844 		ptr--;
845 
846 	for (; ptr >= el->el_line.buffer; ptr--)
847 		if (*ptr == '\n' && --el->el_state.argument <= 0)
848 			break;
849 
850 	if (el->el_state.argument > 0)
851 		return (CC_ERROR);
852 
853 	/*
854          * Move to the beginning of the line
855          */
856 	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
857 		continue;
858 
859 	/*
860          * Move to the character requested
861          */
862 	for (ptr++;
863 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
864 	    ptr++)
865 		continue;
866 
867 	el->el_line.cursor = ptr;
868 	return (CC_CURSOR);
869 }
870 
871 
872 /* ed_next_line():
873  *	Move down one line
874  *	Could be [j] [^n]
875  */
876 protected el_action_t
877 /*ARGSUSED*/
878 ed_next_line(EditLine *el, int c __attribute__((__unused__)))
879 {
880 	char *ptr;
881 	int nchars = c_hpos(el);
882 
883 	/*
884          * Move to the line requested
885          */
886 	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
887 		if (*ptr == '\n' && --el->el_state.argument <= 0)
888 			break;
889 
890 	if (el->el_state.argument > 0)
891 		return (CC_ERROR);
892 
893 	/*
894          * Move to the character requested
895          */
896 	for (ptr++;
897 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
898 	    ptr++)
899 		continue;
900 
901 	el->el_line.cursor = ptr;
902 	return (CC_CURSOR);
903 }
904 
905 
906 /* ed_command():
907  *	Editline extended command
908  *	[M-X] [:]
909  */
910 protected el_action_t
911 /*ARGSUSED*/
912 ed_command(EditLine *el, int c __attribute__((__unused__)))
913 {
914 	char tmpbuf[EL_BUFSIZ];
915 	int tmplen;
916 
917 	tmplen = c_gets(el, tmpbuf, "\n: ");
918 	term__putc('\n');
919 
920 	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
921 		term_beep(el);
922 
923 	el->el_map.current = el->el_map.key;
924 	re_clear_display(el);
925 	return CC_REFRESH;
926 }
927