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