show.c revision 90111
174667Sjedgar/*-
290781Sjedgar * Copyright (c) 1991, 1993
374667Sjedgar *	The Regents of the University of California.  All rights reserved.
474667Sjedgar *
574667Sjedgar * This code is derived from software contributed to Berkeley by
674667Sjedgar * Kenneth Almquist.
774667Sjedgar *
874667Sjedgar * Redistribution and use in source and binary forms, with or without
974667Sjedgar * modification, are permitted provided that the following conditions
1074667Sjedgar * are met:
1174667Sjedgar * 1. Redistributions of source code must retain the above copyright
1274667Sjedgar *    notice, this list of conditions and the following disclaimer.
1374667Sjedgar * 2. Redistributions in binary form must reproduce the above copyright
1474667Sjedgar *    notice, this list of conditions and the following disclaimer in the
1574667Sjedgar *    documentation and/or other materials provided with the distribution.
1674667Sjedgar * 3. All advertising materials mentioning features or use of this software
17184607Simp *    must display the following acknowledgement:
18184607Simp *	This product includes software developed by the University of
19184607Simp *	California, Berkeley and its contributors.
20184607Simp * 4. Neither the name of the University nor the names of its contributors
21184607Simp *    may be used to endorse or promote products derived from this software
22184607Simp *    without specific prior written permission.
23184607Simp *
24184607Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2574667Sjedgar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2674667Sjedgar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2792986Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2892986Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2992986Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3074667Sjedgar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3175185Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3274667Sjedgar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3375185Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3474667Sjedgar * SUCH DAMAGE.
3574667Sjedgar */
3674667Sjedgar
3774667Sjedgar#ifndef lint
3874667Sjedgar#if 0
3975928Sjedgarstatic char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95";
4074667Sjedgar#endif
4174667Sjedgarstatic const char rcsid[] =
4274667Sjedgar  "$FreeBSD: head/bin/sh/show.c 90111 2002-02-02 06:50:57Z imp $";
4374667Sjedgar#endif /* not lint */
4474667Sjedgar
4574667Sjedgar#include <stdio.h>
4690781Sjedgar#include <stdarg.h>
4774667Sjedgar#include <errno.h>
4890781Sjedgar
4974667Sjedgar#include "shell.h"
5074667Sjedgar#include "parser.h"
5174667Sjedgar#include "nodes.h"
5274667Sjedgar#include "mystring.h"
5374667Sjedgar#include "show.h"
5474667Sjedgar
5590781Sjedgar
5674667Sjedgar#ifdef DEBUG
5774667Sjedgarstatic void shtree(union node *, int, char *, FILE*);
5874667Sjedgarstatic void shcmd(union node *, FILE *);
5974667Sjedgarstatic void sharg(union node *, FILE *);
6074667Sjedgarstatic void indent(int, char *, FILE *);
6174667Sjedgarstatic void trstring(char *);
6274667Sjedgar
6390781Sjedgar
6474667Sjedgarvoid
6574667Sjedgarshowtree(union node *n)
6674667Sjedgar{
6774667Sjedgar	trputs("showtree called\n");
6874667Sjedgar	shtree(n, 1, NULL, stdout);
6974667Sjedgar}
7074667Sjedgar
7190781Sjedgar
7274667Sjedgarstatic void
73shtree(union node *n, int ind, char *pfx, FILE *fp)
74{
75	struct nodelist *lp;
76	char *s;
77
78	if (n == NULL)
79		return;
80
81	indent(ind, pfx, fp);
82	switch(n->type) {
83	case NSEMI:
84		s = "; ";
85		goto binop;
86	case NAND:
87		s = " && ";
88		goto binop;
89	case NOR:
90		s = " || ";
91binop:
92		shtree(n->nbinary.ch1, ind, NULL, fp);
93	   /*    if (ind < 0) */
94			fputs(s, fp);
95		shtree(n->nbinary.ch2, ind, NULL, fp);
96		break;
97	case NCMD:
98		shcmd(n, fp);
99		if (ind >= 0)
100			putc('\n', fp);
101		break;
102	case NPIPE:
103		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
104			shcmd(lp->n, fp);
105			if (lp->next)
106				fputs(" | ", fp);
107		}
108		if (n->npipe.backgnd)
109			fputs(" &", fp);
110		if (ind >= 0)
111			putc('\n', fp);
112		break;
113	default:
114		fprintf(fp, "<node type %d>", n->type);
115		if (ind >= 0)
116			putc('\n', fp);
117		break;
118	}
119}
120
121
122
123static void
124shcmd(union node *cmd, FILE *fp)
125{
126	union node *np;
127	int first;
128	char *s;
129	int dftfd;
130
131	first = 1;
132	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
133		if (! first)
134			putchar(' ');
135		sharg(np, fp);
136		first = 0;
137	}
138	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
139		if (! first)
140			putchar(' ');
141		switch (np->nfile.type) {
142			case NTO:	s = ">";  dftfd = 1; break;
143			case NAPPEND:	s = ">>"; dftfd = 1; break;
144			case NTOFD:	s = ">&"; dftfd = 1; break;
145			case NFROM:	s = "<";  dftfd = 0; break;
146			case NFROMTO:	s = "<>"; dftfd = 0; break;
147			case NFROMFD:	s = "<&"; dftfd = 0; break;
148			default:  	s = "*error*"; dftfd = 0; break;
149		}
150		if (np->nfile.fd != dftfd)
151			fprintf(fp, "%d", np->nfile.fd);
152		fputs(s, fp);
153		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
154			fprintf(fp, "%d", np->ndup.dupfd);
155		} else {
156			sharg(np->nfile.fname, fp);
157		}
158		first = 0;
159	}
160}
161
162
163
164static void
165sharg(union node *arg, FILE *fp)
166{
167	char *p;
168	struct nodelist *bqlist;
169	int subtype;
170
171	if (arg->type != NARG) {
172		printf("<node type %d>\n", arg->type);
173		fflush(stdout);
174		abort();
175	}
176	bqlist = arg->narg.backquote;
177	for (p = arg->narg.text ; *p ; p++) {
178		switch (*p) {
179		case CTLESC:
180			putc(*++p, fp);
181			break;
182		case CTLVAR:
183			putc('$', fp);
184			putc('{', fp);
185			subtype = *++p;
186			if (subtype == VSLENGTH)
187				putc('#', fp);
188
189			while (*p != '=')
190				putc(*p++, fp);
191
192			if (subtype & VSNUL)
193				putc(':', fp);
194
195			switch (subtype & VSTYPE) {
196			case VSNORMAL:
197				putc('}', fp);
198				break;
199			case VSMINUS:
200				putc('-', fp);
201				break;
202			case VSPLUS:
203				putc('+', fp);
204				break;
205			case VSQUESTION:
206				putc('?', fp);
207				break;
208			case VSASSIGN:
209				putc('=', fp);
210				break;
211			case VSTRIMLEFT:
212				putc('#', fp);
213				break;
214			case VSTRIMLEFTMAX:
215				putc('#', fp);
216				putc('#', fp);
217				break;
218			case VSTRIMRIGHT:
219				putc('%', fp);
220				break;
221			case VSTRIMRIGHTMAX:
222				putc('%', fp);
223				putc('%', fp);
224				break;
225			case VSLENGTH:
226				break;
227			default:
228				printf("<subtype %d>", subtype);
229			}
230			break;
231		case CTLENDVAR:
232		     putc('}', fp);
233		     break;
234		case CTLBACKQ:
235		case CTLBACKQ|CTLQUOTE:
236			putc('$', fp);
237			putc('(', fp);
238			shtree(bqlist->n, -1, NULL, fp);
239			putc(')', fp);
240			break;
241		default:
242			putc(*p, fp);
243			break;
244		}
245	}
246}
247
248
249static void
250indent(int amount, char *pfx, FILE *fp)
251{
252	int i;
253
254	for (i = 0 ; i < amount ; i++) {
255		if (pfx && i == amount - 1)
256			fputs(pfx, fp);
257		putc('\t', fp);
258	}
259}
260
261
262/*
263 * Debugging stuff.
264 */
265
266
267FILE *tracefile;
268
269#if DEBUG == 2
270int debug = 1;
271#else
272int debug = 0;
273#endif
274
275
276void
277trputc(int c)
278{
279	if (tracefile == NULL)
280		return;
281	putc(c, tracefile);
282	if (c == '\n')
283		fflush(tracefile);
284}
285
286
287void
288sh_trace(const char *fmt, ...)
289{
290	va_list va;
291	va_start(va, fmt);
292	if (tracefile != NULL) {
293		(void) vfprintf(tracefile, fmt, va);
294		if (strchr(fmt, '\n'))
295			(void) fflush(tracefile);
296	}
297	va_end(va);
298}
299
300
301void
302trputs(char *s)
303{
304	if (tracefile == NULL)
305		return;
306	fputs(s, tracefile);
307	if (strchr(s, '\n'))
308		fflush(tracefile);
309}
310
311
312static void
313trstring(char *s)
314{
315	char *p;
316	char c;
317
318	if (tracefile == NULL)
319		return;
320	putc('"', tracefile);
321	for (p = s ; *p ; p++) {
322		switch (*p) {
323		case '\n':  c = 'n';  goto backslash;
324		case '\t':  c = 't';  goto backslash;
325		case '\r':  c = 'r';  goto backslash;
326		case '"':  c = '"';  goto backslash;
327		case '\\':  c = '\\';  goto backslash;
328		case CTLESC:  c = 'e';  goto backslash;
329		case CTLVAR:  c = 'v';  goto backslash;
330		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
331		case CTLBACKQ:  c = 'q';  goto backslash;
332		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
333backslash:	  putc('\\', tracefile);
334			putc(c, tracefile);
335			break;
336		default:
337			if (*p >= ' ' && *p <= '~')
338				putc(*p, tracefile);
339			else {
340				putc('\\', tracefile);
341				putc(*p >> 6 & 03, tracefile);
342				putc(*p >> 3 & 07, tracefile);
343				putc(*p & 07, tracefile);
344			}
345			break;
346		}
347	}
348	putc('"', tracefile);
349}
350
351
352void
353trargs(char **ap)
354{
355	if (tracefile == NULL)
356		return;
357	while (*ap) {
358		trstring(*ap++);
359		if (*ap)
360			putc(' ', tracefile);
361		else
362			putc('\n', tracefile);
363	}
364	fflush(tracefile);
365}
366
367
368void
369opentrace(void)
370{
371	char s[100];
372	char *getenv();
373#ifdef O_APPEND
374	int flags;
375#endif
376
377	if (!debug)
378		return;
379#ifdef not_this_way
380	{
381		char *p;
382		if ((p = getenv("HOME")) == NULL) {
383			if (geteuid() == 0)
384				p = "/";
385			else
386				p = "/tmp";
387		}
388		scopy(p, s);
389		strcat(s, "/trace");
390	}
391#else
392	scopy("./trace", s);
393#endif /* not_this_way */
394	if ((tracefile = fopen(s, "a")) == NULL) {
395		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
396		return;
397	}
398#ifdef O_APPEND
399	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
400		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
401#endif
402	fputs("\nTracing started.\n", tracefile);
403	fflush(tracefile);
404}
405#endif /* DEBUG */
406