show.c revision 66612
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38#if 0
39static char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95";
40#endif
41static const char rcsid[] =
42  "$FreeBSD: head/bin/sh/show.c 66612 2000-10-03 23:13:14Z brian $";
43#endif /* not lint */
44
45#include <stdio.h>
46#ifdef __STDC__
47#include <stdarg.h>
48#else
49#include <varargs.h>
50#endif
51#if DEBUG == 2
52#include <errno.h>
53#endif
54#include <errno.h>
55
56#include "shell.h"
57#include "parser.h"
58#include "nodes.h"
59#include "mystring.h"
60#include "show.h"
61
62
63#ifdef DEBUG
64static void shtree __P((union node *, int, char *, FILE*));
65static void shcmd __P((union node *, FILE *));
66static void sharg __P((union node *, FILE *));
67static void indent __P((int, char *, FILE *));
68static void trstring __P((char *));
69
70
71void
72showtree(n)
73	union node *n;
74{
75	trputs("showtree called\n");
76	shtree(n, 1, NULL, stdout);
77}
78
79
80static void
81shtree(n, ind, pfx, fp)
82	union node *n;
83	int ind;
84	char *pfx;
85	FILE *fp;
86{
87	struct nodelist *lp;
88	char *s;
89
90	if (n == NULL)
91		return;
92
93	indent(ind, pfx, fp);
94	switch(n->type) {
95	case NSEMI:
96		s = "; ";
97		goto binop;
98	case NAND:
99		s = " && ";
100		goto binop;
101	case NOR:
102		s = " || ";
103binop:
104		shtree(n->nbinary.ch1, ind, NULL, fp);
105	   /*    if (ind < 0) */
106			fputs(s, fp);
107		shtree(n->nbinary.ch2, ind, NULL, fp);
108		break;
109	case NCMD:
110		shcmd(n, fp);
111		if (ind >= 0)
112			putc('\n', fp);
113		break;
114	case NPIPE:
115		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
116			shcmd(lp->n, fp);
117			if (lp->next)
118				fputs(" | ", fp);
119		}
120		if (n->npipe.backgnd)
121			fputs(" &", fp);
122		if (ind >= 0)
123			putc('\n', fp);
124		break;
125	default:
126		fprintf(fp, "<node type %d>", n->type);
127		if (ind >= 0)
128			putc('\n', fp);
129		break;
130	}
131}
132
133
134
135static void
136shcmd(cmd, fp)
137	union node *cmd;
138	FILE *fp;
139{
140	union node *np;
141	int first;
142	char *s;
143	int dftfd;
144
145	first = 1;
146	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
147		if (! first)
148			putchar(' ');
149		sharg(np, fp);
150		first = 0;
151	}
152	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
153		if (! first)
154			putchar(' ');
155		switch (np->nfile.type) {
156			case NTO:	s = ">";  dftfd = 1; break;
157			case NAPPEND:	s = ">>"; dftfd = 1; break;
158			case NTOFD:	s = ">&"; dftfd = 1; break;
159			case NFROM:	s = "<";  dftfd = 0; break;
160			case NFROMTO:	s = "<>"; dftfd = 0; break;
161			case NFROMFD:	s = "<&"; dftfd = 0; break;
162			default:  	s = "*error*"; dftfd = 0; break;
163		}
164		if (np->nfile.fd != dftfd)
165			fprintf(fp, "%d", np->nfile.fd);
166		fputs(s, fp);
167		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
168			fprintf(fp, "%d", np->ndup.dupfd);
169		} else {
170			sharg(np->nfile.fname, fp);
171		}
172		first = 0;
173	}
174}
175
176
177
178static void
179sharg(arg, fp)
180	union node *arg;
181	FILE *fp;
182	{
183	char *p;
184	struct nodelist *bqlist;
185	int subtype;
186
187	if (arg->type != NARG) {
188		printf("<node type %d>\n", arg->type);
189		fflush(stdout);
190		abort();
191	}
192	bqlist = arg->narg.backquote;
193	for (p = arg->narg.text ; *p ; p++) {
194		switch (*p) {
195		case CTLESC:
196			putc(*++p, fp);
197			break;
198		case CTLVAR:
199			putc('$', fp);
200			putc('{', fp);
201			subtype = *++p;
202			if (subtype == VSLENGTH)
203				putc('#', fp);
204
205			while (*p != '=')
206				putc(*p++, fp);
207
208			if (subtype & VSNUL)
209				putc(':', fp);
210
211			switch (subtype & VSTYPE) {
212			case VSNORMAL:
213				putc('}', fp);
214				break;
215			case VSMINUS:
216				putc('-', fp);
217				break;
218			case VSPLUS:
219				putc('+', fp);
220				break;
221			case VSQUESTION:
222				putc('?', fp);
223				break;
224			case VSASSIGN:
225				putc('=', fp);
226				break;
227			case VSTRIMLEFT:
228				putc('#', fp);
229				break;
230			case VSTRIMLEFTMAX:
231				putc('#', fp);
232				putc('#', fp);
233				break;
234			case VSTRIMRIGHT:
235				putc('%', fp);
236				break;
237			case VSTRIMRIGHTMAX:
238				putc('%', fp);
239				putc('%', fp);
240				break;
241			case VSLENGTH:
242				break;
243			default:
244				printf("<subtype %d>", subtype);
245			}
246			break;
247		case CTLENDVAR:
248		     putc('}', fp);
249		     break;
250		case CTLBACKQ:
251		case CTLBACKQ|CTLQUOTE:
252			putc('$', fp);
253			putc('(', fp);
254			shtree(bqlist->n, -1, NULL, fp);
255			putc(')', fp);
256			break;
257		default:
258			putc(*p, fp);
259			break;
260		}
261	}
262}
263
264
265static void
266indent(amount, pfx, fp)
267	int amount;
268	char *pfx;
269	FILE *fp;
270{
271	int i;
272
273	for (i = 0 ; i < amount ; i++) {
274		if (pfx && i == amount - 1)
275			fputs(pfx, fp);
276		putc('\t', fp);
277	}
278}
279
280
281/*
282 * Debugging stuff.
283 */
284
285
286FILE *tracefile;
287
288#if DEBUG == 2
289int debug = 1;
290#else
291int debug = 0;
292#endif
293
294
295void
296trputc(c)
297	int c;
298{
299	if (tracefile == NULL)
300		return;
301	putc(c, tracefile);
302	if (c == '\n')
303		fflush(tracefile);
304}
305
306
307void
308#ifdef __STDC__
309sh_trace(const char *fmt, ...)
310#else
311sh_trace(va_alist)
312	va_dcl
313#endif
314{
315	va_list va;
316#ifdef __STDC__
317	va_start(va, fmt);
318#else
319	char *fmt;
320	va_start(va);
321	fmt = va_arg(va, char *);
322#endif
323	if (tracefile != NULL) {
324		(void) vfprintf(tracefile, fmt, va);
325		if (strchr(fmt, '\n'))
326			(void) fflush(tracefile);
327	}
328	va_end(va);
329}
330
331
332void
333trputs(s)
334	char *s;
335{
336	if (tracefile == NULL)
337		return;
338	fputs(s, tracefile);
339	if (strchr(s, '\n'))
340		fflush(tracefile);
341}
342
343
344static void
345trstring(s)
346	char *s;
347{
348	char *p;
349	char c;
350
351	if (tracefile == NULL)
352		return;
353	putc('"', tracefile);
354	for (p = s ; *p ; p++) {
355		switch (*p) {
356		case '\n':  c = 'n';  goto backslash;
357		case '\t':  c = 't';  goto backslash;
358		case '\r':  c = 'r';  goto backslash;
359		case '"':  c = '"';  goto backslash;
360		case '\\':  c = '\\';  goto backslash;
361		case CTLESC:  c = 'e';  goto backslash;
362		case CTLVAR:  c = 'v';  goto backslash;
363		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
364		case CTLBACKQ:  c = 'q';  goto backslash;
365		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
366backslash:	  putc('\\', tracefile);
367			putc(c, tracefile);
368			break;
369		default:
370			if (*p >= ' ' && *p <= '~')
371				putc(*p, tracefile);
372			else {
373				putc('\\', tracefile);
374				putc(*p >> 6 & 03, tracefile);
375				putc(*p >> 3 & 07, tracefile);
376				putc(*p & 07, tracefile);
377			}
378			break;
379		}
380	}
381	putc('"', tracefile);
382}
383
384
385void
386trargs(ap)
387	char **ap;
388{
389	if (tracefile == NULL)
390		return;
391	while (*ap) {
392		trstring(*ap++);
393		if (*ap)
394			putc(' ', tracefile);
395		else
396			putc('\n', tracefile);
397	}
398	fflush(tracefile);
399}
400
401
402void
403opentrace() {
404	char s[100];
405	char *getenv();
406#ifdef O_APPEND
407	int flags;
408#endif
409
410	if (!debug)
411		return;
412#ifdef not_this_way
413	{
414		char *p;
415		if ((p = getenv("HOME")) == NULL) {
416			if (geteuid() == 0)
417				p = "/";
418			else
419				p = "/tmp";
420		}
421		scopy(p, s);
422		strcat(s, "/trace");
423	}
424#else
425	scopy("./trace", s);
426#endif /* not_this_way */
427	if ((tracefile = fopen(s, "a")) == NULL) {
428		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
429		return;
430	}
431#ifdef O_APPEND
432	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
433		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
434#endif
435	fputs("\nTracing started.\n", tracefile);
436	fflush(tracefile);
437}
438#endif /* DEBUG */
439