11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD$");
401556Srgrimes
41109627Stjr#include <fcntl.h>
421556Srgrimes#include <stdio.h>
43109627Stjr#include <stdlib.h>
4417987Speter#include <stdarg.h>
4559437Scracauer#include <errno.h>
4617987Speter
471556Srgrimes#include "shell.h"
481556Srgrimes#include "parser.h"
491556Srgrimes#include "nodes.h"
501556Srgrimes#include "mystring.h"
5117987Speter#include "show.h"
521556Srgrimes
531556Srgrimes
541556Srgrimes#ifdef DEBUG
55213811Sobrienstatic void shtree(union node *, int, char *, FILE*);
56213811Sobrienstatic void shcmd(union node *, FILE *);
57213811Sobrienstatic void sharg(union node *, FILE *);
58213811Sobrienstatic void indent(int, char *, FILE *);
59213811Sobrienstatic void trstring(char *);
601556Srgrimes
611556Srgrimes
6217987Spetervoid
6390111Simpshowtree(union node *n)
6417987Speter{
651556Srgrimes	trputs("showtree called\n");
661556Srgrimes	shtree(n, 1, NULL, stdout);
671556Srgrimes}
681556Srgrimes
691556Srgrimes
70213811Sobrienstatic void
7190111Simpshtree(union node *n, int ind, char *pfx, FILE *fp)
7217987Speter{
731556Srgrimes	struct nodelist *lp;
741556Srgrimes	char *s;
751556Srgrimes
7617987Speter	if (n == NULL)
7717987Speter		return;
7817987Speter
791556Srgrimes	indent(ind, pfx, fp);
801556Srgrimes	switch(n->type) {
811556Srgrimes	case NSEMI:
821556Srgrimes		s = "; ";
831556Srgrimes		goto binop;
841556Srgrimes	case NAND:
851556Srgrimes		s = " && ";
861556Srgrimes		goto binop;
871556Srgrimes	case NOR:
881556Srgrimes		s = " || ";
891556Srgrimesbinop:
901556Srgrimes		shtree(n->nbinary.ch1, ind, NULL, fp);
911556Srgrimes	   /*    if (ind < 0) */
921556Srgrimes			fputs(s, fp);
931556Srgrimes		shtree(n->nbinary.ch2, ind, NULL, fp);
941556Srgrimes		break;
951556Srgrimes	case NCMD:
961556Srgrimes		shcmd(n, fp);
971556Srgrimes		if (ind >= 0)
981556Srgrimes			putc('\n', fp);
991556Srgrimes		break;
1001556Srgrimes	case NPIPE:
1011556Srgrimes		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1021556Srgrimes			shcmd(lp->n, fp);
1031556Srgrimes			if (lp->next)
1041556Srgrimes				fputs(" | ", fp);
1051556Srgrimes		}
1061556Srgrimes		if (n->npipe.backgnd)
1071556Srgrimes			fputs(" &", fp);
1081556Srgrimes		if (ind >= 0)
1091556Srgrimes			putc('\n', fp);
1101556Srgrimes		break;
1111556Srgrimes	default:
1121556Srgrimes		fprintf(fp, "<node type %d>", n->type);
1131556Srgrimes		if (ind >= 0)
1141556Srgrimes			putc('\n', fp);
1151556Srgrimes		break;
1161556Srgrimes	}
1171556Srgrimes}
1181556Srgrimes
1191556Srgrimes
1201556Srgrimes
121213811Sobrienstatic void
12290111Simpshcmd(union node *cmd, FILE *fp)
12317987Speter{
1241556Srgrimes	union node *np;
1251556Srgrimes	int first;
1261556Srgrimes	char *s;
1271556Srgrimes	int dftfd;
1281556Srgrimes
1291556Srgrimes	first = 1;
1301556Srgrimes	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
1311556Srgrimes		if (! first)
1321556Srgrimes			putchar(' ');
1331556Srgrimes		sharg(np, fp);
1341556Srgrimes		first = 0;
1351556Srgrimes	}
1361556Srgrimes	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
1371556Srgrimes		if (! first)
1381556Srgrimes			putchar(' ');
1391556Srgrimes		switch (np->nfile.type) {
1401556Srgrimes			case NTO:	s = ">";  dftfd = 1; break;
1411556Srgrimes			case NAPPEND:	s = ">>"; dftfd = 1; break;
1421556Srgrimes			case NTOFD:	s = ">&"; dftfd = 1; break;
14396922Stjr			case NCLOBBER:	s = ">|"; dftfd = 1; break;
1441556Srgrimes			case NFROM:	s = "<";  dftfd = 0; break;
14566612Sbrian			case NFROMTO:	s = "<>"; dftfd = 0; break;
1461556Srgrimes			case NFROMFD:	s = "<&"; dftfd = 0; break;
147157750Sschweikh			case NHERE:	s = "<<"; dftfd = 0; break;
148157750Sschweikh			case NXHERE:	s = "<<"; dftfd = 0; break;
14917987Speter			default:  	s = "*error*"; dftfd = 0; break;
1501556Srgrimes		}
1511556Srgrimes		if (np->nfile.fd != dftfd)
1521556Srgrimes			fprintf(fp, "%d", np->nfile.fd);
1531556Srgrimes		fputs(s, fp);
1541556Srgrimes		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
15599634Stjr			if (np->ndup.dupfd >= 0)
15699634Stjr				fprintf(fp, "%d", np->ndup.dupfd);
15799634Stjr			else
15899634Stjr				fprintf(fp, "-");
159157750Sschweikh		} else if (np->nfile.type == NHERE) {
160157750Sschweikh				fprintf(fp, "HERE");
161157750Sschweikh		} else if (np->nfile.type == NXHERE) {
162157750Sschweikh				fprintf(fp, "XHERE");
1631556Srgrimes		} else {
1641556Srgrimes			sharg(np->nfile.fname, fp);
1651556Srgrimes		}
1661556Srgrimes		first = 0;
1671556Srgrimes	}
1681556Srgrimes}
1691556Srgrimes
1701556Srgrimes
1711556Srgrimes
172213811Sobrienstatic void
17390111Simpsharg(union node *arg, FILE *fp)
17490111Simp{
1751556Srgrimes	char *p;
1761556Srgrimes	struct nodelist *bqlist;
1771556Srgrimes	int subtype;
1781556Srgrimes
1791556Srgrimes	if (arg->type != NARG) {
1801556Srgrimes		printf("<node type %d>\n", arg->type);
1811556Srgrimes		fflush(stdout);
1821556Srgrimes		abort();
1831556Srgrimes	}
1841556Srgrimes	bqlist = arg->narg.backquote;
1851556Srgrimes	for (p = arg->narg.text ; *p ; p++) {
1861556Srgrimes		switch (*p) {
1871556Srgrimes		case CTLESC:
1881556Srgrimes			putc(*++p, fp);
1891556Srgrimes			break;
1901556Srgrimes		case CTLVAR:
1911556Srgrimes			putc('$', fp);
1921556Srgrimes			putc('{', fp);
1931556Srgrimes			subtype = *++p;
19417987Speter			if (subtype == VSLENGTH)
19517987Speter				putc('#', fp);
19617987Speter
1971556Srgrimes			while (*p != '=')
1981556Srgrimes				putc(*p++, fp);
19917987Speter
2001556Srgrimes			if (subtype & VSNUL)
2011556Srgrimes				putc(':', fp);
20217987Speter
2031556Srgrimes			switch (subtype & VSTYPE) {
2041556Srgrimes			case VSNORMAL:
2051556Srgrimes				putc('}', fp);
2061556Srgrimes				break;
2071556Srgrimes			case VSMINUS:
2081556Srgrimes				putc('-', fp);
2091556Srgrimes				break;
2101556Srgrimes			case VSPLUS:
2111556Srgrimes				putc('+', fp);
2121556Srgrimes				break;
2131556Srgrimes			case VSQUESTION:
2141556Srgrimes				putc('?', fp);
2151556Srgrimes				break;
2161556Srgrimes			case VSASSIGN:
2171556Srgrimes				putc('=', fp);
2181556Srgrimes				break;
21917987Speter			case VSTRIMLEFT:
22017987Speter				putc('#', fp);
22117987Speter				break;
22217987Speter			case VSTRIMLEFTMAX:
22317987Speter				putc('#', fp);
22417987Speter				putc('#', fp);
22517987Speter				break;
22617987Speter			case VSTRIMRIGHT:
22717987Speter				putc('%', fp);
22817987Speter				break;
22917987Speter			case VSTRIMRIGHTMAX:
23017987Speter				putc('%', fp);
23117987Speter				putc('%', fp);
23217987Speter				break;
23317987Speter			case VSLENGTH:
23417987Speter				break;
2351556Srgrimes			default:
2361556Srgrimes				printf("<subtype %d>", subtype);
2371556Srgrimes			}
2381556Srgrimes			break;
2391556Srgrimes		case CTLENDVAR:
2401556Srgrimes		     putc('}', fp);
2411556Srgrimes		     break;
2421556Srgrimes		case CTLBACKQ:
2431556Srgrimes		case CTLBACKQ|CTLQUOTE:
2441556Srgrimes			putc('$', fp);
2451556Srgrimes			putc('(', fp);
2461556Srgrimes			shtree(bqlist->n, -1, NULL, fp);
2471556Srgrimes			putc(')', fp);
2481556Srgrimes			break;
2491556Srgrimes		default:
2501556Srgrimes			putc(*p, fp);
2511556Srgrimes			break;
2521556Srgrimes		}
2531556Srgrimes	}
2541556Srgrimes}
2551556Srgrimes
2561556Srgrimes
257213811Sobrienstatic void
25890111Simpindent(int amount, char *pfx, FILE *fp)
25917987Speter{
2601556Srgrimes	int i;
2611556Srgrimes
2621556Srgrimes	for (i = 0 ; i < amount ; i++) {
2631556Srgrimes		if (pfx && i == amount - 1)
2641556Srgrimes			fputs(pfx, fp);
2651556Srgrimes		putc('\t', fp);
2661556Srgrimes	}
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimes
2701556Srgrimes/*
2711556Srgrimes * Debugging stuff.
2721556Srgrimes */
2731556Srgrimes
2741556Srgrimes
2751556SrgrimesFILE *tracefile;
2761556Srgrimes
277213744Sobrien#if DEBUG >= 2
2781556Srgrimesint debug = 1;
2791556Srgrimes#else
2801556Srgrimesint debug = 0;
2811556Srgrimes#endif
2821556Srgrimes
2831556Srgrimes
28417987Spetervoid
28590111Simptrputc(int c)
28617987Speter{
2871556Srgrimes	if (tracefile == NULL)
2881556Srgrimes		return;
2891556Srgrimes	putc(c, tracefile);
2901556Srgrimes	if (c == '\n')
2911556Srgrimes		fflush(tracefile);
2921556Srgrimes}
2931556Srgrimes
29420425Ssteve
29517987Spetervoid
29659438Scracauersh_trace(const char *fmt, ...)
29717987Speter{
29817987Speter	va_list va;
29917987Speter	va_start(va, fmt);
30017987Speter	if (tracefile != NULL) {
30117987Speter		(void) vfprintf(tracefile, fmt, va);
30217987Speter		if (strchr(fmt, '\n'))
30317987Speter			(void) fflush(tracefile);
30417987Speter	}
30517987Speter	va_end(va);
3061556Srgrimes}
3071556Srgrimes
3081556Srgrimes
30917987Spetervoid
310200956Sjillestrputs(const char *s)
31117987Speter{
3121556Srgrimes	if (tracefile == NULL)
3131556Srgrimes		return;
3141556Srgrimes	fputs(s, tracefile);
3151556Srgrimes	if (strchr(s, '\n'))
3161556Srgrimes		fflush(tracefile);
3171556Srgrimes}
3181556Srgrimes
3191556Srgrimes
320213811Sobrienstatic void
32190111Simptrstring(char *s)
32217987Speter{
32325222Ssteve	char *p;
3241556Srgrimes	char c;
3251556Srgrimes
3261556Srgrimes	if (tracefile == NULL)
3271556Srgrimes		return;
3281556Srgrimes	putc('"', tracefile);
3291556Srgrimes	for (p = s ; *p ; p++) {
3301556Srgrimes		switch (*p) {
3311556Srgrimes		case '\n':  c = 'n';  goto backslash;
3321556Srgrimes		case '\t':  c = 't';  goto backslash;
3331556Srgrimes		case '\r':  c = 'r';  goto backslash;
3341556Srgrimes		case '"':  c = '"';  goto backslash;
3351556Srgrimes		case '\\':  c = '\\';  goto backslash;
3361556Srgrimes		case CTLESC:  c = 'e';  goto backslash;
3371556Srgrimes		case CTLVAR:  c = 'v';  goto backslash;
3381556Srgrimes		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
3391556Srgrimes		case CTLBACKQ:  c = 'q';  goto backslash;
3401556Srgrimes		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
3411556Srgrimesbackslash:	  putc('\\', tracefile);
3421556Srgrimes			putc(c, tracefile);
3431556Srgrimes			break;
3441556Srgrimes		default:
3451556Srgrimes			if (*p >= ' ' && *p <= '~')
3461556Srgrimes				putc(*p, tracefile);
3471556Srgrimes			else {
3481556Srgrimes				putc('\\', tracefile);
3491556Srgrimes				putc(*p >> 6 & 03, tracefile);
3501556Srgrimes				putc(*p >> 3 & 07, tracefile);
3511556Srgrimes				putc(*p & 07, tracefile);
3521556Srgrimes			}
3531556Srgrimes			break;
3541556Srgrimes		}
3551556Srgrimes	}
3561556Srgrimes	putc('"', tracefile);
35718018Speter}
3581556Srgrimes
3591556Srgrimes
36017987Spetervoid
36190111Simptrargs(char **ap)
36217987Speter{
3631556Srgrimes	if (tracefile == NULL)
3641556Srgrimes		return;
3651556Srgrimes	while (*ap) {
3661556Srgrimes		trstring(*ap++);
3671556Srgrimes		if (*ap)
3681556Srgrimes			putc(' ', tracefile);
3691556Srgrimes		else
3701556Srgrimes			putc('\n', tracefile);
3711556Srgrimes	}
3721556Srgrimes	fflush(tracefile);
3731556Srgrimes}
3741556Srgrimes
3751556Srgrimes
37617987Spetervoid
37790111Simpopentrace(void)
37890111Simp{
3791556Srgrimes	char s[100];
3801556Srgrimes	int flags;
3811556Srgrimes
3821556Srgrimes	if (!debug)
3831556Srgrimes		return;
3841556Srgrimes#ifdef not_this_way
38517987Speter	{
38617987Speter		char *p;
38717987Speter		if ((p = getenv("HOME")) == NULL) {
38817987Speter			if (geteuid() == 0)
38917987Speter				p = "/";
39017987Speter			else
39117987Speter				p = "/tmp";
39217987Speter		}
39317987Speter		scopy(p, s);
39417987Speter		strcat(s, "/trace");
3951556Srgrimes	}
3961556Srgrimes#else
3971556Srgrimes	scopy("./trace", s);
3981556Srgrimes#endif /* not_this_way */
3991556Srgrimes	if ((tracefile = fopen(s, "a")) == NULL) {
40053891Scracauer		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
4011556Srgrimes		return;
4021556Srgrimes	}
4031556Srgrimes	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
4041556Srgrimes		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
4051556Srgrimes	fputs("\nTracing started.\n", tracefile);
4061556Srgrimes	fflush(tracefile);
40720425Ssteve}
4081556Srgrimes#endif /* DEBUG */
409