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