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