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);

Reply via email to