common.c revision 1573
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(*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(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(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    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 */
664protected el_action_t
665/*ARGSUSED*/
666ed_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 */
679protected el_action_t
680/*ARGSUSED*/
681ed_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 */
693protected el_action_t
694/*ARGSUSED*/
695ed_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 */
730protected el_action_t
731/*ARGSUSED*/
732ed_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 */
754protected el_action_t
755/*ARGSUSED*/
756ed_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 */
826protected el_action_t
827/*ARGSUSED*/
828ed_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 */
883protected el_action_t
884/*ARGSUSED*/
885ed_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 */
928protected el_action_t
929/*ARGSUSED*/
930ed_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 */
964protected el_action_t
965/*ARGSUSED*/
966ed_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