"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libedit/read.c" (4 Jul 2020, 13990 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "read.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

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