show.c revision 109627
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 109627 2003-01-21 10:06:04Z tjr $");
44
45#include <fcntl.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <stdarg.h>
49#include <errno.h>
50
51#include "shell.h"
52#include "parser.h"
53#include "nodes.h"
54#include "mystring.h"
55#include "show.h"
56
57
58#ifdef DEBUG
59static void shtree(union node *, int, char *, FILE*);
60static void shcmd(union node *, FILE *);
61static void sharg(union node *, FILE *);
62static void indent(int, char *, FILE *);
63static void trstring(char *);
64
65
66void
67showtree(union node *n)
68{
69	trputs("showtree called\n");
70	shtree(n, 1, NULL, stdout);
71}
72
73
74static void
75shtree(union node *n, int ind, char *pfx, FILE *fp)
76{
77	struct nodelist *lp;
78	char *s;
79
80	if (n == NULL)
81		return;
82
83	indent(ind, pfx, fp);
84	switch(n->type) {
85	case NSEMI:
86		s = "; ";
87		goto binop;
88	case NAND:
89		s = " && ";
90		goto binop;
91	case NOR:
92		s = " || ";
93binop:
94		shtree(n->nbinary.ch1, ind, NULL, fp);
95	   /*    if (ind < 0) */
96			fputs(s, fp);
97		shtree(n->nbinary.ch2, ind, NULL, fp);
98		break;
99	case NCMD:
100		shcmd(n, fp);
101		if (ind >= 0)
102			putc('\n', fp);
103		break;
104	case NPIPE:
105		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
106			shcmd(lp->n, fp);
107			if (lp->next)
108				fputs(" | ", fp);
109		}
110		if (n->npipe.backgnd)
111			fputs(" &", fp);
112		if (ind >= 0)
113			putc('\n', fp);
114		break;
115	default:
116		fprintf(fp, "<node type %d>", n->type);
117		if (ind >= 0)
118			putc('\n', fp);
119		break;
120	}
121}
122
123
124
125static void
126shcmd(union node *cmd, FILE *fp)
127{
128	union node *np;
129	int first;
130	char *s;
131	int dftfd;
132
133	first = 1;
134	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
135		if (! first)
136			putchar(' ');
137		sharg(np, fp);
138		first = 0;
139	}
140	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
141		if (! first)
142			putchar(' ');
143		switch (np->nfile.type) {
144			case NTO:	s = ">";  dftfd = 1; break;
145			case NAPPEND:	s = ">>"; dftfd = 1; break;
146			case NTOFD:	s = ">&"; dftfd = 1; break;
147			case NCLOBBER:	s = ">|"; dftfd = 1; break;
148			case NFROM:	s = "<";  dftfd = 0; break;
149			case NFROMTO:	s = "<>"; dftfd = 0; break;
150			case NFROMFD:	s = "<&"; dftfd = 0; break;
151			default:  	s = "*error*"; dftfd = 0; break;
152		}
153		if (np->nfile.fd != dftfd)
154			fprintf(fp, "%d", np->nfile.fd);
155		fputs(s, fp);
156		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
157			if (np->ndup.dupfd >= 0)
158				fprintf(fp, "%d", np->ndup.dupfd);
159			else
160				fprintf(fp, "-");
161		} else {
162			sharg(np->nfile.fname, fp);
163		}
164		first = 0;
165	}
166}
167
168
169
170static void
171sharg(union node *arg, FILE *fp)
172{
173	char *p;
174	struct nodelist *bqlist;
175	int subtype;
176
177	if (arg->type != NARG) {
178		printf("<node type %d>\n", arg->type);
179		fflush(stdout);
180		abort();
181	}
182	bqlist = arg->narg.backquote;
183	for (p = arg->narg.text ; *p ; p++) {
184		switch (*p) {
185		case CTLESC:
186			putc(*++p, fp);
187			break;
188		case CTLVAR:
189			putc('$', fp);
190			putc('{', fp);
191			subtype = *++p;
192			if (subtype == VSLENGTH)
193				putc('#', fp);
194
195			while (*p != '=')
196				putc(*p++, fp);
197
198			if (subtype & VSNUL)
199				putc(':', fp);
200
201			switch (subtype & VSTYPE) {
202			case VSNORMAL:
203				putc('}', fp);
204				break;
205			case VSMINUS:
206				putc('-', fp);
207				break;
208			case VSPLUS:
209				putc('+', fp);
210				break;
211			case VSQUESTION:
212				putc('?', fp);
213				break;
214			case VSASSIGN:
215				putc('=', fp);
216				break;
217			case VSTRIMLEFT:
218				putc('#', fp);
219				break;
220			case VSTRIMLEFTMAX:
221				putc('#', fp);
222				putc('#', fp);
223				break;
224			case VSTRIMRIGHT:
225				putc('%', fp);
226				break;
227			case VSTRIMRIGHTMAX:
228				putc('%', fp);
229				putc('%', fp);
230				break;
231			case VSLENGTH:
232				break;
233			default:
234				printf("<subtype %d>", subtype);
235			}
236			break;
237		case CTLENDVAR:
238		     putc('}', fp);
239		     break;
240		case CTLBACKQ:
241		case CTLBACKQ|CTLQUOTE:
242			putc('$', fp);
243			putc('(', fp);
244			shtree(bqlist->n, -1, NULL, fp);
245			putc(')', fp);
246			break;
247		default:
248			putc(*p, fp);
249			break;
250		}
251	}
252}
253
254
255static void
256indent(int amount, char *pfx, FILE *fp)
257{
258	int i;
259
260	for (i = 0 ; i < amount ; i++) {
261		if (pfx && i == amount - 1)
262			fputs(pfx, fp);
263		putc('\t', fp);
264	}
265}
266
267
268/*
269 * Debugging stuff.
270 */
271
272
273FILE *tracefile;
274
275#if DEBUG == 2
276int debug = 1;
277#else
278int debug = 0;
279#endif
280
281
282void
283trputc(int c)
284{
285	if (tracefile == NULL)
286		return;
287	putc(c, tracefile);
288	if (c == '\n')
289		fflush(tracefile);
290}
291
292
293void
294sh_trace(const char *fmt, ...)
295{
296	va_list va;
297	va_start(va, fmt);
298	if (tracefile != NULL) {
299		(void) vfprintf(tracefile, fmt, va);
300		if (strchr(fmt, '\n'))
301			(void) fflush(tracefile);
302	}
303	va_end(va);
304}
305
306
307void
308trputs(char *s)
309{
310	if (tracefile == NULL)
311		return;
312	fputs(s, tracefile);
313	if (strchr(s, '\n'))
314		fflush(tracefile);
315}
316
317
318static void
319trstring(char *s)
320{
321	char *p;
322	char c;
323
324	if (tracefile == NULL)
325		return;
326	putc('"', tracefile);
327	for (p = s ; *p ; p++) {
328		switch (*p) {
329		case '\n':  c = 'n';  goto backslash;
330		case '\t':  c = 't';  goto backslash;
331		case '\r':  c = 'r';  goto backslash;
332		case '"':  c = '"';  goto backslash;
333		case '\\':  c = '\\';  goto backslash;
334		case CTLESC:  c = 'e';  goto backslash;
335		case CTLVAR:  c = 'v';  goto backslash;
336		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
337		case CTLBACKQ:  c = 'q';  goto backslash;
338		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
339backslash:	  putc('\\', tracefile);
340			putc(c, tracefile);
341			break;
342		default:
343			if (*p >= ' ' && *p <= '~')
344				putc(*p, tracefile);
345			else {
346				putc('\\', tracefile);
347				putc(*p >> 6 & 03, tracefile);
348				putc(*p >> 3 & 07, tracefile);
349				putc(*p & 07, tracefile);
350			}
351			break;
352		}
353	}
354	putc('"', tracefile);
355}
356
357
358void
359trargs(char **ap)
360{
361	if (tracefile == NULL)
362		return;
363	while (*ap) {
364		trstring(*ap++);
365		if (*ap)
366			putc(' ', tracefile);
367		else
368			putc('\n', tracefile);
369	}
370	fflush(tracefile);
371}
372
373
374void
375opentrace(void)
376{
377	char s[100];
378	char *getenv();
379	int flags;
380
381	if (!debug)
382		return;
383#ifdef not_this_way
384	{
385		char *p;
386		if ((p = getenv("HOME")) == NULL) {
387			if (geteuid() == 0)
388				p = "/";
389			else
390				p = "/tmp";
391		}
392		scopy(p, s);
393		strcat(s, "/trace");
394	}
395#else
396	scopy("./trace", s);
397#endif /* not_this_way */
398	if ((tracefile = fopen(s, "a")) == NULL) {
399		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
400		return;
401	}
402	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
403		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
404	fputs("\nTracing started.\n", tracefile);
405	fflush(tracefile);
406}
407#endif /* DEBUG */
408