From e889bca8dc1fe7ddb95651ecbe98ad05bd59e22e Mon Sep 17 00:00:00 2001 Message-Id: From: "Steffen \"Daode\" Nurpmeso" Date: Mon, 10 Sep 2012 15:50:58 +0200 Subject: [PATCH 1/3] Fix editline(3) char read and errno code flow The reading call chain failed to initialize local variables. From Mark Johnston (markjdb AT gmail DOT com). A return value from deeper in the chain was reused without localizing the meaning, which resulted in misinterpretation later on. And the tracking of errno in EditLine::el_errno, and vice versa, was also fixed. All this resulted in the requirement for a different way to control the edit loop, fixed by introduction of the new enum rcmd. With help from Christos Zoulas (christos AT zoulas DOT com). --- lib/libedit/read.c | 53 +++++++++++++++++++++++++++++++-------------------- 1 files changed, 32 insertions(+), 21 deletions(-) diff --git a/lib/libedit/read.c b/lib/libedit/read.c index 7d7f54b..0880b5c 100644 --- a/lib/libedit/read.c +++ b/lib/libedit/read.c @@ -49,13 +49,17 @@ __FBSDID("$FreeBSD$"); #include #include "el.h" -#define OKCMD -1 - -private int read__fixio(int, int); -private int read_preread(EditLine *); -private int read_char(EditLine *, char *); -private int read_getcmd(EditLine *, el_action_t *, char *); -private void read_pop(c_macro_t *); +enum rcmd { + OKCMD = -1, + EOFCMD = 0, + ERRCMD = 1 +}; + +private int read__fixio(int, int); +private int read_preread(EditLine *); +private int read_char(EditLine *, char *); +private enum rcmd read_getcmd(EditLine *, el_action_t *, char *); +private void read_pop(c_macro_t *); /* read_init(): * Initialize the read stuff @@ -227,9 +231,9 @@ el_push(EditLine *el, const char *str) /* read_getcmd(): - * Return next command from the input stream. + * Get next command from the input stream. */ -private int +private enum rcmd read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) { el_action_t cmd; @@ -238,8 +242,7 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) el->el_errno = 0; do { if ((num = el_getc(el, ch)) != 1) { /* if EOF or error */ - el->el_errno = num == 0 ? 0 : errno; - return (num); + return (num < 0 ? ERRCMD : EOFCMD); } #ifdef KANJI @@ -294,16 +297,18 @@ read_char(EditLine *el, char *cp) again: el->el_signal->sig_no = 0; - while ((num_read = read(el->el_infd, cp, 1)) == -1) { + while ((num_read = read(el->el_infd, cp, 1)) < 0) { + int e = errno; if (el->el_signal->sig_no == SIGCONT) { sig_set(el); el_set(el, EL_REFRESH); goto again; } - if (!tried && read__fixio(el->el_infd, errno) == 0) + if (!tried && read__fixio(el->el_infd, e) == 0) tried = 1; else { *cp = '\0'; + errno = e; return (-1); } } @@ -369,8 +374,9 @@ el_getc(EditLine *el, char *cp) (void) fprintf(el->el_errfile, "Reading a character\n"); #endif /* DEBUG_READ */ num_read = (*el->el_read.read_char)(el, cp); + el->el_errno = (num_read < 0) ? errno : 0; #ifdef DEBUG_READ - (void) fprintf(el->el_errfile, "Got it %c\n", *cp); + (void) fprintf(el->el_errfile, "Got <%c> (return %d)\n", *cp, num_read); #endif /* DEBUG_READ */ return (num_read); } @@ -426,7 +432,7 @@ el_gets(EditLine *el, int *nread) char *cp = el->el_line.buffer; size_t idx; - while ((*el->el_read.read_char)(el, cp) == 1) { + while ((num = (*el->el_read.read_char)(el, cp)) == 1) { /* make sure there is space for next character */ if (cp + 1 >= el->el_line.limit) { idx = (cp - el->el_line.buffer); @@ -479,7 +485,7 @@ el_gets(EditLine *el, int *nread) term__flush(el); - while ((*el->el_read.read_char)(el, cp) == 1) { + while ((num = (*el->el_read.read_char)(el, cp)) == 1) { /* make sure there is space next character */ if (cp + 1 >= el->el_line.limit) { idx = (cp - el->el_line.buffer); @@ -504,13 +510,14 @@ el_gets(EditLine *el, int *nread) goto done; } - for (num = OKCMD; num == OKCMD;) { /* while still editing this - * line */ + /* While still editing this line */ + for (num = 0;; num = 0) { + enum rcmd rcmd; #ifdef DEBUG_EDIT read_debug(el); #endif /* DEBUG_EDIT */ - /* if EOF or error */ - if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { + if ((rcmd = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { + num = (rcmd == ERRCMD) ? -1 : 0; #ifdef DEBUG_READ (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num); @@ -589,9 +596,10 @@ el_gets(EditLine *el, int *nread) continue; /* keep going... */ case CC_EOF: /* end of file typed */ + rcmd = EOFCMD; if ((el->el_flags & UNBUFFERED) == 0) num = 0; - else if (num == -1) { + else { *el->el_line.lastchar++ = CONTROL('d'); el->el_line.cursor = el->el_line.lastchar; num = 1; @@ -599,6 +607,7 @@ el_gets(EditLine *el, int *nread) break; case CC_NEWLINE: /* normal end of line */ + rcmd = EOFCMD; num = (int)(el->el_line.lastchar - el->el_line.buffer); break; @@ -628,6 +637,8 @@ el_gets(EditLine *el, int *nread) el->el_chared.c_vcmd.action = NOP; if (el->el_flags & UNBUFFERED) break; + if (rcmd != OKCMD) + break; } term__flush(el); /* flush any buffered output */ -- 1.7.9.rc2.1.g69204