Subject: bin/1502: Bourne Shell does not honor -v flag in scripts
To: None <gnats-bugs@gnats.netbsd.org>
From: Christos Zoulas <christos@deshaw.com>
List: netbsd-bugs
Date: 09/24/1995 23:24:05
>Number: 1502
>Category: bin
>Synopsis: Bourne Shell does not honor -v flag in scripts
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Sep 25 11:35:01 1995
>Last-Modified:
>Originator: Christos Zoulas
>Organization:
Chaos
>Release: Sun Sep 24 19:15:40 EDT 1995
>Environment:
System: NetBSD ramoth 1.0A NetBSD 1.0A (ZEOS_AIC) #53: Wed Jul 19 14:26:39 EDT 1995 christos@ramoth:/tmp_mnt/src/NetBSD/NetBSD-current/src/sys/arch/i386/compile/ZEOS_AIC i386
>Description:
/bin/sh does not honor the -v [verbose flag] in scripts because
it reads as much as it can at a time instead of a line at a time.
There is a comment in the source that indicates that the author
knows about the bug...
>How-To-Repeat:
Run the following script
# cat > foo.sh
set -v
echo foo
set -o
^D
sh foo.sh
>Fix:
Keep an extra pointer to the end of the current line, and process
only the part of the buffer up to that pointer.
*** input.c.dist Fri Jun 9 05:53:04 1995
--- input.c Sun Sep 24 19:22:43 1995
***************
*** 74,79 ****
--- 74,80 ----
struct strpush *prev; /* preceding string on stack */
char *prevstring;
int prevnleft;
+ int prevlleft;
struct alias *ap; /* if push was associated with an alias */
};
***************
*** 87,93 ****
struct parsefile *prev; /* preceding file on stack */
int linno; /* current line */
int fd; /* file descriptor (or -1 if string) */
! int nleft; /* number of chars left in buffer */
char *nextc; /* next char in buffer */
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
--- 88,95 ----
struct parsefile *prev; /* preceding file on stack */
int linno; /* current line */
int fd; /* file descriptor (or -1 if string) */
! int nleft; /* number of chars left in this line */
! int lleft; /* number of chars left in this buffer */
char *nextc; /* next char in buffer */
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
***************
*** 97,102 ****
--- 99,105 ----
int plinno = 1; /* input line number */
MKINIT int parsenleft; /* copy of parsefile->nleft */
+ MKINIT int parselleft; /* copy of parsefile->nleft */
char *parsenextc; /* copy of parsefile->nextc */
MKINIT struct parsefile basepf; /* top level input file */
char basebuf[BUFSIZ]; /* buffer for top level input file */
***************
*** 109,114 ****
--- 112,118 ----
EditLine *el; /* cookie for editline package */
STATIC void pushfile __P((void));
+ static int pread __P((void));
#ifdef mkinit
INCLUDE "input.h"
***************
*** 122,128 ****
RESET {
if (exception != EXSHELLPROC)
! parsenleft = 0; /* clear input buffer */
popallfiles();
}
--- 126,132 ----
RESET {
if (exception != EXSHELLPROC)
! parselleft = parsenleft = 0; /* clear input buffer */
popallfiles();
}
***************
*** 168,224 ****
*/
int
! pgetc() {
return pgetc_macro();
}
! /*
! * Refill the input buffer and return the next input character:
! *
! * 1) If a string was pushed back on the input, pop it;
! * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
! * from a string so we can't refill the buffer, return EOF.
! * 3) Call read to read in the characters.
! * 4) Delete all nul characters from the buffer.
! */
!
! int
! preadbuffer() {
! register char *p, *q;
! register int i;
! register int something;
! extern EditLine *el;
- if (parsefile->strpush) {
- popstring();
- if (--parsenleft >= 0)
- return (*parsenextc++);
- }
- if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
- return PEOF;
- flushout(&output);
- flushout(&errout);
retry:
- p = parsenextc = parsefile->buf;
if (parsefile->fd == 0 && el) {
const char *rl_cp;
int len;
! rl_cp = el_gets(el, &len);
! if (rl_cp == NULL) {
! i = 0;
! goto eof;
}
- strcpy(p, rl_cp); /* XXX - BUFSIZE should redesign so not necessary */
- i = len;
-
} else {
! i = read(parsefile->fd, p, BUFSIZ - 1);
}
! eof:
! if (i <= 0) {
! if (i < 0) {
if (errno == EINTR)
goto retry;
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
--- 172,207 ----
*/
int
! pgetc()
! {
return pgetc_macro();
}
! static int
! pread()
! {
! int nr;
! parsenextc = parsefile->buf;
retry:
if (parsefile->fd == 0 && el) {
const char *rl_cp;
int len;
! rl_cp = el_gets(el, &parsenleft);
! if (rl_cp == NULL)
! nr = 0;
! else {
! /* XXX - BUFSIZE should redesign so not necessary */
! (void) strcpy(parsenextc, rl_cp);
}
} else {
! nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
}
!
! if (nr <= 0) {
! if (nr < 0) {
if (errno == EINTR)
goto retry;
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
***************
*** 232,288 ****
}
}
}
! parsenleft = EOF_NLEFT;
! return PEOF;
}
! parsenleft = i - 1; /* we're returning one char in this call */
/* delete nul characters */
something = 0;
! for (;;) {
! if (*p == '\0')
break;
! if (*p != ' ' && *p != '\t' && *p != '\n')
something = 1;
! p++;
! if (--i <= 0) {
! *p = '\0';
! goto done; /* no nul characters */
}
}
! /*
! * remove nuls
! */
! q = p++;
! while (--i > 0) {
! if (*p != '\0')
! *q++ = *p;
! p++;
! }
*q = '\0';
- if (q == parsefile->buf)
- goto retry; /* buffer contained nothing but nuls */
- parsenleft = q - parsefile->buf - 1;
- done:
if (parsefile->fd == 0 && hist && something) {
INTOFF;
! history(hist, whichprompt == 1 ? H_ENTER : H_ADD,
! parsefile->buf);
INTON;
}
if (vflag) {
! /*
! * This isn't right. Most shells coordinate it with
! * reading a line at a time. I honestly don't know if its
! * worth it.
! */
! i = parsenleft + 1;
! p = parsefile->buf;
! for (; i--; p++)
! out2c(*p)
flushout(out2);
}
return *parsenextc++;
}
--- 215,313 ----
}
}
}
! nr = -1;
}
! return nr;
! }
!
! /*
! * Refill the input buffer and return the next input character:
! *
! * 1) If a string was pushed back on the input, pop it;
! * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
! * from a string so we can't refill the buffer, return EOF.
! * 3) If the is more stuff in this buffer, use it else call read to fill it.
! * 4) Process input up to the next newline, deleting nul characters.
! */
!
! int
! preadbuffer()
! {
! char *p, *q;
! int more;
! int something;
! extern EditLine *el;
! char savec;
!
! if (parsefile->strpush) {
! popstring();
! if (--parsenleft >= 0)
! return (*parsenextc++);
! }
! if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
! return PEOF;
! flushout(&output);
! flushout(&errout);
!
! again:
! if (parselleft <= 0) {
! if ((parselleft = pread()) == -1) {
! parselleft = parsenleft = EOF_NLEFT;
! return PEOF;
! }
! }
!
! q = p = parsenextc;
/* delete nul characters */
something = 0;
! for (more = 1; more;) {
! switch (*p) {
! case '\0':
! p++; /* Skip NULL */
! goto check;
!
! case '\t':
! case ' ':
break;
!
! case '\n':
! parsenleft = q - parsenextc;
! more = 0; /* Stop processing here */
! break;
!
! default:
something = 1;
! break;
! }
!
! *q++ = *p++;
! check:
! if (--parselleft <= 0) {
! parsenleft = q - parsenextc - 1;
! if (parsenleft < 0)
! goto again;
! *q = '\0';
! more = 0;
}
}
!
! savec = *q;
*q = '\0';
if (parsefile->fd == 0 && hist && something) {
INTOFF;
! history(hist, whichprompt == 1 ? H_ENTER : H_ADD, parsenextc);
INTON;
}
+
if (vflag) {
! out2str(parsenextc);
flushout(out2);
}
+
+ *q = savec;
+
return *parsenextc++;
}
***************
*** 319,324 ****
--- 344,350 ----
sp = parsefile->strpush = &(parsefile->basestrpush);
sp->prevstring = parsenextc;
sp->prevnleft = parsenleft;
+ sp->prevlleft = parselleft;
sp->ap = (struct alias *)ap;
if (ap)
((struct alias *)ap)->flag |= ALIASINUSE;
***************
*** 335,340 ****
--- 361,367 ----
INTOFF;
parsenextc = sp->prevstring;
parsenleft = sp->prevnleft;
+ parselleft = sp->prevlleft;
/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
if (sp->ap)
sp->ap->flag &= ~ALIASINUSE;
***************
*** 408,414 ****
if (push)
pushfile();
parsenextc = string;
! parsenleft = strlen(string);
parsefile->buf = NULL;
plinno = 1;
INTON;
--- 435,441 ----
if (push)
pushfile();
parsenextc = string;
! parselleft = parsenleft = strlen(string);
parsefile->buf = NULL;
plinno = 1;
INTON;
***************
*** 426,431 ****
--- 453,459 ----
struct parsefile *pf;
parsefile->nleft = parsenleft;
+ parsefile->lleft = parselleft;
parsefile->nextc = parsenextc;
parsefile->linno = plinno;
pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
***************
*** 451,456 ****
--- 479,485 ----
parsefile = pf->prev;
ckfree(pf);
parsenleft = parsefile->nleft;
+ parselleft = parsefile->lleft;
parsenextc = parsefile->nextc;
plinno = parsefile->linno;
INTON;
>Audit-Trail:
>Unformatted: