common.c revision 1.6
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
39static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93";
40#else
41static 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 */
54protected el_action_t
55/*ARGSUSED*/
56ed_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 */
69protected el_action_t
70ed_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 */
111protected el_action_t
112/*ARGSUSED*/
113ed_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 */
139protected el_action_t
140/*ARGSUSED*/
141ed_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 */
190protected el_action_t
191/*ARGSUSED*/
192ed_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 */
211protected el_action_t
212/*ARGSUSED*/
213ed_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 */
234protected el_action_t
235/*ARGSUSED*/
236ed_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 */
258protected el_action_t
259ed_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 */
283protected el_action_t
284/*ARGSUSED*/
285ed_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 */
312protected el_action_t
313/*ARGSUSED*/
314ed_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 */
338protected el_action_t
339/*ARGSUSED*/
340ed_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 */
363protected el_action_t
364ed_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 */
383protected el_action_t
384ed_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 */
411protected el_action_t
412ed_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 */
435protected el_action_t
436/*ARGSUSED*/
437ed_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 */
452protected el_action_t
453/*ARGSUSED*/
454ed_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 */
466protected el_action_t
467/*ARGSUSED*/
468ed_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 */
480protected el_action_t
481/*ARGSUSED*/
482ed_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 */
494protected el_action_t
495/*ARGSUSED*/
496ed_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 */
508protected el_action_t
509/*ARGSUSED*/
510ed_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 */
522protected el_action_t
523/*ARGSUSED*/
524ed_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 */
536protected el_action_t
537/*ARGSUSED*/
538ed_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 */
550protected el_action_t
551/*ARGSUSED*/
552ed_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 */
566protected el_action_t
567/*ARGSUSED*/
568ed_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 */
586protected el_action_t
587/*ARGSUSED*/
588ed_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 */
601protected el_action_t
602/*ARGSUSED*/
603ed_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 */
615protected el_action_t
616/*ARGSUSED*/
617ed_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 */
629protected el_action_t
630/*ARGSUSED*/
631ed_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 */
643protected el_action_t
644/*ARGSUSED*/
645ed_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 */
681protected el_action_t
682/*ARGSUSED*/
683ed_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 */
708protected el_action_t
709/*ARGSUSED*/
710ed_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 */
776protected el_action_t
777/*ARGSUSED*/
778ed_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 */
830protected el_action_t
831/*ARGSUSED*/
832ed_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 */
873protected el_action_t
874/*ARGSUSED*/
875ed_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 */
907protected el_action_t
908/*ARGSUSED*/
909ed_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