| /*	$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $	*/ | 
 |  | 
 | /*- | 
 |  * Copyright (c) 1991, 1993 | 
 |  *	The Regents of the University of California.  All rights reserved. | 
 |  * | 
 |  * This code is derived from software contributed to Berkeley by | 
 |  * Kenneth Almquist. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 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. | 
 |  * | 
 |  * 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 | 
 |  * 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) | 
 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 |  * SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | #include <sys/cdefs.h> | 
 | #ifndef lint | 
 | #if 0 | 
 | static char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95"; | 
 | #else | 
 | __RCSID("$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $"); | 
 | #endif | 
 | #endif /* not lint */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdarg.h> | 
 | #include <stdlib.h> | 
 |  | 
 | #include "shell.h" | 
 | #include "parser.h" | 
 | #include "nodes.h" | 
 | #include "mystring.h" | 
 | #include "show.h" | 
 | #include "options.h" | 
 |  | 
 |  | 
 | #ifdef DEBUG | 
 | static void shtree(union node *, int, char *, FILE*); | 
 | static void shcmd(union node *, FILE *); | 
 | static void sharg(union node *, FILE *); | 
 | static void indent(int, char *, FILE *); | 
 | static void trstring(char *); | 
 |  | 
 |  | 
 | void | 
 | showtree(union node *n) | 
 | { | 
 | 	trputs("showtree called\n"); | 
 | 	shtree(n, 1, NULL, stdout); | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | shtree(union node *n, int ind, char *pfx, FILE *fp) | 
 | { | 
 | 	struct nodelist *lp; | 
 | 	const char *s; | 
 |  | 
 | 	if (n == NULL) | 
 | 		return; | 
 |  | 
 | 	indent(ind, pfx, fp); | 
 | 	switch(n->type) { | 
 | 	case NSEMI: | 
 | 		s = "; "; | 
 | 		goto binop; | 
 | 	case NAND: | 
 | 		s = " && "; | 
 | 		goto binop; | 
 | 	case NOR: | 
 | 		s = " || "; | 
 | binop: | 
 | 		shtree(n->nbinary.ch1, ind, NULL, fp); | 
 | 	   /*    if (ind < 0) */ | 
 | 			fputs(s, fp); | 
 | 		shtree(n->nbinary.ch2, ind, NULL, fp); | 
 | 		break; | 
 | 	case NCMD: | 
 | 		shcmd(n, fp); | 
 | 		if (ind >= 0) | 
 | 			putc('\n', fp); | 
 | 		break; | 
 | 	case NPIPE: | 
 | 		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { | 
 | 			shcmd(lp->n, fp); | 
 | 			if (lp->next) | 
 | 				fputs(" | ", fp); | 
 | 		} | 
 | 		if (n->npipe.backgnd) | 
 | 			fputs(" &", fp); | 
 | 		if (ind >= 0) | 
 | 			putc('\n', fp); | 
 | 		break; | 
 | 	default: | 
 | 		fprintf(fp, "<node type %d>", n->type); | 
 | 		if (ind >= 0) | 
 | 			putc('\n', fp); | 
 | 		break; | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 |  | 
 | static void | 
 | shcmd(union node *cmd, FILE *fp) | 
 | { | 
 | 	union node *np; | 
 | 	int first; | 
 | 	const char *s; | 
 | 	int dftfd; | 
 |  | 
 | 	first = 1; | 
 | 	for (np = cmd->ncmd.args ; np ; np = np->narg.next) { | 
 | 		if (! first) | 
 | 			putchar(' '); | 
 | 		sharg(np, fp); | 
 | 		first = 0; | 
 | 	} | 
 | 	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { | 
 | 		if (! first) | 
 | 			putchar(' '); | 
 | 		switch (np->nfile.type) { | 
 | 			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; | 
 | 			default:  	s = "*error*"; dftfd = 0; break; | 
 | 		} | 
 | 		if (np->nfile.fd != dftfd) | 
 | 			fprintf(fp, "%d", np->nfile.fd); | 
 | 		fputs(s, fp); | 
 | 		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { | 
 | 			fprintf(fp, "%d", np->ndup.dupfd); | 
 | 		} else { | 
 | 			sharg(np->nfile.fname, fp); | 
 | 		} | 
 | 		first = 0; | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 |  | 
 | static void | 
 | sharg(union node *arg, FILE *fp) | 
 | { | 
 | 	char *p; | 
 | 	struct nodelist *bqlist; | 
 | 	int subtype; | 
 |  | 
 | 	if (arg->type != NARG) { | 
 | 		printf("<node type %d>\n", arg->type); | 
 | 		abort(); | 
 | 	} | 
 | 	bqlist = arg->narg.backquote; | 
 | 	for (p = arg->narg.text ; *p ; p++) { | 
 | 		switch (*p) { | 
 | 		case CTLESC: | 
 | 			putc(*++p, fp); | 
 | 			break; | 
 | 		case CTLVAR: | 
 | 			putc('$', fp); | 
 | 			putc('{', fp); | 
 | 			subtype = *++p; | 
 | 			if (subtype == VSLENGTH) | 
 | 				putc('#', fp); | 
 |  | 
 | 			while (*p != '=') | 
 | 				putc(*p++, fp); | 
 |  | 
 | 			if (subtype & VSNUL) | 
 | 				putc(':', fp); | 
 |  | 
 | 			switch (subtype & VSTYPE) { | 
 | 			case VSNORMAL: | 
 | 				putc('}', fp); | 
 | 				break; | 
 | 			case VSMINUS: | 
 | 				putc('-', fp); | 
 | 				break; | 
 | 			case VSPLUS: | 
 | 				putc('+', fp); | 
 | 				break; | 
 | 			case VSQUESTION: | 
 | 				putc('?', fp); | 
 | 				break; | 
 | 			case VSASSIGN: | 
 | 				putc('=', fp); | 
 | 				break; | 
 | 			case VSTRIMLEFT: | 
 | 				putc('#', fp); | 
 | 				break; | 
 | 			case VSTRIMLEFTMAX: | 
 | 				putc('#', fp); | 
 | 				putc('#', fp); | 
 | 				break; | 
 | 			case VSTRIMRIGHT: | 
 | 				putc('%', fp); | 
 | 				break; | 
 | 			case VSTRIMRIGHTMAX: | 
 | 				putc('%', fp); | 
 | 				putc('%', fp); | 
 | 				break; | 
 | 			case VSLENGTH: | 
 | 				break; | 
 | 			default: | 
 | 				printf("<subtype %d>", subtype); | 
 | 			} | 
 | 			break; | 
 | 		case CTLENDVAR: | 
 | 		     putc('}', fp); | 
 | 		     break; | 
 | 		case CTLBACKQ: | 
 | 		case CTLBACKQ|CTLQUOTE: | 
 | 			putc('$', fp); | 
 | 			putc('(', fp); | 
 | 			shtree(bqlist->n, -1, NULL, fp); | 
 | 			putc(')', fp); | 
 | 			break; | 
 | 		default: | 
 | 			putc(*p, fp); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | indent(int amount, char *pfx, FILE *fp) | 
 | { | 
 | 	int i; | 
 |  | 
 | 	for (i = 0 ; i < amount ; i++) { | 
 | 		if (pfx && i == amount - 1) | 
 | 			fputs(pfx, fp); | 
 | 		putc('\t', fp); | 
 | 	} | 
 | } | 
 | #endif | 
 |  | 
 |  | 
 |  | 
 | /* | 
 |  * Debugging stuff. | 
 |  */ | 
 |  | 
 |  | 
 | FILE *tracefile; | 
 |  | 
 |  | 
 | #ifdef DEBUG | 
 | void | 
 | trputc(int c) | 
 | { | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	putc(c, tracefile); | 
 | } | 
 | #endif | 
 |  | 
 | void | 
 | trace(const char *fmt, ...) | 
 | { | 
 | #ifdef DEBUG | 
 | 	va_list va; | 
 |  | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	va_start(va, fmt); | 
 | 	(void) vfprintf(tracefile, fmt, va); | 
 | 	va_end(va); | 
 | #endif | 
 | } | 
 |  | 
 | void | 
 | tracev(const char *fmt, va_list va) | 
 | { | 
 | #ifdef DEBUG | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	(void) vfprintf(tracefile, fmt, va); | 
 | #endif | 
 | } | 
 |  | 
 |  | 
 | #ifdef DEBUG | 
 | void | 
 | trputs(const char *s) | 
 | { | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	fputs(s, tracefile); | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | trstring(char *s) | 
 | { | 
 | 	char *p; | 
 | 	char c; | 
 |  | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	putc('"', tracefile); | 
 | 	for (p = s ; *p ; p++) { | 
 | 		switch (*p) { | 
 | 		case '\n':  c = 'n';  goto backslash; | 
 | 		case '\t':  c = 't';  goto backslash; | 
 | 		case '\r':  c = 'r';  goto backslash; | 
 | 		case '"':  c = '"';  goto backslash; | 
 | 		case '\\':  c = '\\';  goto backslash; | 
 | 		case CTLESC:  c = 'e';  goto backslash; | 
 | 		case CTLVAR:  c = 'v';  goto backslash; | 
 | 		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); | 
 | 			break; | 
 | 		default: | 
 | 			if (*p >= ' ' && *p <= '~') | 
 | 				putc(*p, tracefile); | 
 | 			else { | 
 | 				putc('\\', tracefile); | 
 | 				putc(*p >> 6 & 03, tracefile); | 
 | 				putc(*p >> 3 & 07, tracefile); | 
 | 				putc(*p & 07, tracefile); | 
 | 			} | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	putc('"', tracefile); | 
 | } | 
 | #endif | 
 |  | 
 |  | 
 | void | 
 | trargs(char **ap) | 
 | { | 
 | #ifdef DEBUG | 
 | 	if (debug != 1) | 
 | 		return; | 
 | 	while (*ap) { | 
 | 		trstring(*ap++); | 
 | 		if (*ap) | 
 | 			putc(' ', tracefile); | 
 | 		else | 
 | 			putc('\n', tracefile); | 
 | 	} | 
 | #endif | 
 | } | 
 |  | 
 |  | 
 | #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; | 
 | 	} | 
 | #ifdef not_this_way | 
 | 	{ | 
 | 		char *p; | 
 | 		if ((p = getenv("HOME")) == NULL) { | 
 | 			if (geteuid() == 0) | 
 | 				p = "/"; | 
 | 			else | 
 | 				p = "/tmp"; | 
 | 		} | 
 | 		scopy(p, s); | 
 | 		strcat(s, "/trace"); | 
 | 	} | 
 | #else | 
 | 	scopy("./trace", s); | 
 | #endif /* not_this_way */ | 
 | 	if (tracefile) { | 
 | 		if (!freopen(s, "a", tracefile)) { | 
 | 			fprintf(stderr, "Can't re-open %s\n", s); | 
 | 			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 */ |