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