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