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