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