common.c revision 26926
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)
38static 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 */
51protected el_action_t
52/*ARGSUSED*/
53ed_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 */
67protected el_action_t
68ed_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 */
124protected el_action_t
125/*ARGSUSED*/
126ed_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 */
154protected el_action_t
155/*ARGSUSED*/
156ed_delete_next_char(el, c)
157    EditLine *el;
158    int c;
159{
160#ifdef notdef /* XXX */
161#define EL el->el_line
162fprintf(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 */
203protected el_action_t
204/*ARGSUSED*/
205ed_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 */
225protected el_action_t
226/*ARGSUSED*/
227ed_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 */
249protected el_action_t
250/*ARGSUSED*/
251ed_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((unsigned char) *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 */
275protected el_action_t
276ed_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 */
302protected el_action_t
303/*ARGSUSED*/
304ed_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 */
329protected el_action_t
330/*ARGSUSED*/
331ed_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 */
356protected el_action_t
357/*ARGSUSED*/
358ed_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 */
384protected el_action_t
385ed_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 */
406protected el_action_t
407ed_digit(el, c)
408    EditLine *el;
409    int c;
410{
411    if (!isdigit((unsigned char) 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 */
449protected el_action_t
450ed_argument_digit(el, c)
451    EditLine *el;
452    register int c;
453{
454    if (!isdigit((unsigned char) 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 */
474protected el_action_t
475/*ARGSUSED*/
476ed_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 */
494protected el_action_t
495/*ARGSUSED*/
496ed_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 */
508protected el_action_t
509/*ARGSUSED*/
510ed_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 */
522protected el_action_t
523/*ARGSUSED*/
524ed_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 */
536protected el_action_t
537/*ARGSUSED*/
538ed_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 */
550protected el_action_t
551/*ARGSUSED*/
552ed_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 */
564protected el_action_t
565/*ARGSUSED*/
566ed_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 */
578protected el_action_t
579/*ARGSUSED*/
580ed_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 */
592protected el_action_t
593/*ARGSUSED*/
594ed_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 */
611protected el_action_t
612/*ARGSUSED*/
613ed_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 */
632protected el_action_t
633/*ARGSUSED*/
634ed_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 */
648protected el_action_t
649/*ARGSUSED*/
650ed_redisplay(el, c)
651    EditLine *el;
652    int c;
653{
654    return CC_REDISPLAY;
655}
656
657
658/* ed_start_over():
659 *	Erase current line and start from scratch
660 *	[^G]
661 */
662protected el_action_t
663/*ARGSUSED*/
664ed_start_over(el, c)
665    EditLine *el;
666    int c;
667{
668    ch_reset(el);
669    return CC_REFRESH;
670}
671
672
673/* ed_sequence_lead_in():
674 *	First character in a bound sequence
675 *	Placeholder for external keys
676 */
677protected el_action_t
678/*ARGSUSED*/
679ed_sequence_lead_in(el, c)
680    EditLine *el;
681    int c;
682{
683    return CC_NORM;
684}
685
686
687/* ed_prev_history():
688 *	Move to the previous history line
689 *	[^P] [k]
690 */
691protected el_action_t
692/*ARGSUSED*/
693ed_prev_history(el, c)
694    EditLine *el;
695    int c;
696{
697    char    beep = 0;
698
699    el->el_chared.c_undo.action = NOP;
700    *el->el_line.lastchar = '\0';		/* just in case */
701
702    if (el->el_history.eventno == 0) {	/* save the current buffer away */
703	(void) strncpy(el->el_history.buf, el->el_line.buffer, EL_BUFSIZ);
704	el->el_history.last = el->el_history.buf +
705		(el->el_line.lastchar - el->el_line.buffer);
706    }
707
708    el->el_history.eventno += el->el_state.argument;
709
710    if (hist_get(el) == CC_ERROR) {
711	beep = 1;
712	/* el->el_history.eventno was fixed by first call */
713	(void) hist_get(el);
714    }
715
716    re_refresh(el);
717    if (beep)
718	return CC_ERROR;
719    else
720	return CC_NORM;	/* was CC_UP_HIST */
721}
722
723
724/* ed_next_history():
725 *	Move to the next history line
726 *	[^N] [j]
727 */
728protected el_action_t
729/*ARGSUSED*/
730ed_next_history(el, c)
731    EditLine *el;
732    int c;
733{
734    el->el_chared.c_undo.action = NOP;
735    *el->el_line.lastchar = '\0';		/* just in case */
736
737    el->el_history.eventno -= el->el_state.argument;
738
739    if (el->el_history.eventno < 0) {
740	el->el_history.eventno = 0;
741	return CC_ERROR;	/* make it beep */
742    }
743
744    return hist_get(el);
745}
746
747
748/* ed_search_prev_history():
749 *	Search previous in history for a line matching the current
750 *	next search history [M-P] [K]
751 */
752protected el_action_t
753/*ARGSUSED*/
754ed_search_prev_history(el, c)
755    EditLine *el;
756    int c;
757{
758    const char *hp;
759    int h;
760    bool_t    found = 0;
761
762    el->el_chared.c_vcmd.action = NOP;
763    el->el_chared.c_undo.action = NOP;
764    *el->el_line.lastchar = '\0';		/* just in case */
765    if (el->el_history.eventno < 0) {
766#ifdef DEBUG_EDIT
767	(void) fprintf(el->el_errfile, "e_prev_search_hist(): eventno < 0;\n");
768#endif
769	el->el_history.eventno = 0;
770	return CC_ERROR;
771    }
772
773    if (el->el_history.eventno == 0) {
774	(void) strncpy(el->el_history.buf, el->el_line.buffer, EL_BUFSIZ);
775	el->el_history.last = el->el_history.buf +
776		(el->el_line.lastchar - el->el_line.buffer);
777    }
778
779
780    if (el->el_history.ref == NULL)
781	return CC_ERROR;
782
783    hp = HIST_FIRST(el);
784    if (hp == NULL)
785	return CC_ERROR;
786
787    c_setpat(el);		/* Set search pattern !! */
788
789    for (h = 1; h <= el->el_history.eventno; h++)
790	hp = HIST_NEXT(el);
791
792    while (hp != NULL) {
793#ifdef SDEBUG
794	(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
795#endif
796	if ((strncmp(hp, el->el_line.buffer,
797		     el->el_line.lastchar - el->el_line.buffer) ||
798	    hp[el->el_line.lastchar-el->el_line.buffer]) &&
799	    c_hmatch(el, hp)) {
800	    found++;
801	    break;
802	}
803	h++;
804	hp = HIST_NEXT(el);
805    }
806
807    if (!found) {
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 = h;
815
816    return hist_get(el);
817}
818
819
820/* ed_search_next_history():
821 *	Search next in history for a line matching the current
822 *	[M-N] [J]
823 */
824protected el_action_t
825/*ARGSUSED*/
826ed_search_next_history(el, c)
827    EditLine *el;
828    int c;
829{
830    const char *hp;
831    int h;
832    bool_t    found = 0;
833
834    el->el_chared.c_vcmd.action = NOP;
835    el->el_chared.c_undo.action = NOP;
836    *el->el_line.lastchar = '\0';		/* just in case */
837
838    if (el->el_history.eventno == 0)
839	return CC_ERROR;
840
841    if (el->el_history.ref == NULL)
842	return CC_ERROR;
843
844    hp = HIST_FIRST(el);
845    if (hp == NULL)
846	return CC_ERROR;
847
848    c_setpat(el);		/* Set search pattern !! */
849
850    for (h = 1; h < el->el_history.eventno && hp; h++) {
851#ifdef SDEBUG
852	(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
853#endif
854	if ((strncmp(hp, el->el_line.buffer,
855		     el->el_line.lastchar - el->el_line.buffer) ||
856	     hp[el->el_line.lastchar-el->el_line.buffer]) &&
857	    c_hmatch(el, hp))
858	    found = h;
859	hp = HIST_NEXT(el);
860    }
861
862    if (!found) {		/* is it the current history number? */
863	if (!c_hmatch(el, el->el_history.buf)) {
864#ifdef SDEBUG
865	    (void) fprintf(el->el_errfile, "not found\n");
866#endif
867	    return CC_ERROR;
868	}
869    }
870
871    el->el_history.eventno = found;
872
873    return hist_get(el);
874}
875
876
877/* ed_prev_line():
878 *	Move up one line
879 *	Could be [k] [^p]
880 */
881protected el_action_t
882/*ARGSUSED*/
883ed_prev_line(el, c)
884    EditLine *el;
885    int c;
886{
887    char *ptr;
888    int nchars = c_hpos(el);
889
890    /*
891     * Move to the line requested
892     */
893    if (*(ptr = el->el_line.cursor) == '\n')
894	ptr--;
895
896    for (; ptr >= el->el_line.buffer; ptr--)
897	if (*ptr == '\n' && --el->el_state.argument <= 0)
898	    break;
899
900    if (el->el_state.argument > 0)
901	return CC_ERROR;
902
903    /*
904     * Move to the beginning of the line
905     */
906    for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
907	continue;
908
909    /*
910     * Move to the character requested
911     */
912    for (ptr++;
913	 nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
914	 ptr++)
915	continue;
916
917    el->el_line.cursor = ptr;
918    return CC_CURSOR;
919}
920
921
922/* ed_next_line():
923 *	Move down one line
924 *	Could be [j] [^n]
925 */
926protected el_action_t
927/*ARGSUSED*/
928ed_next_line(el, c)
929    EditLine *el;
930    int c;
931{
932    char *ptr;
933    int nchars = c_hpos(el);
934
935    /*
936     * Move to the line requested
937     */
938    for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
939	if (*ptr == '\n' && --el->el_state.argument <= 0)
940	    break;
941
942    if (el->el_state.argument > 0)
943	return CC_ERROR;
944
945    /*
946     * Move to the character requested
947     */
948    for (ptr++;
949	 nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
950    	 ptr++)
951	continue;
952
953    el->el_line.cursor = ptr;
954    return CC_CURSOR;
955}
956
957
958/* ed_command():
959 *	Editline extended command
960 *	[M-X] [:]
961 */
962protected el_action_t
963/*ARGSUSED*/
964ed_command(el, c)
965    EditLine *el;
966    int c;
967{
968    char tmpbuf[EL_BUFSIZ];
969    int tmplen;
970
971    el->el_line.buffer[0] = '\0';
972    el->el_line.lastchar = el->el_line.buffer;
973    el->el_line.cursor = el->el_line.buffer;
974
975    c_insert(el, 3);	/* prompt + ": " */
976    *el->el_line.cursor++ = '\n';
977    *el->el_line.cursor++ = ':';
978    *el->el_line.cursor++ = ' ';
979    re_refresh(el);
980
981    tmplen = c_gets(el, tmpbuf);
982    tmpbuf[tmplen] = '\0';
983
984    el->el_line.buffer[0] = '\0';
985    el->el_line.lastchar = el->el_line.buffer;
986    el->el_line.cursor = el->el_line.buffer;
987
988    if (parse_line(el, tmpbuf) == -1)
989	return CC_ERROR;
990    else
991	return CC_REFRESH;
992}
993