diff options
Diffstat (limited to 'read.c')
-rw-r--r-- | read.c | 409 |
1 files changed, 150 insertions, 259 deletions
@@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos Exp $ */ +/* $NetBSD: read.c,v 1.103 2017/06/27 23:24:19 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,13 +37,12 @@ #if 0 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos Exp $"); +__RCSID("$NetBSD: read.c,v 1.103 2017/06/27 23:24:19 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* - * read.c: Clean this junk up! This is horrible code. - * Terminal read functions + * read.c: Terminal read functions */ #include <ctype.h> #include <errno.h> @@ -54,35 +53,75 @@ __RCSID("$NetBSD: read.c,v 1.86 2016/03/02 19:24:20 christos Exp $"); #include <unistd.h> #include "el.h" - -#define OKCMD -1 /* must be -1! */ - -private int read__fixio(int, int); -private int read_preread(EditLine *); -private int read_char(EditLine *, wchar_t *); -private int read_getcmd(EditLine *, el_action_t *, Char *); -private void read_pop(c_macro_t *); +#include "fcns.h" +#include "read.h" + +#define EL_MAXMACRO 10 + +struct macros { + wchar_t **macro; + int level; + int offset; +}; + +struct el_read_t { + struct macros macros; + el_rfunc_t read_char; /* Function to read a character. */ + int read_errno; +}; + +static int read__fixio(int, int); +static int read_char(EditLine *, wchar_t *); +static int read_getcmd(EditLine *, el_action_t *, wchar_t *); +static void read_clearmacros(struct macros *); +static void read_pop(struct macros *); +static const wchar_t *noedit_wgets(EditLine *, int *); /* read_init(): * Initialize the read stuff */ -protected int +libedit_private int read_init(EditLine *el) { + struct macros *ma; + + if ((el->el_read = el_malloc(sizeof(*el->el_read))) == NULL) + return -1; + + ma = &el->el_read->macros; + if ((ma->macro = el_malloc(EL_MAXMACRO * + sizeof(*ma->macro))) == NULL) { + free(el->el_read); + return -1; + } + ma->level = -1; + ma->offset = 0; + /* builtin read_char */ - el->el_read.read_char = read_char; + el->el_read->read_char = read_char; return 0; } +/* el_read_end(): + * Free the data structures used by the read stuff. + */ +libedit_private void +read_end(struct el_read_t *el_read) +{ + read_clearmacros(&el_read->macros); + el_free(el_read->macros.macro); + el_read->macros.macro = NULL; + el_free(el_read); +} /* el_read_setfn(): * Set the read char function to the one provided. * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one. */ -protected int -el_read_setfn(EditLine *el, el_rfunc_t rc) +libedit_private int +el_read_setfn(struct el_read_t *el_read, el_rfunc_t rc) { - el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc; + el_read->read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc; return 0; } @@ -91,42 +130,19 @@ el_read_setfn(EditLine *el, el_rfunc_t rc) * return the current read char function, or EL_BUILTIN_GETCFN * if it is the default one */ -protected el_rfunc_t -el_read_getfn(EditLine *el) +libedit_private el_rfunc_t +el_read_getfn(struct el_read_t *el_read) { - return el->el_read.read_char == read_char ? - EL_BUILTIN_GETCFN : el->el_read.read_char; + return el_read->read_char == read_char ? + EL_BUILTIN_GETCFN : el_read->read_char; } -#ifndef MIN -#define MIN(A,B) ((A) < (B) ? (A) : (B)) -#endif - -#ifdef DEBUG_EDIT -private void -read_debug(EditLine *el) -{ - - if (el->el_line.cursor > el->el_line.lastchar) - (void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); - if (el->el_line.cursor < el->el_line.buffer) - (void) fprintf(el->el_errfile, "cursor < buffer\r\n"); - if (el->el_line.cursor > el->el_line.limit) - (void) fprintf(el->el_errfile, "cursor > limit\r\n"); - if (el->el_line.lastchar > el->el_line.limit) - (void) fprintf(el->el_errfile, "lastchar > limit\r\n"); - if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) - (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); -} -#endif /* DEBUG_EDIT */ - - /* read__fixio(): * Try to recover from a read error */ /* ARGSUSED */ -private int +static int read__fixio(int fd __attribute__((__unused__)), int e) { @@ -184,49 +200,17 @@ read__fixio(int fd __attribute__((__unused__)), int e) } -/* read_preread(): - * Try to read the stuff in the input queue; - */ -private int -read_preread(EditLine *el) -{ - int chrs = 0; - - if (el->el_tty.t_mode == ED_IO) - return 0; - -#ifndef WIDECHAR -/* FIONREAD attempts to buffer up multiple bytes, and to make that work - * properly with partial wide/UTF-8 characters would need some careful work. */ -#ifdef FIONREAD - (void) ioctl(el->el_infd, FIONREAD, &chrs); - if (chrs > 0) { - char buf[EL_BUFSIZ]; - - chrs = read(el->el_infd, buf, - (size_t) MIN(chrs, EL_BUFSIZ - 1)); - if (chrs > 0) { - buf[chrs] = '\0'; - el_push(el, buf); - } - } -#endif /* FIONREAD */ -#endif - return chrs > 0; -} - - /* el_push(): * Push a macro */ -public void -FUN(el,push)(EditLine *el, const Char *str) +void +el_wpush(EditLine *el, const wchar_t *str) { - c_macro_t *ma = &el->el_chared.c_macro; + struct macros *ma = &el->el_read->macros; if (str != NULL && ma->level + 1 < EL_MAXMACRO) { ma->level++; - if ((ma->macro[ma->level] = Strdup(str)) != NULL) + if ((ma->macro[ma->level] = wcsdup(str)) != NULL) return; ma->level--; } @@ -236,24 +220,19 @@ FUN(el,push)(EditLine *el, const Char *str) /* read_getcmd(): - * Get next command from the input stream, return OKCMD on success. + * Get next command from the input stream, + * return 0 on success or -1 on EOF or error. * Character values > 255 are not looked up in the map, but inserted. */ -private int -read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) +static int +read_getcmd(EditLine *el, el_action_t *cmdnum, wchar_t *ch) { - static const Char meta = (Char)0x80; + static const wchar_t meta = (wchar_t)0x80; el_action_t cmd; - wchar_t wc; - int num; - el->el_errno = 0; do { - if ((num = el_wgetc(el, &wc)) != 1) {/* if EOF or error */ - el->el_errno = num == 0 ? 0 : errno; - return 0; /* not OKCMD */ - } - *ch = (Char)wc; + if (el_wgetc(el, ch) != 1) + return -1; #ifdef KANJI if ((*ch & meta)) { @@ -267,11 +246,9 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) el->el_state.metanext = 0; *ch |= meta; } -#ifdef WIDECHAR if (*ch >= N_KEYS) cmd = ED_INSERT; else -#endif cmd = el->el_map.current[(unsigned char) *ch]; if (cmd == ED_SEQUENCE_LEAD_IN) { keymacro_value_t val; @@ -280,30 +257,24 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, Char *ch) cmd = val.cmd; break; case XK_STR: - FUN(el,push)(el, val.str); - break; -#ifdef notyet - case XK_EXE: - /* XXX: In the future to run a user function */ - RunCommand(val.str); + el_wpush(el, val.str); break; -#endif + case XK_NOD: + return -1; default: EL_ABORT((el->el_errfile, "Bad XK_ type \n")); break; } } - if (el->el_map.alt == NULL) - el->el_map.current = el->el_map.key; } while (cmd == ED_SEQUENCE_LEAD_IN); *cmdnum = cmd; - return OKCMD; + return 0; } /* read_char(): * Read a character from the tty. */ -private int +static int read_char(EditLine *el, wchar_t *cp) { ssize_t num_read; @@ -318,7 +289,7 @@ read_char(EditLine *el, wchar_t *cp) int e = errno; switch (el->el_signal->sig_no) { case SIGCONT: - FUN(el,set)(el, EL_REFRESH); + el_wset(el, EL_REFRESH); /*FALLTHROUGH*/ case SIGWINCH: sig_set(el); @@ -343,9 +314,12 @@ read_char(EditLine *el, wchar_t *cp) } for (;;) { + mbstate_t mbs; ++cbp; - switch (ct_mbrtowc(cp, cbuf, cbp)) { + /* This only works because UTF8 is stateless. */ + memset(&mbs, 0, sizeof(mbs)); + switch (mbrtowc(cp, cbuf, cbp, &mbs)) { case (size_t)-1: if (cbp > 1) { /* @@ -384,8 +358,8 @@ read_char(EditLine *el, wchar_t *cp) /* read_pop(): * Pop a macro from the stack */ -private void -read_pop(c_macro_t *ma) +static void +read_pop(struct macros *ma) { int i; @@ -396,22 +370,25 @@ read_pop(c_macro_t *ma) ma->offset = 0; } +static void +read_clearmacros(struct macros *ma) +{ + while (ma->level >= 0) + el_free(ma->macro[ma->level--]); + ma->offset = 0; +} + /* el_wgetc(): * Read a wide character */ -public int +int el_wgetc(EditLine *el, wchar_t *cp) { + struct macros *ma = &el->el_read->macros; int num_read; - c_macro_t *ma = &el->el_chared.c_macro; terminal__flush(el); for (;;) { - if (ma->level < 0) { - if (!read_preread(el)) - break; - } - if (ma->level < 0) break; @@ -430,25 +407,23 @@ el_wgetc(EditLine *el, wchar_t *cp) return 1; } -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Turning raw mode on\n"); -#endif /* DEBUG_READ */ if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */ return 0; -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Reading a character\n"); -#endif /* DEBUG_READ */ - num_read = (*el->el_read.read_char)(el, cp); + num_read = (*el->el_read->read_char)(el, cp); + + /* + * Remember the original reason of a read failure + * such that el_wgets() can restore it after doing + * various cleanup operation that might change errno. + */ if (num_read < 0) - el->el_errno = errno; -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Got it %lc\n", *cp); -#endif /* DEBUG_READ */ + el->el_read->read_errno = errno; + return num_read; } -protected void +libedit_private void read_prepare(EditLine *el) { if (el->el_flags & HANDLE_SIGNALS) @@ -462,14 +437,14 @@ read_prepare(EditLine *el) we have the wrong size. */ el_resize(el); re_clear_display(el); /* reset the display stuff */ - ch_reset(el, 0); + ch_reset(el); re_refresh(el); /* print the prompt */ if (el->el_flags & UNBUFFERED) terminal__flush(el); } -protected void +libedit_private void read_finish(EditLine *el) { if ((el->el_flags & UNBUFFERED) == 0) @@ -478,56 +453,52 @@ read_finish(EditLine *el) sig_clr(el); } -public const Char * -FUN(el,gets)(EditLine *el, int *nread) +static const wchar_t * +noedit_wgets(EditLine *el, int *nread) +{ + el_line_t *lp = &el->el_line; + int num; + + while ((num = (*el->el_read->read_char)(el, lp->lastchar)) == 1) { + if (lp->lastchar + 1 >= lp->limit && + !ch_enlargebufs(el, (size_t)2)) + break; + lp->lastchar++; + if (el->el_flags & UNBUFFERED || + lp->lastchar[-1] == '\r' || + lp->lastchar[-1] == '\n') + break; + } + if (num == -1 && errno == EINTR) + lp->lastchar = lp->buffer; + lp->cursor = lp->lastchar; + *lp->lastchar = '\0'; + *nread = (int)(lp->lastchar - lp->buffer); + return *nread ? lp->buffer : NULL; +} + +const wchar_t * +el_wgets(EditLine *el, int *nread) { int retval; el_action_t cmdnum = 0; int num; /* how many chars we have read at NL */ - wchar_t wc; - Char ch, *cp; - int crlf = 0; + wchar_t ch; int nrb; -#ifdef FIONREAD - c_macro_t *ma = &el->el_chared.c_macro; -#endif /* FIONREAD */ if (nread == NULL) nread = &nrb; *nread = 0; + el->el_read->read_errno = 0; if (el->el_flags & NO_TTY) { - size_t idx; - - cp = el->el_line.buffer; - while ((num = (*el->el_read.read_char)(el, &wc)) == 1) { - *cp = (Char)wc; - /* make sure there is space for next character */ - if (cp + 1 >= el->el_line.limit) { - idx = (size_t)(cp - el->el_line.buffer); - if (!ch_enlargebufs(el, (size_t)2)) - break; - cp = &el->el_line.buffer[idx]; - } - cp++; - if (el->el_flags & UNBUFFERED) - break; - if (cp[-1] == '\r' || cp[-1] == '\n') - break; - } - if (num == -1) { - if (errno == EINTR) - cp = el->el_line.buffer; - el->el_errno = errno; - } - - goto noedit; + el->el_line.lastchar = el->el_line.buffer; + return noedit_wgets(el, nread); } - #ifdef FIONREAD - if (el->el_tty.t_mode == EX_IO && ma->level < 0) { - long chrs = 0; + if (el->el_tty.t_mode == EX_IO && el->el_read->macros.level < 0) { + int chrs = 0; (void) ioctl(el->el_infd, FIONREAD, &chrs); if (chrs == 0) { @@ -544,83 +515,19 @@ FUN(el,gets)(EditLine *el, int *nread) read_prepare(el); if (el->el_flags & EDIT_DISABLED) { - size_t idx; - if ((el->el_flags & UNBUFFERED) == 0) - cp = el->el_line.buffer; - else - cp = el->el_line.lastchar; - + el->el_line.lastchar = el->el_line.buffer; terminal__flush(el); - - while ((num = (*el->el_read.read_char)(el, &wc)) == 1) { - *cp = (Char)wc; - /* make sure there is space next character */ - if (cp + 1 >= el->el_line.limit) { - idx = (size_t)(cp - el->el_line.buffer); - if (!ch_enlargebufs(el, (size_t)2)) - break; - cp = &el->el_line.buffer[idx]; - } - cp++; - crlf = cp[-1] == '\r' || cp[-1] == '\n'; - if (el->el_flags & UNBUFFERED) - break; - if (crlf) - break; - } - - if (num == -1) { - if (errno == EINTR) - cp = el->el_line.buffer; - el->el_errno = errno; - } - - goto noedit; + return noedit_wgets(el, nread); } - for (num = OKCMD; num == OKCMD;) { /* while still editing this - * line */ -#ifdef DEBUG_EDIT - read_debug(el); -#endif /* DEBUG_EDIT */ + for (num = -1; num == -1;) { /* while still editing this line */ /* if EOF or error */ - if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { - num = -1; -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "Returning from el_gets %d\n", num); -#endif /* DEBUG_READ */ + if (read_getcmd(el, &cmdnum, &ch) == -1) break; - } - if (el->el_errno == EINTR) { - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = - el->el_line.cursor = el->el_line.buffer; - break; - } - if ((size_t)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ -#ifdef DEBUG_EDIT - (void) fprintf(el->el_errfile, - "ERROR: illegal command from key 0%o\r\n", ch); -#endif /* DEBUG_EDIT */ + if ((size_t)cmdnum >= el->el_map.nfunc) /* BUG CHECK command */ continue; /* try again */ - } /* now do the real command */ -#ifdef DEBUG_READ - { - el_bindings_t *b; - for (b = el->el_map.help; b->name; b++) - if (b->func == cmdnum) - break; - if (b->name) - (void) fprintf(el->el_errfile, - "Executing " FSTR "\n", b->name); - else - (void) fprintf(el->el_errfile, - "Error command = %d\n", cmdnum); - } -#endif /* DEBUG_READ */ /* vi redo needs these way down the levels... */ el->el_state.thiscmd = cmdnum; el->el_state.thisch = ch; @@ -629,16 +536,12 @@ FUN(el,gets)(EditLine *el, int *nread) el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { if (cmdnum == VI_DELETE_PREV_CHAR && el->el_chared.c_redo.pos != el->el_chared.c_redo.buf - && Isprint(el->el_chared.c_redo.pos[-1])) + && iswprint(el->el_chared.c_redo.pos[-1])) el->el_chared.c_redo.pos--; else *el->el_chared.c_redo.pos++ = ch; } retval = (*el->el_map.func[cmdnum]) (el, ch); -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "Returned state %d\n", retval ); -#endif /* DEBUG_READ */ /* save the last command here */ el->el_state.lastcmd = cmdnum; @@ -685,22 +588,15 @@ FUN(el,gets)(EditLine *el, int *nread) break; case CC_FATAL: /* fatal error, reset to known state */ -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "*** editor fatal ERROR ***\r\n\n"); -#endif /* DEBUG_READ */ /* put (real) cursor in a known place */ re_clear_display(el); /* reset the display stuff */ - ch_reset(el, 1); /* reset the input pointers */ + ch_reset(el); /* reset the input pointers */ + read_clearmacros(&el->el_read->macros); re_refresh(el); /* print the prompt again */ break; case CC_ERROR: default: /* functions we don't know about */ -#ifdef DEBUG_READ - (void) fprintf(el->el_errfile, - "*** editor ERROR ***\r\n\n"); -#endif /* DEBUG_READ */ terminal_beep(el); terminal__flush(el); break; @@ -717,19 +613,14 @@ FUN(el,gets)(EditLine *el, int *nread) if ((el->el_flags & UNBUFFERED) == 0) { read_finish(el); *nread = num != -1 ? num : 0; - } else { + } else *nread = (int)(el->el_line.lastchar - el->el_line.buffer); - } - goto done; -noedit: - el->el_line.cursor = el->el_line.lastchar = cp; - *cp = '\0'; - *nread = (int)(el->el_line.cursor - el->el_line.buffer); -done: + if (*nread == 0) { if (num == -1) { *nread = -1; - errno = el->el_errno; + if (el->el_read->read_errno) + errno = el->el_read->read_errno; } return NULL; } else |