1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36#if 0
37static char sccsid[] = "@(#)show.c	8.3 (Berkeley) 5/4/95";
38#endif
39#endif /* not lint */
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD$");
42
43#include <fcntl.h>
44#include <stdio.h>
45#include <stdlib.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	const 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	const 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			case NHERE:	s = "<<"; dftfd = 0; break;
150			case NXHERE:	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 if (np->nfile.type == NHERE) {
162				fprintf(fp, "HERE");
163		} else if (np->nfile.type == NXHERE) {
164				fprintf(fp, "XHERE");
165		} else {
166			sharg(np->nfile.fname, fp);
167		}
168		first = 0;
169	}
170}
171
172
173
174static void
175sharg(union node *arg, FILE *fp)
176{
177	char *p;
178	struct nodelist *bqlist;
179	int subtype;
180
181	if (arg->type != NARG) {
182		printf("<node type %d>\n", arg->type);
183		fflush(stdout);
184		abort();
185	}
186	bqlist = arg->narg.backquote;
187	for (p = arg->narg.text ; *p ; p++) {
188		switch (*p) {
189		case CTLESC:
190			putc(*++p, fp);
191			break;
192		case CTLVAR:
193			putc('$', fp);
194			putc('{', fp);
195			subtype = *++p;
196			if (subtype == VSLENGTH)
197				putc('#', fp);
198
199			while (*p != '=')
200				putc(*p++, fp);
201
202			if (subtype & VSNUL)
203				putc(':', fp);
204
205			switch (subtype & VSTYPE) {
206			case VSNORMAL:
207				putc('}', fp);
208				break;
209			case VSMINUS:
210				putc('-', fp);
211				break;
212			case VSPLUS:
213				putc('+', fp);
214				break;
215			case VSQUESTION:
216				putc('?', fp);
217				break;
218			case VSASSIGN:
219				putc('=', fp);
220				break;
221			case VSTRIMLEFT:
222				putc('#', fp);
223				break;
224			case VSTRIMLEFTMAX:
225				putc('#', fp);
226				putc('#', fp);
227				break;
228			case VSTRIMRIGHT:
229				putc('%', fp);
230				break;
231			case VSTRIMRIGHTMAX:
232				putc('%', fp);
233				putc('%', fp);
234				break;
235			case VSLENGTH:
236				break;
237			default:
238				printf("<subtype %d>", subtype);
239			}
240			break;
241		case CTLENDVAR:
242		     putc('}', fp);
243		     break;
244		case CTLBACKQ:
245		case CTLBACKQ|CTLQUOTE:
246			putc('$', fp);
247			putc('(', fp);
248			shtree(bqlist->n, -1, NULL, fp);
249			putc(')', fp);
250			break;
251		default:
252			putc(*p, fp);
253			break;
254		}
255	}
256}
257
258
259static void
260indent(int amount, char *pfx, FILE *fp)
261{
262	int i;
263
264	for (i = 0 ; i < amount ; i++) {
265		if (pfx && i == amount - 1)
266			fputs(pfx, fp);
267		putc('\t', fp);
268	}
269}
270
271
272/*
273 * Debugging stuff.
274 */
275
276
277static FILE *tracefile;
278#if DEBUG >= 2
279int debug = 1;
280#else
281int debug = 0;
282#endif
283
284
285void
286trputc(int c)
287{
288	if (tracefile == NULL)
289		return;
290	putc(c, tracefile);
291	if (c == '\n')
292		fflush(tracefile);
293}
294
295
296void
297sh_trace(const char *fmt, ...)
298{
299	va_list va;
300	va_start(va, fmt);
301	if (tracefile != NULL) {
302		(void) vfprintf(tracefile, fmt, va);
303		if (strchr(fmt, '\n'))
304			(void) fflush(tracefile);
305	}
306	va_end(va);
307}
308
309
310void
311trputs(const char *s)
312{
313	if (tracefile == NULL)
314		return;
315	fputs(s, tracefile);
316	if (strchr(s, '\n'))
317		fflush(tracefile);
318}
319
320
321static void
322trstring(char *s)
323{
324	char *p;
325	char c;
326
327	if (tracefile == NULL)
328		return;
329	putc('"', tracefile);
330	for (p = s ; *p ; p++) {
331		switch (*p) {
332		case '\n':  c = 'n';  goto backslash;
333		case '\t':  c = 't';  goto backslash;
334		case '\r':  c = 'r';  goto backslash;
335		case '"':  c = '"';  goto backslash;
336		case '\\':  c = '\\';  goto backslash;
337		case CTLESC:  c = 'e';  goto backslash;
338		case CTLVAR:  c = 'v';  goto backslash;
339		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
340		case CTLBACKQ:  c = 'q';  goto backslash;
341		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
342backslash:	  putc('\\', tracefile);
343			putc(c, tracefile);
344			break;
345		default:
346			if (*p >= ' ' && *p <= '~')
347				putc(*p, tracefile);
348			else {
349				putc('\\', tracefile);
350				putc(*p >> 6 & 03, tracefile);
351				putc(*p >> 3 & 07, tracefile);
352				putc(*p & 07, tracefile);
353			}
354			break;
355		}
356	}
357	putc('"', tracefile);
358}
359
360
361void
362trargs(char **ap)
363{
364	if (tracefile == NULL)
365		return;
366	while (*ap) {
367		trstring(*ap++);
368		if (*ap)
369			putc(' ', tracefile);
370		else
371			putc('\n', tracefile);
372	}
373	fflush(tracefile);
374}
375
376
377void
378opentrace(void)
379{
380	char s[100];
381	int flags;
382
383	if (!debug)
384		return;
385#ifdef not_this_way
386	{
387		char *p;
388		if ((p = getenv("HOME")) == NULL) {
389			if (geteuid() == 0)
390				p = "/";
391			else
392				p = "/tmp";
393		}
394		strcpy(s, p);
395		strcat(s, "/trace");
396	}
397#else
398	strcpy(s, "./trace");
399#endif /* not_this_way */
400	if ((tracefile = fopen(s, "a")) == NULL) {
401		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
402		return;
403	}
404	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
405		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
406	fputs("\nTracing started.\n", tracefile);
407	fflush(tracefile);
408}
409#endif /* DEBUG */
410