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