1 /*        $NetBSD: common.c,v 1.50 2024/06/30 16:29:42 christos 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.50 2024/06/30 16:29:42 christos 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                     if (el->el_line.cursor > el->el_line.buffer)
226                               el->el_line.cursor--;
227 #endif
228           }
229           return CC_CURSOR;
230 }
231 
232 
233 /* ed_move_to_beg():
234  *        Move cursor to the beginning of line
235  *        [^A] [^A]
236  */
237 libedit_private el_action_t
238 /*ARGSUSED*/
ed_move_to_beg(EditLine * el,wint_t c)239 ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
240 {
241 
242           el->el_line.cursor = el->el_line.buffer;
243 
244           if (el->el_map.type == MAP_VI) {
245                               /* We want FIRST non space character */
246                     while (iswspace(*el->el_line.cursor))
247                               el->el_line.cursor++;
248                     if (el->el_chared.c_vcmd.action != NOP) {
249                               cv_delfini(el);
250                               return CC_REFRESH;
251                     }
252           }
253           return CC_CURSOR;
254 }
255 
256 
257 /* ed_transpose_chars():
258  *        Exchange the character to the left of the cursor with the one under it
259  *        [^T] [^T]
260  */
261 libedit_private el_action_t
ed_transpose_chars(EditLine * el,wint_t c)262 ed_transpose_chars(EditLine *el, wint_t c)
263 {
264 
265           if (el->el_line.cursor < el->el_line.lastchar) {
266                     if (el->el_line.lastchar <= &el->el_line.buffer[1])
267                               return CC_ERROR;
268                     else
269                               el->el_line.cursor++;
270           }
271           if (el->el_line.cursor > &el->el_line.buffer[1]) {
272                     /* must have at least two chars entered */
273                     c = el->el_line.cursor[-2];
274                     el->el_line.cursor[-2] = el->el_line.cursor[-1];
275                     el->el_line.cursor[-1] = c;
276                     return CC_REFRESH;
277           } else
278                     return CC_ERROR;
279 }
280 
281 
282 /* ed_next_char():
283  *        Move to the right one character
284  *        [^F] [^F]
285  */
286 libedit_private el_action_t
287 /*ARGSUSED*/
ed_next_char(EditLine * el,wint_t c)288 ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
289 {
290           wchar_t *lim = el->el_line.lastchar;
291 
292           if (el->el_line.cursor >= lim ||
293               (el->el_line.cursor == lim - 1 &&
294               el->el_map.type == MAP_VI &&
295               el->el_chared.c_vcmd.action == NOP))
296                     return CC_ERROR;
297 
298           el->el_line.cursor += el->el_state.argument;
299           if (el->el_line.cursor > lim)
300                     el->el_line.cursor = lim;
301 
302           if (el->el_map.type == MAP_VI)
303                     if (el->el_chared.c_vcmd.action != NOP) {
304                               cv_delfini(el);
305                               return CC_REFRESH;
306                     }
307           return CC_CURSOR;
308 }
309 
310 
311 /* ed_prev_word():
312  *        Move to the beginning of the current word
313  *        [M-b] [b]
314  */
315 libedit_private el_action_t
316 /*ARGSUSED*/
ed_prev_word(EditLine * el,wint_t c)317 ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
318 {
319 
320           if (el->el_line.cursor == el->el_line.buffer)
321                     return CC_ERROR;
322 
323           el->el_line.cursor = c__prev_word(el->el_line.cursor,
324               el->el_line.buffer,
325               el->el_state.argument,
326               ce__isword);
327 
328           if (el->el_map.type == MAP_VI)
329                     if (el->el_chared.c_vcmd.action != NOP) {
330                               cv_delfini(el);
331                               return CC_REFRESH;
332                     }
333           return CC_CURSOR;
334 }
335 
336 
337 /* ed_prev_char():
338  *        Move to the left one character
339  *        [^B] [^B]
340  */
341 libedit_private el_action_t
342 /*ARGSUSED*/
ed_prev_char(EditLine * el,wint_t c)343 ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
344 {
345 
346           if (el->el_line.cursor > el->el_line.buffer) {
347                     el->el_line.cursor -= el->el_state.argument;
348                     if (el->el_line.cursor < el->el_line.buffer)
349                               el->el_line.cursor = el->el_line.buffer;
350 
351                     if (el->el_map.type == MAP_VI)
352                               if (el->el_chared.c_vcmd.action != NOP) {
353                                         cv_delfini(el);
354                                         return CC_REFRESH;
355                               }
356                     return CC_CURSOR;
357           } else
358                     return CC_ERROR;
359 }
360 
361 
362 /* ed_quoted_insert():
363  *        Add the next character typed verbatim
364  *        [^V] [^V]
365  */
366 libedit_private el_action_t
367 /*ARGSUSED*/
ed_quoted_insert(EditLine * el,wint_t c)368 ed_quoted_insert(EditLine *el, wint_t c __attribute__((__unused__)))
369 {
370           int num;
371           wchar_t ch;
372 
373           tty_quotemode(el);
374           num = el_wgetc(el, &ch);
375           tty_noquotemode(el);
376           if (num == 1)
377                     return ed_insert(el, ch);
378           else
379                     return ed_end_of_file(el, 0);
380 }
381 
382 
383 /* ed_digit():
384  *        Adds to argument or enters a digit
385  */
386 libedit_private el_action_t
ed_digit(EditLine * el,wint_t c)387 ed_digit(EditLine *el, wint_t c)
388 {
389 
390           if (!iswdigit(c))
391                     return CC_ERROR;
392 
393           if (el->el_state.doingarg) {
394                               /* if doing an arg, add this in... */
395                     if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
396                               el->el_state.argument = c - '0';
397                     else {
398                               if (el->el_state.argument > 1000000)
399                                         return CC_ERROR;
400                               el->el_state.argument =
401                                   (el->el_state.argument * 10) + (c - '0');
402                     }
403                     return CC_ARGHACK;
404           }
405 
406           return ed_insert(el, c);
407 }
408 
409 
410 /* ed_argument_digit():
411  *        Digit that starts argument
412  *        For ESC-n
413  */
414 libedit_private el_action_t
ed_argument_digit(EditLine * el,wint_t c)415 ed_argument_digit(EditLine *el, wint_t c)
416 {
417 
418           if (!iswdigit(c))
419                     return CC_ERROR;
420 
421           if (el->el_state.doingarg) {
422                     if (el->el_state.argument > 1000000)
423                               return CC_ERROR;
424                     el->el_state.argument = (el->el_state.argument * 10) +
425                         (c - '0');
426           } else {            /* else starting an argument */
427                     el->el_state.argument = c - '0';
428                     el->el_state.doingarg = 1;
429           }
430           return CC_ARGHACK;
431 }
432 
433 
434 /* ed_unassigned():
435  *        Indicates unbound character
436  *        Bound to keys that are not assigned
437  */
438 libedit_private el_action_t
439 /*ARGSUSED*/
ed_unassigned(EditLine * el,wint_t c)440 ed_unassigned(EditLine *el __attribute__((__unused__)),
441     wint_t c __attribute__((__unused__)))
442 {
443 
444           return CC_ERROR;
445 }
446 
447 
448 /* ed_ignore():
449  *        Input characters that have no effect
450  *        [^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
451  */
452 libedit_private el_action_t
453 /*ARGSUSED*/
ed_ignore(EditLine * el,wint_t c)454 ed_ignore(EditLine *el __attribute__((__unused__)),
455                 wint_t c __attribute__((__unused__)))
456 {
457 
458           return CC_NORM;
459 }
460 
461 
462 /* ed_newline():
463  *        Execute command
464  *        [^J]
465  */
466 libedit_private el_action_t
467 /*ARGSUSED*/
ed_newline(EditLine * el,wint_t c)468 ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
469 {
470 
471           re_goto_bottom(el);
472           *el->el_line.lastchar++ = '\n';
473           *el->el_line.lastchar = '\0';
474           return CC_NEWLINE;
475 }
476 
477 
478 /* ed_delete_prev_char():
479  *        Delete the character to the left of the cursor
480  *        [^?]
481  */
482 libedit_private el_action_t
483 /*ARGSUSED*/
ed_delete_prev_char(EditLine * el,wint_t c)484 ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
485 {
486 
487           if (el->el_line.cursor <= el->el_line.buffer)
488                     return CC_ERROR;
489 
490           c_delbefore(el, el->el_state.argument);
491           el->el_line.cursor -= el->el_state.argument;
492           if (el->el_line.cursor < el->el_line.buffer)
493                     el->el_line.cursor = el->el_line.buffer;
494           return CC_REFRESH;
495 }
496 
497 
498 /* ed_clear_screen():
499  *        Clear screen leaving current line at the top
500  *        [^L]
501  */
502 libedit_private el_action_t
503 /*ARGSUSED*/
ed_clear_screen(EditLine * el,wint_t c)504 ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
505 {
506 
507           terminal_clear_screen(el);    /* clear the whole real screen */
508           re_clear_display(el);         /* reset everything */
509           return CC_REFRESH;
510 }
511 
512 
513 /* ed_redisplay():
514  *        Redisplay everything
515  *        ^R
516  */
517 libedit_private el_action_t
518 /*ARGSUSED*/
ed_redisplay(EditLine * el,wint_t c)519 ed_redisplay(EditLine *el __attribute__((__unused__)),
520                wint_t c __attribute__((__unused__)))
521 {
522 
523           return CC_REDISPLAY;
524 }
525 
526 
527 /* ed_start_over():
528  *        Erase current line and start from scratch
529  *        [^G]
530  */
531 libedit_private el_action_t
532 /*ARGSUSED*/
ed_start_over(EditLine * el,wint_t c)533 ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
534 {
535 
536           ch_reset(el);
537           return CC_REFRESH;
538 }
539 
540 
541 /* ed_sequence_lead_in():
542  *        First character in a bound sequence
543  *        Placeholder for external keys
544  */
545 libedit_private el_action_t
546 /*ARGSUSED*/
ed_sequence_lead_in(EditLine * el,wint_t c)547 ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
548                         wint_t c __attribute__((__unused__)))
549 {
550 
551           return CC_NORM;
552 }
553 
554 
555 /* ed_prev_history():
556  *        Move to the previous history line
557  *        [^P] [k]
558  */
559 libedit_private el_action_t
560 /*ARGSUSED*/
ed_prev_history(EditLine * el,wint_t c)561 ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
562 {
563           char beep = 0;
564           int sv_event = el->el_history.eventno;
565 
566           el->el_chared.c_undo.len = -1;
567           *el->el_line.lastchar = '\0';           /* just in case */
568 
569           if (el->el_history.eventno == 0) {      /* save the current buffer
570                                                              * away */
571                     (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
572                         EL_BUFSIZ);
573                     el->el_history.last = el->el_history.buf +
574                         (el->el_line.lastchar - el->el_line.buffer);
575           }
576           el->el_history.eventno += el->el_state.argument;
577 
578           if (hist_get(el) == CC_ERROR) {
579                     if (el->el_map.type == MAP_VI) {
580                               el->el_history.eventno = sv_event;
581                     }
582                     beep = 1;
583                     /* el->el_history.eventno was fixed by first call */
584                     (void) hist_get(el);
585           }
586           if (beep)
587                     return CC_REFRESH_BEEP;
588           return CC_REFRESH;
589 }
590 
591 
592 /* ed_next_history():
593  *        Move to the next history line
594  *        [^N] [j]
595  */
596 libedit_private el_action_t
597 /*ARGSUSED*/
ed_next_history(EditLine * el,wint_t c)598 ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
599 {
600           el_action_t beep = CC_REFRESH, rval;
601 
602           el->el_chared.c_undo.len = -1;
603           *el->el_line.lastchar = '\0'; /* just in case */
604 
605           el->el_history.eventno -= el->el_state.argument;
606 
607           if (el->el_history.eventno < 0) {
608                     el->el_history.eventno = 0;
609                     beep = CC_REFRESH_BEEP;
610           }
611           rval = hist_get(el);
612           if (rval == CC_REFRESH)
613                     return beep;
614           return rval;
615 
616 }
617 
618 
619 /* ed_search_prev_history():
620  *        Search previous in history for a line matching the current
621  *        next search history [M-P] [K]
622  */
623 libedit_private el_action_t
624 /*ARGSUSED*/
ed_search_prev_history(EditLine * el,wint_t c)625 ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
626 {
627           const wchar_t *hp;
628           int h;
629           int found = 0;
630 
631           el->el_chared.c_vcmd.action = NOP;
632           el->el_chared.c_undo.len = -1;
633           *el->el_line.lastchar = '\0'; /* just in case */
634           if (el->el_history.eventno < 0) {
635 #ifdef DEBUG_EDIT
636                     (void) fprintf(el->el_errfile,
637                         "e_prev_search_hist(): eventno < 0;\n");
638 #endif
639                     el->el_history.eventno = 0;
640                     return CC_ERROR;
641           }
642           if (el->el_history.eventno == 0) {
643                     (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
644                         EL_BUFSIZ);
645                     el->el_history.last = el->el_history.buf +
646                         (el->el_line.lastchar - el->el_line.buffer);
647           }
648           if (el->el_history.ref == NULL)
649                     return CC_ERROR;
650 
651           hp = HIST_FIRST(el);
652           if (hp == NULL)
653                     return CC_ERROR;
654 
655           c_setpat(el);                 /* Set search pattern !! */
656 
657           for (h = 1; h <= el->el_history.eventno; h++)
658                     hp = HIST_NEXT(el);
659 
660           while (hp != NULL) {
661 #ifdef SDEBUG
662                     (void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
663 #endif
664                     if ((wcsncmp(hp, el->el_line.buffer, (size_t)
665                                   (el->el_line.lastchar - el->el_line.buffer)) ||
666                               hp[el->el_line.lastchar - el->el_line.buffer]) &&
667                         c_hmatch(el, hp)) {
668                               found = 1;
669                               break;
670                     }
671                     h++;
672                     hp = HIST_NEXT(el);
673           }
674 
675           if (!found) {
676 #ifdef SDEBUG
677                     (void) fprintf(el->el_errfile, "not found\n");
678 #endif
679                     return CC_ERROR;
680           }
681           el->el_history.eventno = h;
682 
683           return hist_get(el);
684 }
685 
686 
687 /* ed_search_next_history():
688  *        Search next in history for a line matching the current
689  *        [M-N] [J]
690  */
691 libedit_private el_action_t
692 /*ARGSUSED*/
ed_search_next_history(EditLine * el,wint_t c)693 ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
694 {
695           const wchar_t *hp;
696           int h;
697           int found = 0;
698 
699           el->el_chared.c_vcmd.action = NOP;
700           el->el_chared.c_undo.len = -1;
701           *el->el_line.lastchar = '\0'; /* just in case */
702 
703           if (el->el_history.eventno == 0)
704                     return CC_ERROR;
705 
706           if (el->el_history.ref == NULL)
707                     return CC_ERROR;
708 
709           hp = HIST_FIRST(el);
710           if (hp == NULL)
711                     return CC_ERROR;
712 
713           c_setpat(el);                 /* Set search pattern !! */
714 
715           for (h = 1; h < el->el_history.eventno && hp; h++) {
716 #ifdef SDEBUG
717                     (void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
718 #endif
719                     if ((wcsncmp(hp, el->el_line.buffer, (size_t)
720                                   (el->el_line.lastchar - el->el_line.buffer)) ||
721                               hp[el->el_line.lastchar - el->el_line.buffer]) &&
722                         c_hmatch(el, hp))
723                               found = h;
724                     hp = HIST_NEXT(el);
725           }
726 
727           if (!found) {                 /* is it the current history number? */
728                     if (!c_hmatch(el, el->el_history.buf)) {
729 #ifdef SDEBUG
730                               (void) fprintf(el->el_errfile, "not found\n");
731 #endif
732                               return CC_ERROR;
733                     }
734           }
735           el->el_history.eventno = found;
736 
737           return hist_get(el);
738 }
739 
740 
741 /* ed_prev_line():
742  *        Move up one line
743  *        Could be [k] [^p]
744  */
745 libedit_private el_action_t
746 /*ARGSUSED*/
ed_prev_line(EditLine * el,wint_t c)747 ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
748 {
749           wchar_t *ptr;
750           int nchars = c_hpos(el);
751 
752           /*
753          * Move to the line requested
754          */
755           if (*(ptr = el->el_line.cursor) == '\n')
756                     ptr--;
757 
758           for (; ptr >= el->el_line.buffer; ptr--)
759                     if (*ptr == '\n' && --el->el_state.argument <= 0)
760                               break;
761 
762           if (el->el_state.argument > 0)
763                     return CC_ERROR;
764 
765           /*
766          * Move to the beginning of the line
767          */
768           for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
769                     continue;
770 
771           /*
772          * Move to the character requested
773          */
774           for (ptr++;
775               nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
776               ptr++)
777                     continue;
778 
779           el->el_line.cursor = ptr;
780           return CC_CURSOR;
781 }
782 
783 
784 /* ed_next_line():
785  *        Move down one line
786  *        Could be [j] [^n]
787  */
788 libedit_private el_action_t
789 /*ARGSUSED*/
ed_next_line(EditLine * el,wint_t c)790 ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
791 {
792           wchar_t *ptr;
793           int nchars = c_hpos(el);
794 
795           /*
796          * Move to the line requested
797          */
798           for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
799                     if (*ptr == '\n' && --el->el_state.argument <= 0)
800                               break;
801 
802           if (el->el_state.argument > 0)
803                     return CC_ERROR;
804 
805           /*
806          * Move to the character requested
807          */
808           for (ptr++;
809               nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
810               ptr++)
811                     continue;
812 
813           el->el_line.cursor = ptr;
814           return CC_CURSOR;
815 }
816 
817 
818 /* ed_command():
819  *        Editline extended command
820  *        [M-X] [:]
821  */
822 libedit_private el_action_t
823 /*ARGSUSED*/
ed_command(EditLine * el,wint_t c)824 ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
825 {
826           wchar_t tmpbuf[EL_BUFSIZ];
827           int tmplen;
828 
829           tmplen = c_gets(el, tmpbuf, L"\n: ");
830           terminal__putc(el, '\n');
831 
832           if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
833                     terminal_beep(el);
834 
835           el->el_map.current = el->el_map.key;
836           re_clear_display(el);
837           return CC_REFRESH;
838 }
839