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