xref: /dragonfly/contrib/libedit/src/common.c (revision 698e9e6cd5f042847de67460caaa3fde98cdfe99)
1 /*        $NetBSD: common.c,v 1.49 2020/03/30 06:54:37 ryo Exp $      */
2 
3 /*-
4  * Copyright (c) 1992, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)common.c    8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: common.c,v 1.49 2020/03/30 06:54:37 ryo Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 
44 /*
45  * common.c: Common Editor functions
46  */
47 #include <ctype.h>
48 #include <string.h>
49 
50 #include "el.h"
51 #include "common.h"
52 #include "fcns.h"
53 #include "parse.h"
54 #include "vi.h"
55 
56 /* ed_end_of_file():
57  *        Indicate end of file
58  *        [^D]
59  */
60 libedit_private el_action_t
61 /*ARGSUSED*/
ed_end_of_file(EditLine * el,wint_t c)62 ed_end_of_file(EditLine *el, wint_t c __attribute__((__unused__)))
63 {
64 
65           re_goto_bottom(el);
66           *el->el_line.lastchar = '\0';
67           return CC_EOF;
68 }
69 
70 
71 /* ed_insert():
72  *        Add character to the line
73  *        Insert a character [bound to all insert keys]
74  */
75 libedit_private el_action_t
ed_insert(EditLine * el,wint_t c)76 ed_insert(EditLine *el, wint_t c)
77 {
78           int count = el->el_state.argument;
79 
80           if (c == '\0')
81                     return CC_ERROR;
82 
83           if (el->el_line.lastchar + el->el_state.argument >=
84               el->el_line.limit) {
85                     /* end of buffer space, try to allocate more */
86                     if (!ch_enlargebufs(el, (size_t) count))
87                               return CC_ERROR;    /* error allocating more */
88           }
89 
90           if (count == 1) {
91                     if (el->el_state.inputmode == MODE_INSERT
92                         || el->el_line.cursor >= el->el_line.lastchar)
93                               c_insert(el, 1);
94 
95                     *el->el_line.cursor++ = c;
96                     re_fastaddc(el);              /* fast refresh for one char. */
97           } else {
98                     if (el->el_state.inputmode != MODE_REPLACE_1)
99                               c_insert(el, el->el_state.argument);
100 
101                     while (count-- && el->el_line.cursor < el->el_line.lastchar)
102                               *el->el_line.cursor++ = c;
103                     re_refresh(el);
104           }
105 
106           if (el->el_state.inputmode == MODE_REPLACE_1)
107                     return vi_command_mode(el, 0);
108 
109           return CC_NORM;
110 }
111 
112 
113 /* ed_delete_prev_word():
114  *        Delete from beginning of current word to cursor
115  *        [M-^?] [^W]
116  */
117 libedit_private el_action_t
118 /*ARGSUSED*/
ed_delete_prev_word(EditLine * el,wint_t c)119 ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
120 {
121           wchar_t *cp, *p, *kp;
122 
123           if (el->el_line.cursor == el->el_line.buffer)
124                     return CC_ERROR;
125 
126           cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
127               el->el_state.argument, ce__isword);
128 
129           for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
130                     *kp++ = *p;
131           el->el_chared.c_kill.last = kp;
132 
133           c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */
134           el->el_line.cursor = cp;
135           if (el->el_line.cursor < el->el_line.buffer)
136                     el->el_line.cursor = el->el_line.buffer; /* bounds check */
137           return CC_REFRESH;
138 }
139 
140 
141 /* ed_delete_next_char():
142  *        Delete character under cursor
143  *        [^D] [x]
144  */
145 libedit_private el_action_t
146 /*ARGSUSED*/
ed_delete_next_char(EditLine * el,wint_t c)147 ed_delete_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
148 {
149 #ifdef DEBUG_EDIT
150 #define   EL        el->el_line
151           (void) fprintf(el->el_errfile,
152               "\nD(b: %p(%ls)  c: %p(%ls) last: %p(%ls) limit: %p(%ls)\n",
153               EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
154               EL.lastchar, EL.limit, EL.limit);
155 #endif
156           if (el->el_line.cursor == el->el_line.lastchar) {
157                               /* if I'm at the end */
158                     if (el->el_map.type == MAP_VI) {
159                               if (el->el_line.cursor == el->el_line.buffer) {
160                                         /* if I'm also at the beginning */
161 #ifdef KSHVI
162                                         return CC_ERROR;
163 #else
164                                         /* then do an EOF */
165                                         terminal_writec(el, c);
166                                         return CC_EOF;
167 #endif
168                               } else {
169 #ifdef KSHVI
170                                         el->el_line.cursor--;
171 #else
172                                         return CC_ERROR;
173 #endif
174                               }
175                     } else
176                                         return CC_ERROR;
177           }
178           c_delafter(el, el->el_state.argument);  /* delete after dot */
179           if (el->el_map.type == MAP_VI &&
180               el->el_line.cursor >= el->el_line.lastchar &&
181               el->el_line.cursor > el->el_line.buffer)
182                               /* bounds check */
183                     el->el_line.cursor = el->el_line.lastchar - 1;
184           return CC_REFRESH;
185 }
186 
187 
188 /* ed_kill_line():
189  *        Cut to the end of line
190  *        [^K] [^K]
191  */
192 libedit_private el_action_t
193 /*ARGSUSED*/
ed_kill_line(EditLine * el,wint_t c)194 ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
195 {
196           wchar_t *kp, *cp;
197 
198           cp = el->el_line.cursor;
199           kp = el->el_chared.c_kill.buf;
200           while (cp < el->el_line.lastchar)
201                     *kp++ = *cp++;      /* copy it */
202           el->el_chared.c_kill.last = kp;
203                               /* zap! -- delete to end */
204           el->el_line.lastchar = el->el_line.cursor;
205           return CC_REFRESH;
206 }
207 
208 
209 /* ed_move_to_end():
210  *        Move cursor to the end of line
211  *        [^E] [^E]
212  */
213 libedit_private el_action_t
214 /*ARGSUSED*/
ed_move_to_end(EditLine * el,wint_t c)215 ed_move_to_end(EditLine *el, wint_t c __attribute__((__unused__)))
216 {
217 
218           el->el_line.cursor = el->el_line.lastchar;
219           if (el->el_map.type == MAP_VI) {
220                     if (el->el_chared.c_vcmd.action != NOP) {
221                               cv_delfini(el);
222                               return CC_REFRESH;
223                     }
224 #ifdef VI_MOVE
225                     el->el_line.cursor--;
226 #endif
227           }
228           return CC_CURSOR;
229 }
230 
231 
232 /* ed_move_to_beg():
233  *        Move cursor to the beginning of line
234  *        [^A] [^A]
235  */
236 libedit_private el_action_t
237 /*ARGSUSED*/
ed_move_to_beg(EditLine * el,wint_t c)238 ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
239 {
240 
241           el->el_line.cursor = el->el_line.buffer;
242 
243           if (el->el_map.type == MAP_VI) {
244                               /* We want FIRST non space character */
245                     while (iswspace(*el->el_line.cursor))
246                               el->el_line.cursor++;
247                     if (el->el_chared.c_vcmd.action != NOP) {
248                               cv_delfini(el);
249                               return CC_REFRESH;
250                     }
251           }
252           return CC_CURSOR;
253 }
254 
255 
256 /* ed_transpose_chars():
257  *        Exchange the character to the left of the cursor with the one under it
258  *        [^T] [^T]
259  */
260 libedit_private el_action_t
ed_transpose_chars(EditLine * el,wint_t c)261 ed_transpose_chars(EditLine *el, wint_t c)
262 {
263 
264           if (el->el_line.cursor < el->el_line.lastchar) {
265                     if (el->el_line.lastchar <= &el->el_line.buffer[1])
266                               return CC_ERROR;
267                     else
268                               el->el_line.cursor++;
269           }
270           if (el->el_line.cursor > &el->el_line.buffer[1]) {
271                     /* must have at least two chars entered */
272                     c = el->el_line.cursor[-2];
273                     el->el_line.cursor[-2] = el->el_line.cursor[-1];
274                     el->el_line.cursor[-1] = c;
275                     return CC_REFRESH;
276           } else
277                     return CC_ERROR;
278 }
279 
280 
281 /* ed_next_char():
282  *        Move to the right one character
283  *        [^F] [^F]
284  */
285 libedit_private el_action_t
286 /*ARGSUSED*/
ed_next_char(EditLine * el,wint_t c)287 ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
288 {
289           wchar_t *lim = el->el_line.lastchar;
290 
291           if (el->el_line.cursor >= lim ||
292               (el->el_line.cursor == lim - 1 &&
293               el->el_map.type == MAP_VI &&
294               el->el_chared.c_vcmd.action == NOP))
295                     return CC_ERROR;
296 
297           el->el_line.cursor += el->el_state.argument;
298           if (el->el_line.cursor > lim)
299                     el->el_line.cursor = lim;
300 
301           if (el->el_map.type == MAP_VI)
302                     if (el->el_chared.c_vcmd.action != NOP) {
303                               cv_delfini(el);
304                               return CC_REFRESH;
305                     }
306           return CC_CURSOR;
307 }
308 
309 
310 /* ed_prev_word():
311  *        Move to the beginning of the current word
312  *        [M-b] [b]
313  */
314 libedit_private el_action_t
315 /*ARGSUSED*/
ed_prev_word(EditLine * el,wint_t c)316 ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
317 {
318 
319           if (el->el_line.cursor == el->el_line.buffer)
320                     return CC_ERROR;
321 
322           el->el_line.cursor = c__prev_word(el->el_line.cursor,
323               el->el_line.buffer,
324               el->el_state.argument,
325               ce__isword);
326 
327           if (el->el_map.type == MAP_VI)
328                     if (el->el_chared.c_vcmd.action != NOP) {
329                               cv_delfini(el);
330                               return CC_REFRESH;
331                     }
332           return CC_CURSOR;
333 }
334 
335 
336 /* ed_prev_char():
337  *        Move to the left one character
338  *        [^B] [^B]
339  */
340 libedit_private el_action_t
341 /*ARGSUSED*/
ed_prev_char(EditLine * el,wint_t c)342 ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
343 {
344 
345           if (el->el_line.cursor > el->el_line.buffer) {
346                     el->el_line.cursor -= el->el_state.argument;
347                     if (el->el_line.cursor < el->el_line.buffer)
348                               el->el_line.cursor = el->el_line.buffer;
349 
350                     if (el->el_map.type == MAP_VI)
351                               if (el->el_chared.c_vcmd.action != NOP) {
352                                         cv_delfini(el);
353                                         return CC_REFRESH;
354                               }
355                     return CC_CURSOR;
356           } else
357                     return CC_ERROR;
358 }
359 
360 
361 /* ed_quoted_insert():
362  *        Add the next character typed verbatim
363  *        [^V] [^V]
364  */
365 libedit_private el_action_t
366 /*ARGSUSED*/
ed_quoted_insert(EditLine * el,wint_t c)367 ed_quoted_insert(EditLine *el, wint_t c __attribute__((__unused__)))
368 {
369           int num;
370           wchar_t ch;
371 
372           tty_quotemode(el);
373           num = el_wgetc(el, &ch);
374           tty_noquotemode(el);
375           if (num == 1)
376                     return ed_insert(el, ch);
377           else
378                     return ed_end_of_file(el, 0);
379 }
380 
381 
382 /* ed_digit():
383  *        Adds to argument or enters a digit
384  */
385 libedit_private el_action_t
ed_digit(EditLine * el,wint_t c)386 ed_digit(EditLine *el, wint_t c)
387 {
388 
389           if (!iswdigit(c))
390                     return CC_ERROR;
391 
392           if (el->el_state.doingarg) {
393                               /* if doing an arg, add this in... */
394                     if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
395                               el->el_state.argument = c - '0';
396                     else {
397                               if (el->el_state.argument > 1000000)
398                                         return CC_ERROR;
399                               el->el_state.argument =
400                                   (el->el_state.argument * 10) + (c - '0');
401                     }
402                     return CC_ARGHACK;
403           }
404 
405           return ed_insert(el, c);
406 }
407 
408 
409 /* ed_argument_digit():
410  *        Digit that starts argument
411  *        For ESC-n
412  */
413 libedit_private el_action_t
ed_argument_digit(EditLine * el,wint_t c)414 ed_argument_digit(EditLine *el, wint_t c)
415 {
416 
417           if (!iswdigit(c))
418                     return CC_ERROR;
419 
420           if (el->el_state.doingarg) {
421                     if (el->el_state.argument > 1000000)
422                               return CC_ERROR;
423                     el->el_state.argument = (el->el_state.argument * 10) +
424                         (c - '0');
425           } else {            /* else starting an argument */
426                     el->el_state.argument = c - '0';
427                     el->el_state.doingarg = 1;
428           }
429           return CC_ARGHACK;
430 }
431 
432 
433 /* ed_unassigned():
434  *        Indicates unbound character
435  *        Bound to keys that are not assigned
436  */
437 libedit_private el_action_t
438 /*ARGSUSED*/
ed_unassigned(EditLine * el,wint_t c)439 ed_unassigned(EditLine *el __attribute__((__unused__)),
440     wint_t c __attribute__((__unused__)))
441 {
442 
443           return CC_ERROR;
444 }
445 
446 
447 /* ed_ignore():
448  *        Input characters that have no effect
449  *        [^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
450  */
451 libedit_private el_action_t
452 /*ARGSUSED*/
ed_ignore(EditLine * el,wint_t c)453 ed_ignore(EditLine *el __attribute__((__unused__)),
454                 wint_t c __attribute__((__unused__)))
455 {
456 
457           return CC_NORM;
458 }
459 
460 
461 /* ed_newline():
462  *        Execute command
463  *        [^J]
464  */
465 libedit_private el_action_t
466 /*ARGSUSED*/
ed_newline(EditLine * el,wint_t c)467 ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
468 {
469 
470           re_goto_bottom(el);
471           *el->el_line.lastchar++ = '\n';
472           *el->el_line.lastchar = '\0';
473           return CC_NEWLINE;
474 }
475 
476 
477 /* ed_delete_prev_char():
478  *        Delete the character to the left of the cursor
479  *        [^?]
480  */
481 libedit_private el_action_t
482 /*ARGSUSED*/
ed_delete_prev_char(EditLine * el,wint_t c)483 ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
484 {
485 
486           if (el->el_line.cursor <= el->el_line.buffer)
487                     return CC_ERROR;
488 
489           c_delbefore(el, el->el_state.argument);
490           el->el_line.cursor -= el->el_state.argument;
491           if (el->el_line.cursor < el->el_line.buffer)
492                     el->el_line.cursor = el->el_line.buffer;
493           return CC_REFRESH;
494 }
495 
496 
497 /* ed_clear_screen():
498  *        Clear screen leaving current line at the top
499  *        [^L]
500  */
501 libedit_private el_action_t
502 /*ARGSUSED*/
ed_clear_screen(EditLine * el,wint_t c)503 ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
504 {
505 
506           terminal_clear_screen(el);    /* clear the whole real screen */
507           re_clear_display(el);         /* reset everything */
508           return CC_REFRESH;
509 }
510 
511 
512 /* ed_redisplay():
513  *        Redisplay everything
514  *        ^R
515  */
516 libedit_private el_action_t
517 /*ARGSUSED*/
ed_redisplay(EditLine * el,wint_t c)518 ed_redisplay(EditLine *el __attribute__((__unused__)),
519                wint_t c __attribute__((__unused__)))
520 {
521 
522           return CC_REDISPLAY;
523 }
524 
525 
526 /* ed_start_over():
527  *        Erase current line and start from scratch
528  *        [^G]
529  */
530 libedit_private el_action_t
531 /*ARGSUSED*/
ed_start_over(EditLine * el,wint_t c)532 ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
533 {
534 
535           ch_reset(el);
536           return CC_REFRESH;
537 }
538 
539 
540 /* ed_sequence_lead_in():
541  *        First character in a bound sequence
542  *        Placeholder for external keys
543  */
544 libedit_private el_action_t
545 /*ARGSUSED*/
ed_sequence_lead_in(EditLine * el,wint_t c)546 ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
547                         wint_t c __attribute__((__unused__)))
548 {
549 
550           return CC_NORM;
551 }
552 
553 
554 /* ed_prev_history():
555  *        Move to the previous history line
556  *        [^P] [k]
557  */
558 libedit_private el_action_t
559 /*ARGSUSED*/
ed_prev_history(EditLine * el,wint_t c)560 ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
561 {
562           char beep = 0;
563           int sv_event = el->el_history.eventno;
564 
565           el->el_chared.c_undo.len = -1;
566           *el->el_line.lastchar = '\0';           /* just in case */
567 
568           if (el->el_history.eventno == 0) {      /* save the current buffer
569                                                              * away */
570                     (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
571                         EL_BUFSIZ);
572                     el->el_history.last = el->el_history.buf +
573                         (el->el_line.lastchar - el->el_line.buffer);
574           }
575           el->el_history.eventno += el->el_state.argument;
576 
577           if (hist_get(el) == CC_ERROR) {
578                     if (el->el_map.type == MAP_VI) {
579                               el->el_history.eventno = sv_event;
580                     }
581                     beep = 1;
582                     /* el->el_history.eventno was fixed by first call */
583                     (void) hist_get(el);
584           }
585           if (beep)
586                     return CC_REFRESH_BEEP;
587           return CC_REFRESH;
588 }
589 
590 
591 /* ed_next_history():
592  *        Move to the next history line
593  *        [^N] [j]
594  */
595 libedit_private el_action_t
596 /*ARGSUSED*/
ed_next_history(EditLine * el,wint_t c)597 ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
598 {
599           el_action_t beep = CC_REFRESH, rval;
600 
601           el->el_chared.c_undo.len = -1;
602           *el->el_line.lastchar = '\0'; /* just in case */
603 
604           el->el_history.eventno -= el->el_state.argument;
605 
606           if (el->el_history.eventno < 0) {
607                     el->el_history.eventno = 0;
608                     beep = CC_REFRESH_BEEP;
609           }
610           rval = hist_get(el);
611           if (rval == CC_REFRESH)
612                     return beep;
613           return rval;
614 
615 }
616 
617 
618 /* ed_search_prev_history():
619  *        Search previous in history for a line matching the current
620  *        next search history [M-P] [K]
621  */
622 libedit_private el_action_t
623 /*ARGSUSED*/
ed_search_prev_history(EditLine * el,wint_t c)624 ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
625 {
626           const wchar_t *hp;
627           int h;
628           int found = 0;
629 
630           el->el_chared.c_vcmd.action = NOP;
631           el->el_chared.c_undo.len = -1;
632           *el->el_line.lastchar = '\0'; /* just in case */
633           if (el->el_history.eventno < 0) {
634 #ifdef DEBUG_EDIT
635                     (void) fprintf(el->el_errfile,
636                         "e_prev_search_hist(): eventno < 0;\n");
637 #endif
638                     el->el_history.eventno = 0;
639                     return CC_ERROR;
640           }
641           if (el->el_history.eventno == 0) {
642                     (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
643                         EL_BUFSIZ);
644                     el->el_history.last = el->el_history.buf +
645                         (el->el_line.lastchar - el->el_line.buffer);
646           }
647           if (el->el_history.ref == NULL)
648                     return CC_ERROR;
649 
650           hp = HIST_FIRST(el);
651           if (hp == NULL)
652                     return CC_ERROR;
653 
654           c_setpat(el);                 /* Set search pattern !! */
655 
656           for (h = 1; h <= el->el_history.eventno; h++)
657                     hp = HIST_NEXT(el);
658 
659           while (hp != NULL) {
660 #ifdef SDEBUG
661                     (void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
662 #endif
663                     if ((wcsncmp(hp, el->el_line.buffer, (size_t)
664                                   (el->el_line.lastchar - el->el_line.buffer)) ||
665                               hp[el->el_line.lastchar - el->el_line.buffer]) &&
666                         c_hmatch(el, hp)) {
667                               found = 1;
668                               break;
669                     }
670                     h++;
671                     hp = HIST_NEXT(el);
672           }
673 
674           if (!found) {
675 #ifdef SDEBUG
676                     (void) fprintf(el->el_errfile, "not found\n");
677 #endif
678                     return CC_ERROR;
679           }
680           el->el_history.eventno = h;
681 
682           return hist_get(el);
683 }
684 
685 
686 /* ed_search_next_history():
687  *        Search next in history for a line matching the current
688  *        [M-N] [J]
689  */
690 libedit_private el_action_t
691 /*ARGSUSED*/
ed_search_next_history(EditLine * el,wint_t c)692 ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
693 {
694           const wchar_t *hp;
695           int h;
696           int found = 0;
697 
698           el->el_chared.c_vcmd.action = NOP;
699           el->el_chared.c_undo.len = -1;
700           *el->el_line.lastchar = '\0'; /* just in case */
701 
702           if (el->el_history.eventno == 0)
703                     return CC_ERROR;
704 
705           if (el->el_history.ref == NULL)
706                     return CC_ERROR;
707 
708           hp = HIST_FIRST(el);
709           if (hp == NULL)
710                     return CC_ERROR;
711 
712           c_setpat(el);                 /* Set search pattern !! */
713 
714           for (h = 1; h < el->el_history.eventno && hp; h++) {
715 #ifdef SDEBUG
716                     (void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
717 #endif
718                     if ((wcsncmp(hp, el->el_line.buffer, (size_t)
719                                   (el->el_line.lastchar - el->el_line.buffer)) ||
720                               hp[el->el_line.lastchar - el->el_line.buffer]) &&
721                         c_hmatch(el, hp))
722                               found = h;
723                     hp = HIST_NEXT(el);
724           }
725 
726           if (!found) {                 /* is it the current history number? */
727                     if (!c_hmatch(el, el->el_history.buf)) {
728 #ifdef SDEBUG
729                               (void) fprintf(el->el_errfile, "not found\n");
730 #endif
731                               return CC_ERROR;
732                     }
733           }
734           el->el_history.eventno = found;
735 
736           return hist_get(el);
737 }
738 
739 
740 /* ed_prev_line():
741  *        Move up one line
742  *        Could be [k] [^p]
743  */
744 libedit_private el_action_t
745 /*ARGSUSED*/
ed_prev_line(EditLine * el,wint_t c)746 ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
747 {
748           wchar_t *ptr;
749           int nchars = c_hpos(el);
750 
751           /*
752          * Move to the line requested
753          */
754           if (*(ptr = el->el_line.cursor) == '\n')
755                     ptr--;
756 
757           for (; ptr >= el->el_line.buffer; ptr--)
758                     if (*ptr == '\n' && --el->el_state.argument <= 0)
759                               break;
760 
761           if (el->el_state.argument > 0)
762                     return CC_ERROR;
763 
764           /*
765          * Move to the beginning of the line
766          */
767           for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
768                     continue;
769 
770           /*
771          * Move to the character requested
772          */
773           for (ptr++;
774               nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
775               ptr++)
776                     continue;
777 
778           el->el_line.cursor = ptr;
779           return CC_CURSOR;
780 }
781 
782 
783 /* ed_next_line():
784  *        Move down one line
785  *        Could be [j] [^n]
786  */
787 libedit_private el_action_t
788 /*ARGSUSED*/
ed_next_line(EditLine * el,wint_t c)789 ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
790 {
791           wchar_t *ptr;
792           int nchars = c_hpos(el);
793 
794           /*
795          * Move to the line requested
796          */
797           for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
798                     if (*ptr == '\n' && --el->el_state.argument <= 0)
799                               break;
800 
801           if (el->el_state.argument > 0)
802                     return CC_ERROR;
803 
804           /*
805          * Move to the character requested
806          */
807           for (ptr++;
808               nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
809               ptr++)
810                     continue;
811 
812           el->el_line.cursor = ptr;
813           return CC_CURSOR;
814 }
815 
816 
817 /* ed_command():
818  *        Editline extended command
819  *        [M-X] [:]
820  */
821 libedit_private el_action_t
822 /*ARGSUSED*/
ed_command(EditLine * el,wint_t c)823 ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
824 {
825           wchar_t tmpbuf[EL_BUFSIZ];
826           int tmplen;
827 
828           tmplen = c_gets(el, tmpbuf, L"\n: ");
829           terminal__putc(el, '\n');
830 
831           if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
832                     terminal_beep(el);
833 
834           el->el_map.current = el->el_map.key;
835           re_clear_display(el);
836           return CC_REFRESH;
837 }
838