show.c revision 99110
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
41#endif /* not lint */
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/bin/sh/show.c 99110 2002-06-30 05:15:05Z obrien $");
44
45#include <stdio.h>
46#include <stdarg.h>
47#include <errno.h>
48
49#include "shell.h"
50#include "parser.h"
51#include "nodes.h"
52#include "mystring.h"
53#include "show.h"
54
55
56#ifdef DEBUG
57static void shtree(union node *, int, char *, FILE*);
58static void shcmd(union node *, FILE *);
59static void sharg(union node *, FILE *);
60static void indent(int, char *, FILE *);
61static void trstring(char *);
62
63
64void
65showtree(union node *n)
66{
67	trputs("showtree called\n");
68	shtree(n, 1, NULL, stdout);
69}
70
71
72static 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 NCLOBBER:	s = ">|"; dftfd = 1; break;
146			case NFROM:	s = "<";  dftfd = 0; break;
147			case NFROMTO:	s = "<>"; dftfd = 0; break;
148			case NFROMFD:	s = "<&"; dftfd = 0; break;
149			default:  	s = "*error*"; dftfd = 0; break;
150		}
151		if (np->nfile.fd != dftfd)
152			fprintf(fp, "%d", np->nfile.fd);
153		fputs(s, fp);
154		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
155			fprintf(fp, "%d", np->ndup.dupfd);
156		} else {
157			sharg(np->nfile.fname, fp);
158		}
159		first = 0;
160	}
161}
162
163
164
165static void
166sharg(union node *arg, FILE *fp)
167{
168	char *p;
169	struct nodelist *bqlist;
170	int subtype;
171
172	if (arg->type != NARG) {
173		printf("<node type %d>\n", arg->type);
174		fflush(stdout);
175		abort();
176	}
177	bqlist = arg->narg.backquote;
178	for (p = arg->narg.text ; *p ; p++) {
179		switch (*p) {
180		case CTLESC:
181			putc(*++p, fp);
182			break;
183		case CTLVAR:
184			putc('$', fp);
185			putc('{', fp);
186			subtype = *++p;
187			if (subtype == VSLENGTH)
188				putc('#', fp);
189
190			while (*p != '=')
191				putc(*p++, fp);
192
193			if (subtype & VSNUL)
194				putc(':', fp);
195
196			switch (subtype & VSTYPE) {
197			case VSNORMAL:
198				putc('}', fp);
199				break;
200			case VSMINUS:
201				putc('-', fp);
202				break;
203			case VSPLUS:
204				putc('+', fp);
205				break;
206			case VSQUESTION:
207				putc('?', fp);
208				break;
209			case VSASSIGN:
210				putc('=', fp);
211				break;
212			case VSTRIMLEFT:
213				putc('#', fp);
214				break;
215			case VSTRIMLEFTMAX:
216				putc('#', fp);
217				putc('#', fp);
218				break;
219			case VSTRIMRIGHT:
220				putc('%', fp);
221				break;
222			case VSTRIMRIGHTMAX:
223				putc('%', fp);
224				putc('%', fp);
225				break;
226			case VSLENGTH:
227				break;
228			default:
229				printf("<subtype %d>", subtype);
230			}
231			break;
232		case CTLENDVAR:
233		     putc('}', fp);
234		     break;
235		case CTLBACKQ:
236		case CTLBACKQ|CTLQUOTE:
237			putc('$', fp);
238			putc('(', fp);
239			shtree(bqlist->n, -1, NULL, fp);
240			putc(')', fp);
241			break;
242		default:
243			putc(*p, fp);
244			break;
245		}
246	}
247}
248
249
250static void
251indent(int amount, char *pfx, FILE *fp)
252{
253	int i;
254
255	for (i = 0 ; i < amount ; i++) {
256		if (pfx && i == amount - 1)
257			fputs(pfx, fp);
258		putc('\t', fp);
259	}
260}
261
262
263/*
264 * Debugging stuff.
265 */
266
267
268FILE *tracefile;
269
270#if DEBUG == 2
271int debug = 1;
272#else
273int debug = 0;
274#endif
275
276
277void
278trputc(int c)
279{
280	if (tracefile == NULL)
281		return;
282	putc(c, tracefile);
283	if (c == '\n')
284		fflush(tracefile);
285}
286
287
288void
289sh_trace(const char *fmt, ...)
290{
291	va_list va;
292	va_start(va, fmt);
293	if (tracefile != NULL) {
294		(void) vfprintf(tracefile, fmt, va);
295		if (strchr(fmt, '\n'))
296			(void) fflush(tracefile);
297	}
298	va_end(va);
299}
300
301
302void
303trputs(char *s)
304{
305	if (tracefile == NULL)
306		return;
307	fputs(s, tracefile);
308	if (strchr(s, '\n'))
309		fflush(tracefile);
310}
311
312
313static void
314trstring(char *s)
315{
316	char *p;
317	char c;
318
319	if (tracefile == NULL)
320		return;
321	putc('"', tracefile);
322	for (p = s ; *p ; p++) {
323		switch (*p) {
324		case '\n':  c = 'n';  goto backslash;
325		case '\t':  c = 't';  goto backslash;
326		case '\r':  c = 'r';  goto backslash;
327		case '"':  c = '"';  goto backslash;
328		case '\\':  c = '\\';  goto backslash;
329		case CTLESC:  c = 'e';  goto backslash;
330		case CTLVAR:  c = 'v';  goto backslash;
331		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
332		case CTLBACKQ:  c = 'q';  goto backslash;
333		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
334backslash:	  putc('\\', tracefile);
335			putc(c, tracefile);
336			break;
337		default:
338			if (*p >= ' ' && *p <= '~')
339				putc(*p, tracefile);
340			else {
341				putc('\\', tracefile);
342				putc(*p >> 6 & 03, tracefile);
343				putc(*p >> 3 & 07, tracefile);
344				putc(*p & 07, tracefile);
345			}
346			break;
347		}
348	}
349	putc('"', tracefile);
350}
351
352
353void
354trargs(char **ap)
355{
356	if (tracefile == NULL)
357		return;
358	while (*ap) {
359		trstring(*ap++);
360		if (*ap)
361			putc(' ', tracefile);
362		else
363			putc('\n', tracefile);
364	}
365	fflush(tracefile);
366}
367
368
369void
370opentrace(void)
371{
372	char s[100];
373	char *getenv();
374#ifdef O_APPEND
375	int flags;
376#endif
377
378	if (!debug)
379		return;
380#ifdef not_this_way
381	{
382		char *p;
383		if ((p = getenv("HOME")) == NULL) {
384			if (geteuid() == 0)
385				p = "/";
386			else
387				p = "/tmp";
388		}
389		scopy(p, s);
390		strcat(s, "/trace");
391	}
392#else
393	scopy("./trace", s);
394#endif /* not_this_way */
395	if ((tracefile = fopen(s, "a")) == NULL) {
396		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
397		return;
398	}
399#ifdef O_APPEND
400	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
401		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
402#endif
403	fputs("\nTracing started.\n", tracefile);
404	fflush(tracefile);
405}
406#endif /* DEBUG */
407