xref: /netbsd/lib/libedit/common.c (revision c4a72b64)
1 /*	$NetBSD: common.c,v 1.14 2002/11/20 16:50:08 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.14 2002/11/20 16:50:08 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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, int c)
458 {
459 
460 	return (CC_NORM);
461 }
462 
463 
464 /* ed_tty_dsusp():
465  *	Tty delayed suspend character
466  *	[^Y]
467  */
468 protected el_action_t
469 /*ARGSUSED*/
470 ed_tty_dsusp(EditLine *el, int c)
471 {
472 
473 	return (CC_NORM);
474 }
475 
476 
477 /* ed_tty_flush_output():
478  *	Tty flush output characters
479  *	[^O]
480  */
481 protected el_action_t
482 /*ARGSUSED*/
483 ed_tty_flush_output(EditLine *el, int c)
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, int c)
497 {
498 
499 	return (CC_NORM);
500 }
501 
502 
503 /* ed_tty_sigtstp():
504  *	Tty suspend character
505  *	[^Z]
506  */
507 protected el_action_t
508 /*ARGSUSED*/
509 ed_tty_sigtstp(EditLine *el, int c)
510 {
511 
512 	return (CC_NORM);
513 }
514 
515 
516 /* ed_tty_stop_output():
517  *	Tty disallow output characters
518  *	[^S]
519  */
520 protected el_action_t
521 /*ARGSUSED*/
522 ed_tty_stop_output(EditLine *el, int c)
523 {
524 
525 	return (CC_NORM);
526 }
527 
528 
529 /* ed_tty_start_output():
530  *	Tty allow output characters
531  *	[^Q]
532  */
533 protected el_action_t
534 /*ARGSUSED*/
535 ed_tty_start_output(EditLine *el, int c)
536 {
537 
538 	return (CC_NORM);
539 }
540 
541 
542 /* ed_newline():
543  *	Execute command
544  *	[^J]
545  */
546 protected el_action_t
547 /*ARGSUSED*/
548 ed_newline(EditLine *el, int c)
549 {
550 
551 	re_goto_bottom(el);
552 	*el->el_line.lastchar++ = '\n';
553 	*el->el_line.lastchar = '\0';
554 	return (CC_NEWLINE);
555 }
556 
557 
558 /* ed_delete_prev_char():
559  *	Delete the character to the left of the cursor
560  *	[^?]
561  */
562 protected el_action_t
563 /*ARGSUSED*/
564 ed_delete_prev_char(EditLine *el, int c)
565 {
566 
567 	if (el->el_line.cursor <= el->el_line.buffer)
568 		return (CC_ERROR);
569 
570 	c_delbefore(el, el->el_state.argument);
571 	el->el_line.cursor -= el->el_state.argument;
572 	if (el->el_line.cursor < el->el_line.buffer)
573 		el->el_line.cursor = el->el_line.buffer;
574 	return (CC_REFRESH);
575 }
576 
577 
578 /* ed_clear_screen():
579  *	Clear screen leaving current line at the top
580  *	[^L]
581  */
582 protected el_action_t
583 /*ARGSUSED*/
584 ed_clear_screen(EditLine *el, int c)
585 {
586 
587 	term_clear_screen(el);	/* clear the whole real screen */
588 	re_clear_display(el);	/* reset everything */
589 	return (CC_REFRESH);
590 }
591 
592 
593 /* ed_redisplay():
594  *	Redisplay everything
595  *	^R
596  */
597 protected el_action_t
598 /*ARGSUSED*/
599 ed_redisplay(EditLine *el, int c)
600 {
601 
602 	return (CC_REDISPLAY);
603 }
604 
605 
606 /* ed_start_over():
607  *	Erase current line and start from scratch
608  *	[^G]
609  */
610 protected el_action_t
611 /*ARGSUSED*/
612 ed_start_over(EditLine *el, int c)
613 {
614 
615 	ch_reset(el);
616 	return (CC_REFRESH);
617 }
618 
619 
620 /* ed_sequence_lead_in():
621  *	First character in a bound sequence
622  *	Placeholder for external keys
623  */
624 protected el_action_t
625 /*ARGSUSED*/
626 ed_sequence_lead_in(EditLine *el, int c)
627 {
628 
629 	return (CC_NORM);
630 }
631 
632 
633 /* ed_prev_history():
634  *	Move to the previous history line
635  *	[^P] [k]
636  */
637 protected el_action_t
638 /*ARGSUSED*/
639 ed_prev_history(EditLine *el, int c)
640 {
641 	char beep = 0;
642 	int sv_event = el->el_history.eventno;
643 
644 	el->el_chared.c_undo.len = -1;
645 	*el->el_line.lastchar = '\0';		/* just in case */
646 
647 	if (el->el_history.eventno == 0) {	/* save the current buffer
648 						 * away */
649 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
650 		    EL_BUFSIZ);
651 		el->el_history.last = el->el_history.buf +
652 		    (el->el_line.lastchar - el->el_line.buffer);
653 	}
654 	el->el_history.eventno += el->el_state.argument;
655 
656 	if (hist_get(el) == CC_ERROR) {
657 		if (el->el_map.type == MAP_VI) {
658 			el->el_history.eventno = sv_event;
659 			return CC_ERROR;
660 		}
661 		beep = 1;
662 		/* el->el_history.eventno was fixed by first call */
663 		(void) hist_get(el);
664 	}
665 	if (beep)
666 		return CC_REFRESH_BEEP;
667 	return CC_REFRESH;
668 }
669 
670 
671 /* ed_next_history():
672  *	Move to the next history line
673  *	[^N] [j]
674  */
675 protected el_action_t
676 /*ARGSUSED*/
677 ed_next_history(EditLine *el, int c)
678 {
679 	el_action_t beep = CC_REFRESH, rval;
680 
681 	el->el_chared.c_undo.len = -1;
682 	*el->el_line.lastchar = '\0';	/* just in case */
683 
684 	el->el_history.eventno -= el->el_state.argument;
685 
686 	if (el->el_history.eventno < 0) {
687 		el->el_history.eventno = 0;
688 		beep = CC_REFRESH_BEEP;
689 	}
690 	rval = hist_get(el);
691 	if (rval == CC_REFRESH)
692 		return beep;
693 	return rval;
694 
695 }
696 
697 
698 /* ed_search_prev_history():
699  *	Search previous in history for a line matching the current
700  *	next search history [M-P] [K]
701  */
702 protected el_action_t
703 /*ARGSUSED*/
704 ed_search_prev_history(EditLine *el, int c)
705 {
706 	const char *hp;
707 	int h;
708 	bool_t found = 0;
709 
710 	el->el_chared.c_vcmd.action = NOP;
711 	el->el_chared.c_undo.len = -1;
712 	*el->el_line.lastchar = '\0';	/* just in case */
713 	if (el->el_history.eventno < 0) {
714 #ifdef DEBUG_EDIT
715 		(void) fprintf(el->el_errfile,
716 		    "e_prev_search_hist(): eventno < 0;\n");
717 #endif
718 		el->el_history.eventno = 0;
719 		return (CC_ERROR);
720 	}
721 	if (el->el_history.eventno == 0) {
722 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
723 		    EL_BUFSIZ);
724 		el->el_history.last = el->el_history.buf +
725 		    (el->el_line.lastchar - el->el_line.buffer);
726 	}
727 	if (el->el_history.ref == NULL)
728 		return (CC_ERROR);
729 
730 	hp = HIST_FIRST(el);
731 	if (hp == NULL)
732 		return (CC_ERROR);
733 
734 	c_setpat(el);		/* Set search pattern !! */
735 
736 	for (h = 1; h <= el->el_history.eventno; h++)
737 		hp = HIST_NEXT(el);
738 
739 	while (hp != NULL) {
740 #ifdef SDEBUG
741 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
742 #endif
743 		if ((strncmp(hp, el->el_line.buffer, (size_t)
744 			    (el->el_line.lastchar - el->el_line.buffer)) ||
745 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
746 		    c_hmatch(el, hp)) {
747 			found++;
748 			break;
749 		}
750 		h++;
751 		hp = HIST_NEXT(el);
752 	}
753 
754 	if (!found) {
755 #ifdef SDEBUG
756 		(void) fprintf(el->el_errfile, "not found\n");
757 #endif
758 		return (CC_ERROR);
759 	}
760 	el->el_history.eventno = h;
761 
762 	return (hist_get(el));
763 }
764 
765 
766 /* ed_search_next_history():
767  *	Search next in history for a line matching the current
768  *	[M-N] [J]
769  */
770 protected el_action_t
771 /*ARGSUSED*/
772 ed_search_next_history(EditLine *el, int c)
773 {
774 	const char *hp;
775 	int h;
776 	bool_t found = 0;
777 
778 	el->el_chared.c_vcmd.action = NOP;
779 	el->el_chared.c_undo.len = -1;
780 	*el->el_line.lastchar = '\0';	/* just in case */
781 
782 	if (el->el_history.eventno == 0)
783 		return (CC_ERROR);
784 
785 	if (el->el_history.ref == NULL)
786 		return (CC_ERROR);
787 
788 	hp = HIST_FIRST(el);
789 	if (hp == NULL)
790 		return (CC_ERROR);
791 
792 	c_setpat(el);		/* Set search pattern !! */
793 
794 	for (h = 1; h < el->el_history.eventno && hp; h++) {
795 #ifdef SDEBUG
796 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
797 #endif
798 		if ((strncmp(hp, el->el_line.buffer, (size_t)
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 = h;
803 		hp = HIST_NEXT(el);
804 	}
805 
806 	if (!found) {		/* is it the current history number? */
807 		if (!c_hmatch(el, el->el_history.buf)) {
808 #ifdef SDEBUG
809 			(void) fprintf(el->el_errfile, "not found\n");
810 #endif
811 			return (CC_ERROR);
812 		}
813 	}
814 	el->el_history.eventno = found;
815 
816 	return (hist_get(el));
817 }
818 
819 
820 /* ed_prev_line():
821  *	Move up one line
822  *	Could be [k] [^p]
823  */
824 protected el_action_t
825 /*ARGSUSED*/
826 ed_prev_line(EditLine *el, int c)
827 {
828 	char *ptr;
829 	int nchars = c_hpos(el);
830 
831 	/*
832          * Move to the line requested
833          */
834 	if (*(ptr = el->el_line.cursor) == '\n')
835 		ptr--;
836 
837 	for (; ptr >= el->el_line.buffer; ptr--)
838 		if (*ptr == '\n' && --el->el_state.argument <= 0)
839 			break;
840 
841 	if (el->el_state.argument > 0)
842 		return (CC_ERROR);
843 
844 	/*
845          * Move to the beginning of the line
846          */
847 	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
848 		continue;
849 
850 	/*
851          * Move to the character requested
852          */
853 	for (ptr++;
854 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
855 	    ptr++)
856 		continue;
857 
858 	el->el_line.cursor = ptr;
859 	return (CC_CURSOR);
860 }
861 
862 
863 /* ed_next_line():
864  *	Move down one line
865  *	Could be [j] [^n]
866  */
867 protected el_action_t
868 /*ARGSUSED*/
869 ed_next_line(EditLine *el, int c)
870 {
871 	char *ptr;
872 	int nchars = c_hpos(el);
873 
874 	/*
875          * Move to the line requested
876          */
877 	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
878 		if (*ptr == '\n' && --el->el_state.argument <= 0)
879 			break;
880 
881 	if (el->el_state.argument > 0)
882 		return (CC_ERROR);
883 
884 	/*
885          * Move to the character requested
886          */
887 	for (ptr++;
888 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
889 	    ptr++)
890 		continue;
891 
892 	el->el_line.cursor = ptr;
893 	return (CC_CURSOR);
894 }
895 
896 
897 /* ed_command():
898  *	Editline extended command
899  *	[M-X] [:]
900  */
901 protected el_action_t
902 /*ARGSUSED*/
903 ed_command(EditLine *el, int c)
904 {
905 	char tmpbuf[EL_BUFSIZ];
906 	int tmplen;
907 
908 	tmplen = c_gets(el, tmpbuf, "\n: ");
909 	term__putc('\n');
910 
911 	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
912 		term_beep(el);
913 
914 	el->el_map.current = el->el_map.key;
915 	re_clear_display(el);
916 	return CC_REFRESH;
917 }
918