show.c revision 149742
1214501Srpaulo/*-
2214501Srpaulo * Copyright (c) 1991, 1993
3252726Srpaulo *	The Regents of the University of California.  All rights reserved.
4214501Srpaulo *
5252726Srpaulo * This code is derived from software contributed to Berkeley by
6252726Srpaulo * Kenneth Almquist.
7214501Srpaulo *
8214501Srpaulo * Redistribution and use in source and binary forms, with or without
9214501Srpaulo * modification, are permitted provided that the following conditions
10214501Srpaulo * are met:
11214501Srpaulo * 1. Redistributions of source code must retain the above copyright
12214501Srpaulo *    notice, this list of conditions and the following disclaimer.
13214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
14214501Srpaulo *    notice, this list of conditions and the following disclaimer in the
15252726Srpaulo *    documentation and/or other materials provided with the distribution.
16252726Srpaulo * 4. Neither the name of the University nor the names of its contributors
17214501Srpaulo *    may be used to endorse or promote products derived from this software
18214501Srpaulo *    without specific prior written permission.
19214501Srpaulo *
20214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23214501Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30214501Srpaulo * SUCH DAMAGE.
31214501Srpaulo */
32214501Srpaulo
33214501Srpaulo#ifndef lint
34214501Srpaulo#if 0
35214501Srpaulostatic char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95";
36214501Srpaulo#endif
37214501Srpaulo#endif /* not lint */
38214501Srpaulo#include <sys/cdefs.h>
39214501Srpaulo__FBSDID("$FreeBSD: head/bin/sh/show.c 149742 2005-09-02 22:28:27Z stefanf $");
40214501Srpaulo
41214501Srpaulo#include <fcntl.h>
42214501Srpaulo#include <stdio.h>
43214501Srpaulo#include <stdlib.h>
44214501Srpaulo#include <stdarg.h>
45214501Srpaulo#include <errno.h>
46214501Srpaulo
47214501Srpaulo#include "shell.h"
48214501Srpaulo#include "parser.h"
49214501Srpaulo#include "nodes.h"
50214501Srpaulo#include "mystring.h"
51214501Srpaulo#include "show.h"
52252726Srpaulo
53214501Srpaulo
54252726Srpaulo#ifdef DEBUG
55252726Srpaulostatic void shtree(union node *, int, char *, FILE*);
56214501Srpaulostatic void shcmd(union node *, FILE *);
57214501Srpaulostatic void sharg(union node *, FILE *);
58214501Srpaulostatic void indent(int, char *, FILE *);
59214501Srpaulostatic void trstring(char *);
60214501Srpaulo
61214501Srpaulo
62214501Srpaulovoid
63214501Srpauloshowtree(union node *n)
64214501Srpaulo{
65214501Srpaulo	trputs("showtree called\n");
66214501Srpaulo	shtree(n, 1, NULL, stdout);
67214501Srpaulo}
68214501Srpaulo
69214501Srpaulo
70252726Srpaulostatic void
71252726Srpauloshtree(union node *n, int ind, char *pfx, FILE *fp)
72252726Srpaulo{
73252726Srpaulo	struct nodelist *lp;
74214501Srpaulo	char *s;
75214501Srpaulo
76214501Srpaulo	if (n == NULL)
77214501Srpaulo		return;
78214501Srpaulo
79214501Srpaulo	indent(ind, pfx, fp);
80214501Srpaulo	switch(n->type) {
81214501Srpaulo	case NSEMI:
82214501Srpaulo		s = "; ";
83214501Srpaulo		goto binop;
84214501Srpaulo	case NAND:
85214501Srpaulo		s = " && ";
86214501Srpaulo		goto binop;
87214501Srpaulo	case NOR:
88214501Srpaulo		s = " || ";
89214501Srpaulobinop:
90214501Srpaulo		shtree(n->nbinary.ch1, ind, NULL, fp);
91214501Srpaulo	   /*    if (ind < 0) */
92214501Srpaulo			fputs(s, fp);
93214501Srpaulo		shtree(n->nbinary.ch2, ind, NULL, fp);
94214501Srpaulo		break;
95214501Srpaulo	case NCMD:
96214501Srpaulo		shcmd(n, fp);
97214501Srpaulo		if (ind >= 0)
98214501Srpaulo			putc('\n', fp);
99214501Srpaulo		break;
100252726Srpaulo	case NPIPE:
101252726Srpaulo		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
102252726Srpaulo			shcmd(lp->n, fp);
103252726Srpaulo			if (lp->next)
104252726Srpaulo				fputs(" | ", fp);
105214501Srpaulo		}
106214501Srpaulo		if (n->npipe.backgnd)
107214501Srpaulo			fputs(" &", fp);
108214501Srpaulo		if (ind >= 0)
109214501Srpaulo			putc('\n', fp);
110214501Srpaulo		break;
111214501Srpaulo	default:
112214501Srpaulo		fprintf(fp, "<node type %d>", n->type);
113214501Srpaulo		if (ind >= 0)
114214501Srpaulo			putc('\n', fp);
115214501Srpaulo		break;
116214501Srpaulo	}
117214501Srpaulo}
118214501Srpaulo
119252726Srpaulo
120214501Srpaulo
121214501Srpaulostatic void
122214501Srpauloshcmd(union node *cmd, FILE *fp)
123214501Srpaulo{
124214501Srpaulo	union node *np;
125214501Srpaulo	int first;
126214501Srpaulo	char *s;
127214501Srpaulo	int dftfd;
128214501Srpaulo
129214501Srpaulo	first = 1;
130252726Srpaulo	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
131252726Srpaulo		if (! first)
132252726Srpaulo			putchar(' ');
133252726Srpaulo		sharg(np, fp);
134252726Srpaulo		first = 0;
135214501Srpaulo	}
136214501Srpaulo	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
137252726Srpaulo		if (! first)
138252726Srpaulo			putchar(' ');
139214501Srpaulo		switch (np->nfile.type) {
140214501Srpaulo			case NTO:	s = ">";  dftfd = 1; break;
141214501Srpaulo			case NAPPEND:	s = ">>"; dftfd = 1; break;
142214501Srpaulo			case NTOFD:	s = ">&"; dftfd = 1; break;
143214501Srpaulo			case NCLOBBER:	s = ">|"; dftfd = 1; break;
144214501Srpaulo			case NFROM:	s = "<";  dftfd = 0; break;
145214501Srpaulo			case NFROMTO:	s = "<>"; dftfd = 0; break;
146252726Srpaulo			case NFROMFD:	s = "<&"; dftfd = 0; break;
147252726Srpaulo			default:  	s = "*error*"; dftfd = 0; break;
148252726Srpaulo		}
149252726Srpaulo		if (np->nfile.fd != dftfd)
150252726Srpaulo			fprintf(fp, "%d", np->nfile.fd);
151252726Srpaulo		fputs(s, fp);
152214501Srpaulo		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
153214501Srpaulo			if (np->ndup.dupfd >= 0)
154252726Srpaulo				fprintf(fp, "%d", np->ndup.dupfd);
155252726Srpaulo			else
156252726Srpaulo				fprintf(fp, "-");
157252726Srpaulo		} else {
158252726Srpaulo			sharg(np->nfile.fname, fp);
159214501Srpaulo		}
160252726Srpaulo		first = 0;
161252726Srpaulo	}
162252726Srpaulo}
163252726Srpaulo
164252726Srpaulo
165252726Srpaulo
166252726Srpaulostatic void
167252726Srpaulosharg(union node *arg, FILE *fp)
168252726Srpaulo{
169252726Srpaulo	char *p;
170252726Srpaulo	struct nodelist *bqlist;
171252726Srpaulo	int subtype;
172252726Srpaulo
173252726Srpaulo	if (arg->type != NARG) {
174252726Srpaulo		printf("<node type %d>\n", arg->type);
175252726Srpaulo		fflush(stdout);
176252726Srpaulo		abort();
177214501Srpaulo	}
178214501Srpaulo	bqlist = arg->narg.backquote;
179214501Srpaulo	for (p = arg->narg.text ; *p ; p++) {
180214501Srpaulo		switch (*p) {
181214501Srpaulo		case CTLESC:
182214501Srpaulo			putc(*++p, fp);
183252726Srpaulo			break;
184214501Srpaulo		case CTLVAR:
185214501Srpaulo			putc('$', fp);
186214501Srpaulo			putc('{', fp);
187214501Srpaulo			subtype = *++p;
188214501Srpaulo			if (subtype == VSLENGTH)
189214501Srpaulo				putc('#', fp);
190214501Srpaulo
191214501Srpaulo			while (*p != '=')
192214501Srpaulo				putc(*p++, fp);
193214501Srpaulo
194214501Srpaulo			if (subtype & VSNUL)
195214501Srpaulo				putc(':', fp);
196214501Srpaulo
197214501Srpaulo			switch (subtype & VSTYPE) {
198214501Srpaulo			case VSNORMAL:
199214501Srpaulo				putc('}', fp);
200214501Srpaulo				break;
201252726Srpaulo			case VSMINUS:
202214501Srpaulo				putc('-', fp);
203214501Srpaulo				break;
204214501Srpaulo			case VSPLUS:
205214501Srpaulo				putc('+', fp);
206214501Srpaulo				break;
207252726Srpaulo			case VSQUESTION:
208252726Srpaulo				putc('?', fp);
209252726Srpaulo				break;
210252726Srpaulo			case VSASSIGN:
211252726Srpaulo				putc('=', fp);
212252726Srpaulo				break;
213252726Srpaulo			case VSTRIMLEFT:
214252726Srpaulo				putc('#', fp);
215252726Srpaulo				break;
216214501Srpaulo			case VSTRIMLEFTMAX:
217214501Srpaulo				putc('#', fp);
218214501Srpaulo				putc('#', fp);
219214501Srpaulo				break;
220214501Srpaulo			case VSTRIMRIGHT:
221214501Srpaulo				putc('%', fp);
222214501Srpaulo				break;
223214501Srpaulo			case VSTRIMRIGHTMAX:
224214501Srpaulo				putc('%', fp);
225214501Srpaulo				putc('%', fp);
226214501Srpaulo				break;
227214501Srpaulo			case VSLENGTH:
228214501Srpaulo				break;
229214501Srpaulo			default:
230214501Srpaulo				printf("<subtype %d>", subtype);
231214501Srpaulo			}
232214501Srpaulo			break;
233214501Srpaulo		case CTLENDVAR:
234214501Srpaulo		     putc('}', fp);
235214501Srpaulo		     break;
236214501Srpaulo		case CTLBACKQ:
237214501Srpaulo		case CTLBACKQ|CTLQUOTE:
238214501Srpaulo			putc('$', fp);
239214501Srpaulo			putc('(', fp);
240214501Srpaulo			shtree(bqlist->n, -1, NULL, fp);
241214501Srpaulo			putc(')', fp);
242214501Srpaulo			break;
243214501Srpaulo		default:
244252726Srpaulo			putc(*p, fp);
245214501Srpaulo			break;
246214501Srpaulo		}
247214501Srpaulo	}
248214501Srpaulo}
249214501Srpaulo
250214501Srpaulo
251214501Srpaulostatic void
252214501Srpauloindent(int amount, char *pfx, FILE *fp)
253214501Srpaulo{
254214501Srpaulo	int i;
255214501Srpaulo
256214501Srpaulo	for (i = 0 ; i < amount ; i++) {
257214501Srpaulo		if (pfx && i == amount - 1)
258252726Srpaulo			fputs(pfx, fp);
259252726Srpaulo		putc('\t', fp);
260252726Srpaulo	}
261252726Srpaulo}
262252726Srpaulo
263214501Srpaulo
264214501Srpaulo/*
265214501Srpaulo * Debugging stuff.
266214501Srpaulo */
267214501Srpaulo
268214501Srpaulo
269214501SrpauloFILE *tracefile;
270214501Srpaulo
271214501Srpaulo#if DEBUG == 2
272214501Srpauloint debug = 1;
273214501Srpaulo#else
274214501Srpauloint debug = 0;
275214501Srpaulo#endif
276214501Srpaulo
277214501Srpaulo
278214501Srpaulovoid
279214501Srpaulotrputc(int c)
280214501Srpaulo{
281214501Srpaulo	if (tracefile == NULL)
282214501Srpaulo		return;
283252726Srpaulo	putc(c, tracefile);
284214501Srpaulo	if (c == '\n')
285214501Srpaulo		fflush(tracefile);
286214501Srpaulo}
287214501Srpaulo
288214501Srpaulo
289214501Srpaulovoid
290214501Srpaulosh_trace(const char *fmt, ...)
291214501Srpaulo{
292214501Srpaulo	va_list va;
293214501Srpaulo	va_start(va, fmt);
294214501Srpaulo	if (tracefile != NULL) {
295214501Srpaulo		(void) vfprintf(tracefile, fmt, va);
296214501Srpaulo		if (strchr(fmt, '\n'))
297214501Srpaulo			(void) fflush(tracefile);
298214501Srpaulo	}
299214501Srpaulo	va_end(va);
300214501Srpaulo}
301214501Srpaulo
302214501Srpaulo
303214501Srpaulovoid
304214501Srpaulotrputs(char *s)
305214501Srpaulo{
306214501Srpaulo	if (tracefile == NULL)
307252726Srpaulo		return;
308252726Srpaulo	fputs(s, tracefile);
309214501Srpaulo	if (strchr(s, '\n'))
310214501Srpaulo		fflush(tracefile);
311214501Srpaulo}
312214501Srpaulo
313214501Srpaulo
314214501Srpaulostatic void
315214501Srpaulotrstring(char *s)
316214501Srpaulo{
317214501Srpaulo	char *p;
318214501Srpaulo	char c;
319214501Srpaulo
320214501Srpaulo	if (tracefile == NULL)
321214501Srpaulo		return;
322214501Srpaulo	putc('"', tracefile);
323214501Srpaulo	for (p = s ; *p ; p++) {
324214501Srpaulo		switch (*p) {
325214501Srpaulo		case '\n':  c = 'n';  goto backslash;
326214501Srpaulo		case '\t':  c = 't';  goto backslash;
327214501Srpaulo		case '\r':  c = 'r';  goto backslash;
328214501Srpaulo		case '"':  c = '"';  goto backslash;
329214501Srpaulo		case '\\':  c = '\\';  goto backslash;
330214501Srpaulo		case CTLESC:  c = 'e';  goto backslash;
331214501Srpaulo		case CTLVAR:  c = 'v';  goto backslash;
332214501Srpaulo		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
333214501Srpaulo		case CTLBACKQ:  c = 'q';  goto backslash;
334214501Srpaulo		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
335214501Srpaulobackslash:	  putc('\\', tracefile);
336214501Srpaulo			putc(c, tracefile);
337214501Srpaulo			break;
338252726Srpaulo		default:
339214501Srpaulo			if (*p >= ' ' && *p <= '~')
340214501Srpaulo				putc(*p, tracefile);
341214501Srpaulo			else {
342214501Srpaulo				putc('\\', tracefile);
343214501Srpaulo				putc(*p >> 6 & 03, tracefile);
344214501Srpaulo				putc(*p >> 3 & 07, tracefile);
345214501Srpaulo				putc(*p & 07, tracefile);
346214501Srpaulo			}
347214501Srpaulo			break;
348214501Srpaulo		}
349214501Srpaulo	}
350214501Srpaulo	putc('"', tracefile);
351252726Srpaulo}
352214501Srpaulo
353214501Srpaulo
354214501Srpaulovoid
355214501Srpaulotrargs(char **ap)
356214501Srpaulo{
357214501Srpaulo	if (tracefile == NULL)
358214501Srpaulo		return;
359214501Srpaulo	while (*ap) {
360214501Srpaulo		trstring(*ap++);
361214501Srpaulo		if (*ap)
362214501Srpaulo			putc(' ', tracefile);
363214501Srpaulo		else
364214501Srpaulo			putc('\n', tracefile);
365214501Srpaulo	}
366214501Srpaulo	fflush(tracefile);
367252726Srpaulo}
368252726Srpaulo
369252726Srpaulo
370252726Srpaulovoid
371252726Srpauloopentrace(void)
372214501Srpaulo{
373252726Srpaulo	char s[100];
374252726Srpaulo	int flags;
375252726Srpaulo
376252726Srpaulo	if (!debug)
377252726Srpaulo		return;
378252726Srpaulo#ifdef not_this_way
379252726Srpaulo	{
380252726Srpaulo		char *p;
381252726Srpaulo		if ((p = getenv("HOME")) == NULL) {
382252726Srpaulo			if (geteuid() == 0)
383252726Srpaulo				p = "/";
384252726Srpaulo			else
385252726Srpaulo				p = "/tmp";
386252726Srpaulo		}
387252726Srpaulo		scopy(p, s);
388252726Srpaulo		strcat(s, "/trace");
389252726Srpaulo	}
390252726Srpaulo#else
391252726Srpaulo	scopy("./trace", s);
392252726Srpaulo#endif /* not_this_way */
393252726Srpaulo	if ((tracefile = fopen(s, "a")) == NULL) {
394252726Srpaulo		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
395252726Srpaulo		return;
396252726Srpaulo	}
397252726Srpaulo	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
398252726Srpaulo		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
399252726Srpaulo	fputs("\nTracing started.\n", tracefile);
400252726Srpaulo	fflush(tracefile);
401252726Srpaulo}
402252726Srpaulo#endif /* DEBUG */
403252726Srpaulo