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