xref: /dragonfly/contrib/libedit/src/read.c (revision 698e9e6cd5f042847de67460caaa3fde98cdfe99)
1 /*        $NetBSD: read.c,v 1.107 2021/08/15 10:08:41 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[] = "@(#)read.c      8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: read.c,v 1.107 2021/08/15 10:08:41 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 
44 /*
45  * read.c: Terminal read functions
46  */
47 #include <ctype.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <limits.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 
55 #include "el.h"
56 #include "fcns.h"
57 #include "read.h"
58 
59 #define   EL_MAXMACRO         10
60 
61 struct macros {
62           wchar_t   **macro;
63           int         level;
64           int         offset;
65 };
66 
67 struct el_read_t {
68           struct macros        macros;
69           el_rfunc_t           read_char;         /* Function to read a character. */
70           int                  read_errno;
71 };
72 
73 static int          read__fixio(int, int);
74 static int          read_char(EditLine *, wchar_t *);
75 static int          read_getcmd(EditLine *, el_action_t *, wchar_t *);
76 static void         read_clearmacros(struct macros *);
77 static void         read_pop(struct macros *);
78 static const wchar_t *noedit_wgets(EditLine *, int *);
79 
80 /* read_init():
81  *        Initialize the read stuff
82  */
83 libedit_private int
read_init(EditLine * el)84 read_init(EditLine *el)
85 {
86           struct macros *ma;
87 
88           if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL)
89                     return -1;
90 
91           ma = &el->el_read->macros;
92           if ((ma->macro = el_calloc(EL_MAXMACRO, sizeof(*ma->macro))) == NULL) {
93                     free(el->el_read);
94                     return -1;
95           }
96           ma->level = -1;
97           ma->offset = 0;
98 
99           /* builtin read_char */
100           el->el_read->read_char = read_char;
101           return 0;
102 }
103 
104 /* el_read_end():
105  *        Free the data structures used by the read stuff.
106  */
107 libedit_private void
read_end(struct el_read_t * el_read)108 read_end(struct el_read_t *el_read)
109 {
110           read_clearmacros(&el_read->macros);
111           el_free(el_read->macros.macro);
112           el_read->macros.macro = NULL;
113           el_free(el_read);
114 }
115 
116 /* el_read_setfn():
117  *        Set the read char function to the one provided.
118  *        If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
119  */
120 libedit_private int
el_read_setfn(struct el_read_t * el_read,el_rfunc_t rc)121 el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc)
122 {
123           el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
124           return 0;
125 }
126 
127 
128 /* el_read_getfn():
129  *        return the current read char function, or EL_BUILTIN_GETCFN
130  *        if it is the default one
131  */
132 libedit_private el_rfunc_t
el_read_getfn(struct el_read_t * el_read)133 el_read_getfn(struct el_read_t *el_read)
134 {
135        return el_read->read_char == read_char ?
136               EL_BUILTIN_GETCFN : el_read->read_char;
137 }
138 
139 
140 /* read__fixio():
141  *        Try to recover from a read error
142  */
143 /* ARGSUSED */
144 static int
read__fixio(int fd,int e)145 read__fixio(int fd __attribute__((__unused__)), int e)
146 {
147 
148           switch (e) {
149           case -1:            /* Make sure that the code is reachable */
150 
151 #ifdef EWOULDBLOCK
152           case EWOULDBLOCK:
153 #ifndef TRY_AGAIN
154 #define TRY_AGAIN
155 #endif
156 #endif /* EWOULDBLOCK */
157 
158 #if defined(POSIX) && defined(EAGAIN)
159 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
160           case EAGAIN:
161 #ifndef TRY_AGAIN
162 #define TRY_AGAIN
163 #endif
164 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
165 #endif /* POSIX && EAGAIN */
166 
167                     e = 0;
168 #ifdef TRY_AGAIN
169 #if defined(F_SETFL) && defined(O_NDELAY)
170                     if ((e = fcntl(fd, F_GETFL, 0)) == -1)
171                               return -1;
172 
173                     if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
174                               return -1;
175                     else
176                               e = 1;
177 #endif /* F_SETFL && O_NDELAY */
178 
179 #ifdef FIONBIO
180                     {
181                               int zero = 0;
182 
183                               if (ioctl(fd, FIONBIO, &zero) == -1)
184                                         return -1;
185                               else
186                                         e = 1;
187                     }
188 #endif /* FIONBIO */
189 
190 #endif /* TRY_AGAIN */
191                     return e ? 0 : -1;
192 
193           case EINTR:
194                     return 0;
195 
196           default:
197                     return -1;
198           }
199 }
200 
201 
202 /* el_push():
203  *        Push a macro
204  */
205 void
el_wpush(EditLine * el,const wchar_t * str)206 el_wpush(EditLine *el, const wchar_t *str)
207 {
208           struct macros *ma = &el->el_read->macros;
209 
210           if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
211                     ma->level++;
212                     if ((ma->macro[ma->level] = wcsdup(str)) != NULL)
213                               return;
214                     ma->level--;
215           }
216           terminal_beep(el);
217           terminal__flush(el);
218 }
219 
220 
221 /* read_getcmd():
222  *        Get next command from the input stream,
223  *        return 0 on success or -1 on EOF or error.
224  *        Character values > 255 are not looked up in the map, but inserted.
225  */
226 static int
read_getcmd(EditLine * el,el_action_t * cmdnum,wchar_t * ch)227 read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch)
228 {
229           static const wchar_t meta = (wchar_t)0x80;
230           el_action_t cmd;
231 
232           do {
233                     if (el_wgetc(el, ch) != 1)
234                               return -1;
235 
236 #ifdef    KANJI
237                     if ((*ch & meta)) {
238                               el->el_state.metanext = 0;
239                               cmd = CcViMap[' '];
240                               break;
241                     } else
242 #endif /* KANJI */
243 
244                     if (el->el_state.metanext) {
245                               el->el_state.metanext = 0;
246                               *ch |= meta;
247                     }
248                     if (*ch >= N_KEYS)
249                               cmd = ED_INSERT;
250                     else
251                               cmd = el->el_map.current[(unsigned char) *ch];
252                     if (cmd == ED_SEQUENCE_LEAD_IN) {
253                               keymacro_value_t val;
254                               switch (keymacro_get(el, ch, &val)) {
255                               case XK_CMD:
256                                         cmd = val.cmd;
257                                         break;
258                               case XK_STR:
259                                         el_wpush(el, val.str);
260                                         break;
261                               case XK_NOD:
262                                         return -1;
263                               default:
264                                         EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
265                                         break;
266                               }
267                     }
268           } while (cmd == ED_SEQUENCE_LEAD_IN);
269           *cmdnum = cmd;
270           return 0;
271 }
272 
273 /* read_char():
274  *        Read a character from the tty.
275  */
276 static int
read_char(EditLine * el,wchar_t * cp)277 read_char(EditLine *el, wchar_t *cp)
278 {
279           ssize_t num_read;
280           int tried = (el->el_flags & FIXIO) == 0;
281           char cbuf[MB_LEN_MAX];
282           size_t cbp = 0;
283           int save_errno = errno;
284 
285  again:
286           el->el_signal->sig_no = 0;
287           while ((num_read = read(el->el_infd, cbuf + cbp, (size_t)1)) == -1) {
288                     int e = errno;
289                     switch (el->el_signal->sig_no) {
290                     case SIGCONT:
291                               el_wset(el, EL_REFRESH);
292                               /*FALLTHROUGH*/
293                     case SIGWINCH:
294                               sig_set(el);
295                               goto again;
296                     default:
297                               break;
298                     }
299                     if (!tried && read__fixio(el->el_infd, e) == 0) {
300                               errno = save_errno;
301                               tried = 1;
302                     } else {
303                               errno = e;
304                               *cp = L'\0';
305                               return -1;
306                     }
307           }
308 
309           /* Test for EOF */
310           if (num_read == 0) {
311                     *cp = L'\0';
312                     return 0;
313           }
314 
315           for (;;) {
316                     mbstate_t mbs;
317 
318                     ++cbp;
319                     /* This only works because UTF8 is stateless. */
320                     memset(&mbs, 0, sizeof(mbs));
321                     switch (mbrtowc(cp, cbuf, cbp, &mbs)) {
322                     case (size_t)-1:
323                               if (cbp > 1) {
324                                         /*
325                                          * Invalid sequence, discard all bytes
326                                          * except the last one.
327                                          */
328                                         cbuf[0] = cbuf[cbp - 1];
329                                         cbp = 0;
330                                         break;
331                               } else {
332                                         /* Invalid byte, discard it. */
333                                         cbp = 0;
334                                         goto again;
335                               }
336                     case (size_t)-2:
337                               if (cbp >= MB_LEN_MAX) {
338                                         errno = EILSEQ;
339                                         *cp = L'\0';
340                                         return -1;
341                               }
342                               /* Incomplete sequence, read another byte. */
343                               goto again;
344                     default:
345                               /* Valid character, process it. */
346                               return 1;
347                     }
348           }
349 }
350 
351 /* read_pop():
352  *        Pop a macro from the stack
353  */
354 static void
read_pop(struct macros * ma)355 read_pop(struct macros *ma)
356 {
357           int i;
358 
359           el_free(ma->macro[0]);
360           for (i = 0; i < ma->level; i++)
361                     ma->macro[i] = ma->macro[i + 1];
362           ma->level--;
363           ma->offset = 0;
364 }
365 
366 static void
read_clearmacros(struct macros * ma)367 read_clearmacros(struct macros *ma)
368 {
369           while (ma->level >= 0)
370                     el_free(ma->macro[ma->level--]);
371           ma->offset = 0;
372 }
373 
374 /* el_wgetc():
375  *        Read a wide character
376  */
377 int
el_wgetc(EditLine * el,wchar_t * cp)378 el_wgetc(EditLine *el, wchar_t *cp)
379 {
380           struct macros *ma = &el->el_read->macros;
381           int num_read;
382 
383           terminal__flush(el);
384           for (;;) {
385                     if (ma->level < 0)
386                               break;
387 
388                     if (ma->macro[0][ma->offset] == '\0') {
389                               read_pop(ma);
390                               continue;
391                     }
392 
393                     *cp = ma->macro[0][ma->offset++];
394 
395                     if (ma->macro[0][ma->offset] == '\0') {
396                               /* Needed for QuoteMode On */
397                               read_pop(ma);
398                     }
399 
400                     return 1;
401           }
402 
403           if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
404                     return 0;
405 
406           num_read = (*el->el_read->read_char)(el, cp);
407 
408           /*
409            * Remember the original reason of a read failure
410            * such that el_wgets() can restore it after doing
411            * various cleanup operation that might change errno.
412            */
413           if (num_read < 0)
414                     el->el_read->read_errno = errno;
415 
416           return num_read;
417 }
418 
419 libedit_private void
read_prepare(EditLine * el)420 read_prepare(EditLine *el)
421 {
422           if (el->el_flags & HANDLE_SIGNALS)
423                     sig_set(el);
424           if (el->el_flags & NO_TTY)
425                     return;
426           if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
427                     tty_rawmode(el);
428 
429           /* This is relatively cheap, and things go terribly wrong if
430              we have the wrong size. */
431           el_resize(el);
432           re_clear_display(el);         /* reset the display stuff */
433           ch_reset(el);
434           re_refresh(el);               /* print the prompt */
435 
436           if (el->el_flags & UNBUFFERED)
437                     terminal__flush(el);
438 }
439 
440 libedit_private void
read_finish(EditLine * el)441 read_finish(EditLine *el)
442 {
443           if ((el->el_flags & UNBUFFERED) == 0)
444                     (void) tty_cookedmode(el);
445           if (el->el_flags & HANDLE_SIGNALS)
446                     sig_clr(el);
447 }
448 
449 static const wchar_t *
noedit_wgets(EditLine * el,int * nread)450 noedit_wgets(EditLine *el, int *nread)
451 {
452           el_line_t *lp = &el->el_line;
453           int                  num;
454 
455           while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) {
456                     if (lp->lastchar + 1 >= lp->limit &&
457                         !ch_enlargebufs(el, (size_t)2))
458                               break;
459                     lp->lastchar++;
460                     if (el->el_flags & UNBUFFERED ||
461                         lp->lastchar[-1] == '\r' ||
462                         lp->lastchar[-1] == '\n')
463                               break;
464           }
465           if (num == -1 && errno == EINTR)
466                     lp->lastchar = lp->buffer;
467           lp->cursor = lp->lastchar;
468           *lp->lastchar = '\0';
469           *nread = (int)(lp->lastchar - lp->buffer);
470           return *nread ? lp->buffer : NULL;
471 }
472 
473 const wchar_t *
el_wgets(EditLine * el,int * nread)474 el_wgets(EditLine *el, int *nread)
475 {
476           int retval;
477           el_action_t cmdnum = 0;
478           int num;            /* how many chars we have read at NL */
479           wchar_t ch;
480           int nrb;
481 
482           if (nread == NULL)
483                     nread = &nrb;
484           *nread = 0;
485           el->el_read->read_errno = 0;
486 
487           if (el->el_flags & NO_TTY) {
488                     el->el_line.lastchar = el->el_line.buffer;
489                     return noedit_wgets(el, nread);
490           }
491 
492 #ifdef FIONREAD
493           if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) {
494                     int chrs = 0;
495 
496                     (void) ioctl(el->el_infd, FIONREAD, &chrs);
497                     if (chrs == 0) {
498                               if (tty_rawmode(el) < 0) {
499                                         errno = 0;
500                                         *nread = 0;
501                                         return NULL;
502                               }
503                     }
504           }
505 #endif /* FIONREAD */
506 
507           if ((el->el_flags & UNBUFFERED) == 0)
508                     read_prepare(el);
509 
510           if (el->el_flags & EDIT_DISABLED) {
511                     if ((el->el_flags & UNBUFFERED) == 0)
512                               el->el_line.lastchar = el->el_line.buffer;
513                     terminal__flush(el);
514                     return noedit_wgets(el, nread);
515           }
516 
517           for (num = -1; num == -1;) {  /* while still editing this line */
518                     /* if EOF or error */
519                     if (read_getcmd(el, &cmdnum, &ch) == -1)
520                               break;
521                     if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */
522                               continue; /* try again */
523                     /* now do the real command */
524                     /* vi redo needs these way down the levels... */
525                     el->el_state.thiscmd = cmdnum;
526                     el->el_state.thisch = ch;
527                     if (el->el_map.type == MAP_VI &&
528                         el->el_map.current == el->el_map.key &&
529                         el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
530                               if (cmdnum == VI_DELETE_PREV_CHAR &&
531                                   el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
532                                   && iswprint(el->el_chared.c_redo.pos[-1]))
533                                         el->el_chared.c_redo.pos--;
534                               else
535                                         *el->el_chared.c_redo.pos++ = ch;
536                     }
537                     retval = (*el->el_map.func[cmdnum]) (el, ch);
538 
539                     /* save the last command here */
540                     el->el_state.lastcmd = cmdnum;
541 
542                     /* use any return value */
543                     switch (retval) {
544                     case CC_CURSOR:
545                               re_refresh_cursor(el);
546                               break;
547 
548                     case CC_REDISPLAY:
549                               re_clear_lines(el);
550                               re_clear_display(el);
551                               /* FALLTHROUGH */
552 
553                     case CC_REFRESH:
554                               re_refresh(el);
555                               break;
556 
557                     case CC_REFRESH_BEEP:
558                               re_refresh(el);
559                               terminal_beep(el);
560                               break;
561 
562                     case CC_NORM:       /* normal char */
563                               break;
564 
565                     case CC_ARGHACK:    /* Suggested by Rich Salz */
566                               /* <rsalz@pineapple.bbn.com> */
567                               continue; /* keep going... */
568 
569                     case CC_EOF:        /* end of file typed */
570                               if ((el->el_flags & UNBUFFERED) == 0)
571                                         num = 0;
572                               else if (num == -1) {
573                                         *el->el_line.lastchar++ = CONTROL('d');
574                                         el->el_line.cursor = el->el_line.lastchar;
575                                         num = 1;
576                               }
577                               break;
578 
579                     case CC_NEWLINE:    /* normal end of line */
580                               num = (int)(el->el_line.lastchar - el->el_line.buffer);
581                               break;
582 
583                     case CC_FATAL:      /* fatal error, reset to known state */
584                               /* put (real) cursor in a known place */
585                               re_clear_display(el);         /* reset the display stuff */
586                               ch_reset(el);       /* reset the input pointers */
587                               read_clearmacros(&el->el_read->macros);
588                               re_refresh(el); /* print the prompt again */
589                               break;
590 
591                     case CC_ERROR:
592                     default:  /* functions we don't know about */
593                               terminal_beep(el);
594                               terminal__flush(el);
595                               break;
596                     }
597                     el->el_state.argument = 1;
598                     el->el_state.doingarg = 0;
599                     el->el_chared.c_vcmd.action = NOP;
600                     if (el->el_flags & UNBUFFERED)
601                               break;
602           }
603 
604           terminal__flush(el);                    /* flush any buffered output */
605           /* make sure the tty is set up correctly */
606           if ((el->el_flags & UNBUFFERED) == 0) {
607                     read_finish(el);
608                     *nread = num != -1 ? num : 0;
609           } else
610                     *nread = (int)(el->el_line.lastchar - el->el_line.buffer);
611 
612           if (*nread == 0) {
613                     if (num == -1) {
614                               *nread = -1;
615                               if (el->el_read->read_errno)
616                                         errno = el->el_read->read_errno;
617                     }
618                     return NULL;
619           } else
620                     return el->el_line.buffer;
621 }
622