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