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