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