Module Name: src Committed By: kre Date: Thu Mar 16 13:09:06 UTC 2017
Modified Files: src/bin/sh: Makefile show.c show.h Log Message: Have "make clean" remove sh.html1 and adapt it to clean trace files the way they have been generated the past 20 years or so... To generate a diff of this commit: cvs rdiff -u -r1.102 -r1.103 src/bin/sh/Makefile cvs rdiff -u -r1.34 -r1.35 src/bin/sh/show.c cvs rdiff -u -r1.7 -r1.8 src/bin/sh/show.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/bin/sh/Makefile diff -u src/bin/sh/Makefile:1.102 src/bin/sh/Makefile:1.103 --- src/bin/sh/Makefile:1.102 Sat Feb 27 18:34:12 2016 +++ src/bin/sh/Makefile Thu Mar 16 13:09:06 2017 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.102 2016/02/27 18:34:12 christos Exp $ +# $NetBSD: Makefile,v 1.103 2017/03/16 13:09:06 kre Exp $ # @(#)Makefile 8.4 (Berkeley) 5/5/95 .include <bsd.own.mk> @@ -53,8 +53,8 @@ SRCS+=printf.c ${NETBSDSRCDIR}/usr.bin/printf \ ${NETBSDSRCDIR}/bin/kill -CLEANFILES+= ${GENSRCS} ${GENHDRS} y.tab.h -CLEANFILES+= trace +CLEANFILES+= ${GENSRCS} ${GENHDRS} y.tab.h sh.html1 +CLEANFILES+= trace.* token.h: mktokens ${_MKTARGET_CREATE} Index: src/bin/sh/show.c diff -u src/bin/sh/show.c:1.34 src/bin/sh/show.c:1.35 --- src/bin/sh/show.c:1.34 Sun Oct 23 08:24:27 2016 +++ src/bin/sh/show.c Thu Mar 16 13:09:06 2017 @@ -1,9 +1,11 @@ -/* $NetBSD: show.c,v 1.34 2016/10/23 08:24:27 abhinav Exp $ */ +/* $NetBSD: show.c,v 1.35 2017/03/16 13:09:06 kre Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2016,2017 The NetBSD Foundation, Inc. All rights reserved. + * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * @@ -15,14 +17,16 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 3. Neither the name of the University, the NetBSD Foundation, nor the + * names of their contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS, FOUNDATION, AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * IN NO EVENT SHALL THE REGENTS, FOUNDATION OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -37,7 +41,7 @@ #if 0 static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; #else -__RCSID("$NetBSD: show.c,v 1.34 2016/10/23 08:24:27 abhinav Exp $"); +__RCSID("$NetBSD: show.c,v 1.35 2017/03/16 13:09:06 kre Exp $"); #endif #endif /* not lint */ @@ -45,6 +49,10 @@ __RCSID("$NetBSD: show.c,v 1.34 2016/10/ #include <stdarg.h> #include <stdlib.h> #include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/uio.h> #include "shell.h" #include "parser.h" @@ -52,390 +60,903 @@ __RCSID("$NetBSD: show.c,v 1.34 2016/10/ #include "mystring.h" #include "show.h" #include "options.h" -#ifndef SMALL +#include "redir.h" +#include "error.h" + +#if defined(DEBUG) && !defined(DBG_PID) +/* + * If this is compiled, it means this is being compiled in a shell that still + * has an older shell.h (a simpler TRACE() mechanism than is coming soon.) + * + * Compensate for as much of that as is missing and is needed here + * to compile and operate at all. After the other changes have appeared, + * this little block can (and should be) deleted (sometime). + * + * Try to avoid waiting 22 years... + */ +#define DBG_PID 1 +#define DBG_NEST 2 + +/* decide at compile time for now (DBG_NEST won't work) */ +static int DFlags = DBG_PID; +static int ShNest = 0; +#endif + #define DEFINE_NODENAMES #include "nodenames.h" + +#define TR_STD_WIDTH 60 /* tend to fold lines wider than this */ +#define TR_IOVECS 10 /* number of lines or trace (max) / write */ + +typedef struct traceinfo { + int tfd; /* file descriptor for open trace file */ + int nxtiov; /* the buffer we should be writing to */ + char lastc; /* the last non-white character output */ + uint8_t supr; /* char classes to supress after \n */ + pid_t pid; /* process id of process that opened that file */ + size_t llen; /* number of chars in current output line */ + size_t blen; /* chars used in current buffer being filled */ + char * tracefile; /* name of the tracefile */ + struct iovec lines[TR_IOVECS]; /* filled, flling, pending buffers */ +} TFILE; + +/* These are auto turned off when non white space is printed */ +#define SUP_NL 0x01 /* don't print \n */ +#define SUP_SP 0x03 /* supress spaces */ +#define SUP_WSP 0x04 /* supress all white space */ + +#ifdef DEBUG +TFILE tracedata, *tracetfile; +FILE *tracefile; /* just for histedit */ #endif +#ifdef DEBUG +static void shtree(union node *, int, int, int, TFILE *); +static void shcmd(union node *, TFILE *); +static void shsubsh(union node *, TFILE *); +static void shredir(union node *, TFILE *, int); +static void sharg(union node *, TFILE *); +static void indent(int, TFILE *); +static void trstring(const char *); +static void trace_putc(char, TFILE *); +static void trace_puts(const char *, TFILE *); +static void trace_flush(TFILE *, int); +static char *trace_id(TFILE *); + +inline static int trlinelen(TFILE *); +#endif -FILE *tracefile; + +/* + * These functions are the externally visible interface + */ #ifdef DEBUG -static int shtree(union node *, int, int, char *, FILE*); -static int shcmd(union node *, FILE *); -static int shsubsh(union node *, FILE *); -static int shredir(union node *, FILE *, int); -static int sharg(union node *, FILE *); -static int indent(int, char *, FILE *); -static void trstring(char *); +void +opentrace(void) +{ + char *s; + int fd; + int i; + pid_t pid; + + if (debug != 1) { + /* leave open because libedit might be using it */ + if (tracefile) + fflush(tracefile); + if (tracetfile) + trace_flush(tracetfile, 1); + return; + } + pid = getpid(); + if (asprintf(&s, "trace.%jd", (intmax_t)pid) <= 0) { + debug = 0; + error("Cannot asprintf tracefilename"); + }; + + fd = open(s, O_WRONLY|O_APPEND|O_CREAT, 0666); + if (fd == -1) { + debug = 0; + error("Can't open tracefile: %s (%s)\n", s, strerror(errno)); + } + fd = to_upper_fd(fd); + if (fd <= 2) { + (void) close(fd); + debug = 0; + error("Attempt to use fd %d as tracefile thwarted\n", fd); + } + + /* + * This stuff is just so histedit has a FILE * to use + */ + if (tracefile) + (void) fclose(tracefile); /* also closes tfd */ + tracefile = fdopen(fd, "a"); /* don't care if it is NULL */ + if (tracefile) /* except here... */ + setlinebuf(tracefile); + + /* + * Now the real tracing setup + */ + if (tracedata.tfd > 0 && tracedata.tfd != fd) + (void) close(tracedata.tfd); /* usually done by fclose() */ + tracedata.tfd = fd; + tracedata.pid = pid; + tracedata.nxtiov = 0; + tracedata.blen = 0; + tracedata.llen = 0; + tracedata.lastc = '\0'; + tracedata.supr = SUP_NL | SUP_WSP; + +#define replace(f, v) do { \ + if (tracedata.f != NULL) \ + free(tracedata.f); \ + tracedata.f = v; \ + } while (/*CONSTCOND*/ 0) + + replace(tracefile, s); + + for (i = 0; i < TR_IOVECS; i++) { + replace(lines[i].iov_base, NULL); + tracedata.lines[i].iov_len = 0; + } + +#undef replace + + tracetfile = &tracedata; + + trace_puts("\nTracing started.\n", tracetfile); +} + +void +trace(const char *fmt, ...) +{ + va_list va; + char *s; + + if (debug != 1 || !tracetfile) + return; + va_start(va, fmt); + (void) vasprintf(&s, fmt, va); + va_end(va); + + trace_puts(s, tracetfile); + free(s); + if (tracetfile->llen == 0) + trace_flush(tracetfile, 0); +} + +void +tracev(const char *fmt, va_list va) +{ + va_list ap; + char *s; + + if (debug != 1 || !tracetfile) + return; + va_copy(ap, va); + (void) vasprintf(&s, fmt, ap); + va_end(ap); + + trace_puts(s, tracetfile); + free(s); + if (tracetfile->llen == 0) + trace_flush(tracetfile, 0); +} + + +void +trputs(const char *s) +{ + if (debug != 1 || !tracetfile) + return; + trace_puts(s, tracetfile); +} + +void +trputc(int c) +{ + if (debug != 1 || !tracetfile) + return; + trace_putc(c, tracetfile); +} void showtree(union node *n) { - FILE *fp; + TFILE *fp; - fp = tracefile ? tracefile : stdout; + if ((fp = tracetfile) == NULL) + return; - trputs("showtree("); + trace_puts("showtree(", fp); if (n == NULL) - trputs("NULL"); + trace_puts("NULL", fp); else if (n == NEOF) - trputs("NEOF"); - trputs(") called\n"); + trace_puts("NEOF", fp); + else + trace("%p", n); + trace_puts(") called\n", fp); if (n != NULL && n != NEOF) - shtree(n, 1, 1, NULL, fp); + shtree(n, 1, 1, 1, fp); } +void +trargs(char **ap) +{ + if (debug != 1 || !tracetfile) + return; + while (*ap) { + trstring(*ap++); + if (*ap) + trace_putc(' ', tracetfile); + else + trace_putc('\n', tracetfile); + } +} +#endif + + +/* + * Beyond here we just have the implementation of all of that + */ -static int -shtree(union node *n, int ind, int nl, char *pfx, FILE *fp) + +#ifdef DEBUG + +inline static int +trlinelen(TFILE * fp) +{ + return fp->llen; +} + +static void +shtree(union node *n, int ind, int ilvl, int nl, TFILE *fp) { struct nodelist *lp; const char *s; - int len; if (n == NULL) { if (nl) - fputc('\n', fp); - return 0; + trace_putc('\n', fp); + return; } - len = indent(ind, pfx, fp); + indent(ind, fp); switch (n->type) { case NSEMI: - s = "; "; - len += 2; + s = NULL; goto binop; case NAND: s = " && "; - len += 4; goto binop; case NOR: s = " || "; - len += 4; binop: - len += shtree(n->nbinary.ch1, 0, 0, NULL, fp); - fputs(s, fp); - if (len >= 60) { - putc('\n', fp); - len = indent(ind < 0 ? 2 : ind + 1, pfx, fp); + shtree(n->nbinary.ch1, 0, ilvl, 0, fp); + if (s != NULL) + trace_puts(s, fp); + if (trlinelen(fp) >= TR_STD_WIDTH) { + trace_putc('\n', fp); + indent(ind < 0 ? 2 : ind + 1, fp); + } else if (s == NULL) { + if (fp->lastc != '&') + trace_puts("; ", fp); + else + trace_putc(' ', fp); } - len += shtree(n->nbinary.ch2, 0, nl, NULL, fp); + shtree(n->nbinary.ch2, 0, ilvl, nl, fp); break; case NCMD: - len += shcmd(n, fp); - if (nl && len > 0) - len = 0, putc('\n', fp); + shcmd(n, fp); + if (n->ncmd.backgnd) + trace_puts(" &", fp); + if (nl && trlinelen(fp) > 0) + trace_putc('\n', fp); break; case NPIPE: for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - len += shcmd(lp->n, fp); + shtree(lp->n, 0, ilvl, 0, fp); if (lp->next) { - len += 3, fputs(" | ", fp); - if (len >= 60) { - fputc('\n', fp); - len = indent(ind < 0 ? 2 : ind + 1, - pfx, fp); - } + trace_puts(" |", fp); + if (trlinelen(fp) >= TR_STD_WIDTH) { + trace_putc('\n', fp); + indent((ind < 0 ? ilvl : ind) + 1, fp); + } else + trace_putc(' ', fp); } } if (n->npipe.backgnd) - len += 2, fputs(" &", fp); - if (nl || len >= 60) - len = 0, fputc('\n', fp); + trace_puts(" &", fp); + if (nl || trlinelen(fp) >= TR_STD_WIDTH) + trace_putc('\n', fp); break; + case NBACKGND: case NSUBSHELL: - len += shsubsh(n, fp); - if (nl && len > 0) - len = 0, putc('\n', fp); - break; - default: -#ifdef NODETYPENAME - len += fprintf(fp, "<node type %d [%s]>", n->type, - NODETYPENAME(n->type)); -#else - len += fprintf(fp, "<node type %d>", n->type); -#endif + shsubsh(n, fp); + if (n->type == NBACKGND) + trace_puts(" &", fp); + if (nl && trlinelen(fp) > 0) + trace_putc('\n', fp); + break; + case NDEFUN: + trace_puts(n->narg.text, fp); + trace_puts("() {\n", fp); + indent(ind, fp); + shtree(n->narg.next, (ind < 0 ? ilvl : ind) + 1, ilvl+1, 1, fp); + indent(ind, fp); + trace_puts("}\n", fp); + break; + case NNOT: + trace_puts("! ", fp); + shtree(n->nnot.com, -1, ilvl, nl, fp); + break; + case NREDIR: + shtree(n->nredir.n, -1, ilvl, 0, fp); + shredir(n->nredir.redirect, fp, n->nredir.n == NULL); + if (nl) + trace_putc('\n', fp); + break; + + case NIF: + itsif: + trace_puts("if ", fp); + shtree(n->nif.test, -1, ilvl, 0, fp); + if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) { + if (fp->lastc != '&') + trace_puts(" ;", fp); + } else + indent(ilvl, fp); + trace_puts(" then ", fp); + if (nl || trlinelen(fp) > TR_STD_WIDTH - 24) + indent(ilvl+1, fp); + shtree(n->nif.ifpart, -1, ilvl + 1, 0, fp); + if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) { + if (fp->lastc != '&') + trace_puts(" ;", fp); + } else + indent(ilvl, fp); + if (n->nif.elsepart && n->nif.elsepart->type == NIF) { + if (nl || trlinelen(fp) > TR_STD_WIDTH - 24) + indent(ilvl, fp); + n = n->nif.elsepart; + trace_puts(" el", fp); + goto itsif; + } + if (n->nif.elsepart) { + if (nl || trlinelen(fp) > TR_STD_WIDTH - 24) + indent(ilvl+1, fp); + trace_puts(" else ", fp); + shtree(n->nif.elsepart, -1, ilvl + 1, 0, fp); + if (fp->lastc != '&') + trace_puts(" ;", fp); + } + trace_puts(" fi", fp); + if (nl) + trace_putc('\n', fp); + break; + + case NWHILE: + trace_puts("while ", fp); + goto aloop; + case NUNTIL: + trace_puts("until ", fp); + aloop: + shtree(n->nbinary.ch1, -1, ilvl, 0, fp); + if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) { + if (fp->lastc != '&') + trace_puts(" ;", fp); + } else + trace_putc('\n', fp); + trace_puts(" do ", fp); + shtree(n->nbinary.ch1, -1, ilvl + 1, 1, fp); + trace_puts(" done ", fp); if (nl) - len = 0, putc('\n', fp); + trace_putc('\n', fp); + break; + + case NFOR: + trace_puts("for ", fp); + trace_puts(n->nfor.var, fp); + if (n->nfor.args) { + union node *argp; + + trace_puts(" in ", fp); + for (argp = n->nfor.args; argp; argp=argp->narg.next) { + sharg(argp, fp); + trace_putc(' ', fp); + } + if (trlinelen(fp) > 0 && trlinelen(fp) < TR_STD_WIDTH) { + if (fp->lastc != '&') + trace_putc(';', fp); + } else + trace_putc('\n', fp); + } + trace_puts(" do ", fp); + shtree(n->nfor.body, -1, ilvl + 1, 0, fp); + if (fp->lastc != '&') + trace_putc(';', fp); + trace_puts(" done", fp); + if (nl) + trace_putc('\n', fp); + break; + + case NCASE: + trace_puts("case ", fp); + sharg(n->ncase.expr, fp); + trace_puts(" in", fp); + if (nl) + trace_putc('\n', fp); + { + union node *cp; + + for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) { + union node *patp; + + if (nl || trlinelen(fp) > TR_STD_WIDTH - 16) + indent(ilvl, fp); + else + trace_putc(' ', fp); + trace_putc('(', fp); + patp = cp->nclist.pattern; + while (patp != NULL) { + trace_putc(' ', fp); + sharg(patp, fp); + trace_putc(' ', fp); + if ((patp = patp->narg.next) != NULL) + trace_putc('|', fp); + } + trace_putc(')', fp); + if (nl) + indent(ilvl + 1, fp); + else + trace_putc(' ', fp); + shtree(cp->nclist.body, -1, ilvl+2, 0, fp); + trace_puts(" ;;", fp); + if (nl) + trace_putc('\n', fp); + } + } + if (nl) { + trace_putc('\n', fp); + indent(ind, fp); + } else + trace_putc(' ', fp); + trace_puts("esac", fp); + if (nl) + trace_putc('\n', fp); + break; + + default: { + char *str; + + asprintf(&str, "<node type %d [%s]>", n->type, + NODETYPENAME(n->type)); + trace_puts(str, fp); + free(str); + if (nl) + trace_putc('\n', fp); + } break; } - return len; } - -static int -shcmd(union node *cmd, FILE *fp) +static void +shcmd(union node *cmd, TFILE *fp) { union node *np; int first; - int len = 0; first = 1; for (np = cmd->ncmd.args ; np ; np = np->narg.next) { if (! first) - len++, fputc(' ', fp); - len += sharg(np, fp); + trace_putc(' ', fp); + sharg(np, fp); first = 0; } - return len + shredir(cmd, fp, first); + shredir(cmd->ncmd.redirect, fp, first); } -static int -shsubsh(union node *cmd, FILE *fp) +static void +shsubsh(union node *cmd, TFILE *fp) { - int len = 6; - - fputs(" ( ", fp); - len += shtree(cmd->nredir.n, -1, 0, NULL, fp); - fputs(" ) ", fp); - len += shredir(cmd, fp, 1); - - return len; + trace_puts(" ( ", fp); + shtree(cmd->nredir.n, -1, 3, 0, fp); + trace_puts(" ) ", fp); + shredir(cmd->ncmd.redirect, fp, 1); } -static int -shredir(union node *cmd, FILE *fp, int first) +static void +shredir(union node *np, TFILE *fp, int first) { - union node *np; const char *s; int dftfd; - int len = 0; char buf[106]; - for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { + for ( ; np ; np = np->nfile.next) { if (! first) - len++, fputc(' ', fp); + trace_putc(' ', fp); switch (np->nfile.type) { - case NTO: s = ">"; dftfd = 1; len += 1; break; - case NCLOBBER: s = ">|"; dftfd = 1; len += 2; break; - case NAPPEND: s = ">>"; dftfd = 1; len += 2; break; - case NTOFD: s = ">&"; dftfd = 1; len += 2; break; - case NFROM: s = "<"; dftfd = 0; len += 1; break; - case NFROMFD: s = "<&"; dftfd = 0; len += 2; break; - case NFROMTO: s = "<>"; dftfd = 0; len += 2; break; - case NXHERE: /* FALLTHROUGH */ - case NHERE: s = "<<"; dftfd = 0; len += 2; break; - default: s = "*error*"; dftfd = 0; len += 7; break; - } - if (np->nfile.fd != dftfd) - len += fprintf(fp, "%d", np->nfile.fd); - fputs(s, fp); + case NTO: s = ">"; dftfd = 1; break; + case NCLOBBER: s = ">|"; dftfd = 1; break; + case NAPPEND: s = ">>"; dftfd = 1; break; + case NTOFD: s = ">&"; dftfd = 1; break; + case NFROM: s = "<"; dftfd = 0; break; + case NFROMFD: s = "<&"; dftfd = 0; break; + case NFROMTO: s = "<>"; dftfd = 0; break; + case NXHERE: /* FALLTHROUGH */ + case NHERE: s = "<<"; dftfd = 0; break; + default: s = "*error*"; dftfd = 0; break; + } + if (np->nfile.fd != dftfd) { + sprintf(buf, "%d", np->nfile.fd); + trace_puts(buf, fp); + } + trace_puts(s, fp); if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { - len += fprintf(fp, "%d", np->ndup.dupfd); + if (np->ndup.vname) + sharg(np->ndup.vname, fp); + else { + sprintf(buf, "%d", np->ndup.dupfd); + trace_puts(buf, fp); + } } else if (np->nfile.type == NHERE || np->nfile.type == NXHERE) { if (np->nfile.type == NHERE) - fputc('\\', fp); - fputs("!!!\n", fp); + trace_putc('\\', fp); + trace_puts("!!!\n", fp); s = np->nhere.doc->narg.text; if (strlen(s) > 100) { memmove(buf, s, 100); buf[100] = '\0'; - strcat(buf, " ..."); + strcat(buf, " ...\n"); s = buf; } - fputs(s, fp); - fputs("!!!", fp); - len = 3; + trace_puts(s, fp); + trace_puts("!!! ", fp); } else { - len += sharg(np->nfile.fname, fp); + sharg(np->nfile.fname, fp); } first = 0; } - return len; } - - -static int -sharg(union node *arg, FILE *fp) +static void +sharg(union node *arg, TFILE *fp) { - char *p; + char *p, *s; struct nodelist *bqlist; - int subtype; - int len = 0; + int subtype = 0; + int quoted = 0; if (arg->type != NARG) { - fprintf(fp, "<node type %d>\n", arg->type); - abort(); + asprintf(&s, "<node type %d> ! NARG\n", arg->type); + trace_puts(s, fp); + abort(); /* no need to free s, better not to */ } + bqlist = arg->narg.backquote; for (p = arg->narg.text ; *p ; p++) { switch (*p) { case CTLESC: - putc(*++p, fp); - len++; + trace_putc('\\', fp); + trace_putc(*++p, fp); break; + case CTLVAR: - putc('$', fp); - putc('{', fp); - len += 2; subtype = *++p; - if (subtype == VSLENGTH) - len++, putc('#', fp); + if (!quoted != !(subtype & VSQUOTE)) + trace_putc('"', fp); + trace_putc('$', fp); + trace_putc('{', fp); + if ((subtype & VSTYPE) == VSLENGTH) + trace_putc('#', fp); while (*++p != '=') - len++, putc(*p, fp); + trace_putc(*p, fp); if (subtype & VSNUL) - len++, putc(':', fp); + trace_putc(':', fp); switch (subtype & VSTYPE) { case VSNORMAL: - putc('}', fp); - len++; + /* { */ + trace_putc('}', fp); + if (!quoted != !(subtype & VSQUOTE)) + trace_putc('"', fp); break; case VSMINUS: - putc('-', fp); - len++; + trace_putc('-', fp); break; case VSPLUS: - putc('+', fp); - len++; + trace_putc('+', fp); break; case VSQUESTION: - putc('?', fp); - len++; + trace_putc('?', fp); break; case VSASSIGN: - putc('=', fp); - len++; - break; - case VSTRIMLEFT: - putc('#', fp); - len++; + trace_putc('=', fp); break; case VSTRIMLEFTMAX: - putc('#', fp); - putc('#', fp); - len += 2; - break; - case VSTRIMRIGHT: - putc('%', fp); - len++; + trace_putc('#', fp); + /* FALLTHRU */ + case VSTRIMLEFT: + trace_putc('#', fp); break; case VSTRIMRIGHTMAX: - putc('%', fp); - putc('%', fp); - len += 2; + trace_putc('%', fp); + /* FALLTHRU */ + case VSTRIMRIGHT: + trace_putc('%', fp); break; case VSLENGTH: break; - default: - len += fprintf(fp, "<subtype %d>", subtype); + default: { + char str[32]; + + snprintf(str, sizeof str, + "<subtype %d>", subtype); + trace_puts(str, fp); + } + break; } break; case CTLENDVAR: - putc('}', fp); - len++; - break; - case CTLBACKQ: + /* { */ + trace_putc('}', fp); + if (!quoted != !(subtype & VSQUOTE)) + trace_putc('"', fp); + subtype = 0; + break; + case CTLBACKQ|CTLQUOTE: - putc('$', fp); - putc('(', fp); - len += shtree(bqlist->n, -1, 0, NULL, fp) + 3; - putc(')', fp); + if (!quoted) + trace_putc('"', fp); + /* FALLTHRU */ + case CTLBACKQ: + trace_putc('$', fp); + trace_putc('(', fp); + if (bqlist) { + shtree(bqlist->n, -1, 3, 0, fp); + bqlist = bqlist->next; + } else + trace_puts("???", fp); + trace_putc(')', fp); + if (!quoted && *p == (CTLBACKQ|CTLQUOTE)) + trace_putc('"', fp); + break; + + case CTLQUOTEMARK: + if (subtype != 0 || !quoted) { + trace_putc('"', fp); + quoted++; + } + break; + case CTLQUOTEEND: + trace_putc('"', fp); + quoted--; + break; + case CTLARI: + trace_puts("$(( ", fp); break; + case CTLENDARI: + trace_puts(" ))", fp); + break; + default: - putc(*p, fp); - len++; + if (*p == '$') + trace_putc('\\', fp); + trace_putc(*p, fp); break; } } - return len; + if (quoted) + trace_putc('"', fp); } -static int -indent(int amount, char *pfx, FILE *fp) +static void +indent(int amount, TFILE *fp) { int i; - int len = 0; - /* - * in practice, pfx is **always** NULL - * but here, we assume if it were not, at least strlen(pfx) < 8 - * if that is invalid, output will look messy - */ - for (i = 0 ; i < amount ; i++) { - if (pfx && i == amount - 1) - fputs(pfx, fp); - putc('\t', fp); - len |= 7; - len++; + if (amount <= 0) + return; + + amount <<= 2; /* indent slots -> chars */ + + i = trlinelen(fp); + fp->supr = SUP_NL; + if (i > amount) { + trace_putc('\n', fp); + i = 0; + } + fp->supr = 0; + for (; i < amount - 7 ; i++) { + trace_putc('\t', fp); + i |= 7; + } + while (i < amount) { + trace_putc(' ', fp); + i++; } - return len; + fp->supr = SUP_WSP; } -#endif +static void +trace_putc(char c, TFILE *fp) +{ + char *p; + if (c == '\0') + return; + if (debug == 0 || fp == NULL) + return; -/* - * Debugging stuff. - */ + if (fp->llen == 0) { + if (fp->blen != 0) + abort(); + if ((fp->supr & SUP_NL) && c == '\n') + return; + if ((fp->supr & (SUP_WSP|SUP_SP)) && c == ' ') + return; + if ((fp->supr & SUP_WSP) && c == '\t') + return; + if (fp->nxtiov >= TR_IOVECS - 1) /* should be rare */ + trace_flush(fp, 0); + p = trace_id(fp); + if (p != NULL) { + fp->lines[fp->nxtiov].iov_base = p; + fp->lines[fp->nxtiov].iov_len = strlen(p); + fp->nxtiov++; + } + } else if (fp->blen && fp->blen >= fp->lines[fp->nxtiov].iov_len) { + fp->blen = 0; + if (++fp->nxtiov >= TR_IOVECS) + trace_flush(fp, 0); + } -#ifdef DEBUG -void -trputc(int c) -{ - if (debug != 1 || !tracefile) + if (fp->lines[fp->nxtiov].iov_len == 0) { + p = (char *)malloc(2 * TR_STD_WIDTH); + if (p == NULL) { + trace_flush(fp, 1); + debug = 0; + return; + } + *p = '\0'; + fp->lines[fp->nxtiov].iov_base = p; + fp->lines[fp->nxtiov].iov_len = 2 * TR_STD_WIDTH; + fp->blen = 0; + } + + p = (char *)fp->lines[fp->nxtiov].iov_base + fp->blen++; + *p++ = c; + *p = 0; + + if (c != ' ' && c != '\t' && c != '\n') { + fp->lastc = c; + fp->supr = 0; + } + + if (c == '\n') { + fp->lines[fp->nxtiov++].iov_len = fp->blen; + fp->blen = 0; + fp->llen = 0; + fp->supr |= SUP_NL; return; - putc(c, tracefile); + } + + if (c == '\t') + fp->llen |= 7; + fp->llen++; } -#endif void -trace(const char *fmt, ...) +trace_flush(TFILE *fp, int all) { -#ifdef DEBUG - va_list va; + int niov, i; + ssize_t written; - if (debug != 1 || !tracefile) + niov = fp->nxtiov; + if (all && fp->blen > 0) { + fp->lines[niov].iov_len = fp->blen; + fp->blen = 0; + fp->llen = 0; + niov++; + } + if (niov == 0) return; - va_start(va, fmt); - (void) vfprintf(tracefile, fmt, va); - va_end(va); -#endif + if (fp->blen > 0 && --niov == 0) + return; + written = writev(fp->tfd, fp->lines, niov); + for (i = 0; i < niov; i++) { + free(fp->lines[i].iov_base); + fp->lines[i].iov_base = NULL; + fp->lines[i].iov_len = 0; + } + if (written == -1) { + if (fp->blen > 0) { + free(fp->lines[niov].iov_base); + fp->lines[niov].iov_base = NULL; + fp->lines[niov].iov_len = 0; + } + debug = 0; + fp->blen = 0; + fp->llen = 0; + return; + } + if (fp->blen > 0) { + fp->lines[0].iov_base = fp->lines[niov].iov_base; + fp->lines[0].iov_len = fp->lines[niov].iov_len; + fp->lines[niov].iov_base = NULL; + fp->lines[niov].iov_len = 0; + } + fp->nxtiov = 0; } void -tracev(const char *fmt, va_list va) +trace_puts(const char *s, TFILE *fp) { -#ifdef DEBUG - va_list ap; - if (debug != 1 || !tracefile) - return; - va_copy(ap, va); - (void) vfprintf(tracefile, fmt, ap); - va_end(ap); -#endif -} + char c; + while ((c = *s++) != '\0') + trace_putc(c, fp); +} -#ifdef DEBUG -void -trputs(const char *s) +inline static char * +trace_id(TFILE *tf) { - if (debug != 1 || !tracefile) - return; - fputs(s, tracefile); -} + int i; + char indent[16]; + char *p; + if (DFlags & DBG_NEST) { + p = indent; + for (i = 0; i < 6; i++) + *p++ = (i < ShNest) ? '#' : ' '; + while (i++ < ShNest && p < &indent[sizeof indent - 1]) + *p++ = '#'; + *p = '\0'; + } else + indent[0] = '\0'; + + if (DFlags & DBG_PID) { + i = getpid(); + (void) asprintf(&p, "%5d%c%s\t", i, + i == tf->pid ? ':' : '=', indent); + return p; + } else if (DFlags & DBG_NEST) { + *p++ = '\t'; + *p = '\0'; + (void) asprintf(&p, "%s\t", indent); + return p; + } + return NULL; +} +/* + * Used only from trargs(), which itself is used only to print + * arg lists (argv[]) either that were passed into this shell, or + * the arg list about to be given to some other command (incl + * builtins, and functions) as their argv[]. If any of the CTL* + * chars seem to appear, they really should be just treated as data, + * not special... But this is just debug, so, who cares! + */ static void -trstring(char *s) +trstring(const char *s) { - char *p; + const char *p; char c; + TFILE *fp; - if (debug != 1 || !tracefile) + if (debug != 1 || !tracetfile) return; - putc('"', tracefile); + fp = tracetfile; + trace_putc('"', fp); for (p = s ; *p ; p++) { switch (*p) { case '\n': c = 'n'; goto backslash; @@ -448,78 +969,22 @@ trstring(char *s) case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash; case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; -backslash: putc('\\', tracefile); - putc(c, tracefile); + backslash: trace_putc('\\', fp); + trace_putc(c, fp); break; default: if (*p >= ' ' && *p <= '~') - putc(*p, tracefile); + trace_putc(*p, fp); else { - putc('\\', tracefile); - putc(*p >> 6 & 03, tracefile); - putc(*p >> 3 & 07, tracefile); - putc(*p & 07, tracefile); + trace_putc('\\', fp); + trace_putc(*p >> 6 & 03, fp); + trace_putc(*p >> 3 & 07, fp); + trace_putc(*p & 07, fp); } break; } } - putc('"', tracefile); -} -#endif - - -void -trargs(char **ap) -{ -#ifdef DEBUG - if (debug != 1 || !tracefile) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } -#endif + trace_putc('"', fp); } - -#ifdef DEBUG -void -opentrace(void) -{ - char s[100]; -#ifdef O_APPEND - int flags; -#endif - - if (debug != 1) { - if (tracefile) - fflush(tracefile); - /* leave open because libedit might be using it */ - return; - } - snprintf(s, sizeof(s), "./trace.%d", (int)getpid()); - if (tracefile) { - if (!freopen(s, "a", tracefile)) { - fprintf(stderr, "Can't re-open %s\n", s); - tracefile = NULL; - debug = 0; - return; - } - } else { - if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); - debug = 0; - return; - } - } -#ifdef O_APPEND - if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) - fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif - setlinebuf(tracefile); - fputs("\nTracing started.\n", tracefile); -} #endif /* DEBUG */ Index: src/bin/sh/show.h diff -u src/bin/sh/show.h:1.7 src/bin/sh/show.h:1.8 --- src/bin/sh/show.h:1.7 Thu Aug 7 09:05:38 2003 +++ src/bin/sh/show.h Thu Mar 16 13:09:06 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */ +/* $NetBSD: show.h,v 1.8 2017/03/16 13:09:06 kre Exp $ */ /*- * Copyright (c) 1995 @@ -33,12 +33,12 @@ #include <stdarg.h> +#ifdef DEBUG union node; void showtree(union node *); void trace(const char *, ...); void tracev(const char *, va_list); void trargs(char **); -#ifdef DEBUG void trputc(int); void trputs(const char *); void opentrace(void);