show.c revision 1.29 1 /* $NetBSD: show.c,v 1.29 2016/02/27 18:34:12 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. 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 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: show.c,v 1.29 2016/02/27 18:34:12 christos Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <stdio.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48
49 #include "shell.h"
50 #include "parser.h"
51 #include "nodes.h"
52 #include "mystring.h"
53 #include "show.h"
54 #include "options.h"
55
56
57 FILE *tracefile;
58
59 #ifdef DEBUG
60 static int shtree(union node *, int, int, char *, FILE*);
61 static int shcmd(union node *, FILE *);
62 static int sharg(union node *, FILE *);
63 static int indent(int, char *, FILE *);
64 static void trstring(char *);
65
66 void
67 showtree(union node *n)
68 {
69 FILE *fp;
70
71 fp = tracefile ? tracefile : stdout;
72
73 trputs("showtree(");
74 if (n == NULL)
75 trputs("NULL");
76 else if (n == NEOF)
77 trputs("NEOF");
78 trputs(") called\n");
79 if (n != NULL && n != NEOF)
80 shtree(n, 1, 1, NULL, fp);
81 }
82
83
84 static int
85 shtree(union node *n, int ind, int nl, char *pfx, FILE *fp)
86 {
87 struct nodelist *lp;
88 const char *s;
89 int len;
90
91 if (n == NULL) {
92 if (nl)
93 fputc('\n', fp);
94 return 0;
95 }
96
97 len = indent(ind, pfx, fp);
98 switch (n->type) {
99 case NSEMI:
100 s = "; ";
101 len += 2;
102 goto binop;
103 case NAND:
104 s = " && ";
105 len += 4;
106 goto binop;
107 case NOR:
108 s = " || ";
109 len += 4;
110 binop:
111 len += shtree(n->nbinary.ch1, 0, 0, NULL, fp);
112 fputs(s, fp);
113 if (len >= 60) {
114 putc('\n', fp);
115 len = indent(ind < 0 ? 2 : ind + 1, pfx, fp);
116 }
117 len += shtree(n->nbinary.ch2, 0, nl, NULL, fp);
118 break;
119 case NCMD:
120 len += shcmd(n, fp);
121 if (nl)
122 len = 0, putc('\n', fp);
123 break;
124 case NPIPE:
125 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
126 len += shcmd(lp->n, fp);
127 if (lp->next) {
128 len += 3, fputs(" | ", fp);
129 if (len >= 60) {
130 fputc('\n', fp);
131 len = indent(ind < 0 ? 2 : ind + 1,
132 pfx, fp);
133 }
134 }
135 }
136 if (n->npipe.backgnd)
137 len += 2, fputs(" &", fp);
138 if (nl || len >= 60)
139 len = 0, fputc('\n', fp);
140 break;
141 default:
142 #ifdef NODETYPENAME
143 len += fprintf(fp, "<node type %d [%s]>", n->type,
144 NODETYPENAME(n->type));
145 #else
146 len += fprintf(fp, "<node type %d>", n->type);
147 #endif
148 if (nl)
149 len = 0, putc('\n', fp);
150 break;
151 }
152 return len;
153 }
154
155
156
157 static int
158 shcmd(union node *cmd, FILE *fp)
159 {
160 union node *np;
161 int first;
162 const char *s;
163 int dftfd;
164 int len = 0;
165
166 first = 1;
167 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
168 if (! first)
169 len++, fputc(' ', fp);
170 len += sharg(np, fp);
171 first = 0;
172 }
173 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
174 if (! first)
175 len++, fputc(' ', fp);
176 switch (np->nfile.type) {
177 case NTO: s = ">"; dftfd = 1; len += 1; break;
178 case NCLOBBER: s = ">|"; dftfd = 1; len += 2; break;
179 case NAPPEND: s = ">>"; dftfd = 1; len += 2; break;
180 case NTOFD: s = ">&"; dftfd = 1; len += 2; break;
181 case NFROM: s = "<"; dftfd = 0; len += 1; break;
182 case NFROMFD: s = "<&"; dftfd = 0; len += 2; break;
183 case NFROMTO: s = "<>"; dftfd = 0; len += 2; break;
184 default: s = "*error*"; dftfd = 0; len += 7; break;
185 }
186 if (np->nfile.fd != dftfd)
187 len += fprintf(fp, "%d", np->nfile.fd);
188 fputs(s, fp);
189 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
190 len += fprintf(fp, "%d", np->ndup.dupfd);
191 } else {
192 len += sharg(np->nfile.fname, fp);
193 }
194 first = 0;
195 }
196 return len;
197 }
198
199
200
201 static int
202 sharg(union node *arg, FILE *fp)
203 {
204 char *p;
205 struct nodelist *bqlist;
206 int subtype;
207 int len = 0;
208
209 if (arg->type != NARG) {
210 fprintf(fp, "<node type %d>\n", arg->type);
211 abort();
212 }
213 bqlist = arg->narg.backquote;
214 for (p = arg->narg.text ; *p ; p++) {
215 switch (*p) {
216 case CTLESC:
217 putc(*++p, fp);
218 len++;
219 break;
220 case CTLVAR:
221 putc('$', fp);
222 putc('{', fp);
223 len += 2;
224 subtype = *++p;
225 if (subtype == VSLENGTH)
226 len++, putc('#', fp);
227
228 while (*++p != '=')
229 len++, putc(*p, fp);
230
231 if (subtype & VSNUL)
232 len++, putc(':', fp);
233
234 switch (subtype & VSTYPE) {
235 case VSNORMAL:
236 putc('}', fp);
237 len++;
238 break;
239 case VSMINUS:
240 putc('-', fp);
241 len++;
242 break;
243 case VSPLUS:
244 putc('+', fp);
245 len++;
246 break;
247 case VSQUESTION:
248 putc('?', fp);
249 len++;
250 break;
251 case VSASSIGN:
252 putc('=', fp);
253 len++;
254 break;
255 case VSTRIMLEFT:
256 putc('#', fp);
257 len++;
258 break;
259 case VSTRIMLEFTMAX:
260 putc('#', fp);
261 putc('#', fp);
262 len += 2;
263 break;
264 case VSTRIMRIGHT:
265 putc('%', fp);
266 len++;
267 break;
268 case VSTRIMRIGHTMAX:
269 putc('%', fp);
270 putc('%', fp);
271 len += 2;
272 break;
273 case VSLENGTH:
274 break;
275 default:
276 len += fprintf(fp, "<subtype %d>", subtype);
277 }
278 break;
279 case CTLENDVAR:
280 putc('}', fp);
281 len++;
282 break;
283 case CTLBACKQ:
284 case CTLBACKQ|CTLQUOTE:
285 putc('$', fp);
286 putc('(', fp);
287 len += shtree(bqlist->n, -1, 0, NULL, fp) + 3;
288 putc(')', fp);
289 break;
290 default:
291 putc(*p, fp);
292 len++;
293 break;
294 }
295 }
296 return len;
297 }
298
299
300 static int
301 indent(int amount, char *pfx, FILE *fp)
302 {
303 int i;
304 int len = 0;
305
306 /*
307 * in practice, pfx is **always** NULL
308 * but here, we assume if it were not, at least strlen(pfx) < 8
309 * if that is invalid, output will look messy
310 */
311 for (i = 0 ; i < amount ; i++) {
312 if (pfx && i == amount - 1)
313 fputs(pfx, fp);
314 putc('\t', fp);
315 len |= 7;
316 len++;
317 }
318 return len;
319 }
320 #endif
321
322
323
324 /*
325 * Debugging stuff.
326 */
327
328
329
330
331 #ifdef DEBUG
332 void
333 trputc(int c)
334 {
335 if (debug != 1 || !tracefile)
336 return;
337 putc(c, tracefile);
338 }
339 #endif
340
341 void
342 trace(const char *fmt, ...)
343 {
344 #ifdef DEBUG
345 va_list va;
346
347 if (debug != 1 || !tracefile)
348 return;
349 va_start(va, fmt);
350 (void) vfprintf(tracefile, fmt, va);
351 va_end(va);
352 #endif
353 }
354
355 void
356 tracev(const char *fmt, va_list va)
357 {
358 #ifdef DEBUG
359 va_list ap;
360 if (debug != 1 || !tracefile)
361 return;
362 va_copy(ap, va);
363 (void) vfprintf(tracefile, fmt, ap);
364 va_end(ap);
365 #endif
366 }
367
368
369 #ifdef DEBUG
370 void
371 trputs(const char *s)
372 {
373 if (debug != 1 || !tracefile)
374 return;
375 fputs(s, tracefile);
376 }
377
378
379 static void
380 trstring(char *s)
381 {
382 char *p;
383 char c;
384
385 if (debug != 1 || !tracefile)
386 return;
387 putc('"', tracefile);
388 for (p = s ; *p ; p++) {
389 switch (*p) {
390 case '\n': c = 'n'; goto backslash;
391 case '\t': c = 't'; goto backslash;
392 case '\r': c = 'r'; goto backslash;
393 case '"': c = '"'; goto backslash;
394 case '\\': c = '\\'; goto backslash;
395 case CTLESC: c = 'e'; goto backslash;
396 case CTLVAR: c = 'v'; goto backslash;
397 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
398 case CTLBACKQ: c = 'q'; goto backslash;
399 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
400 backslash: putc('\\', tracefile);
401 putc(c, tracefile);
402 break;
403 default:
404 if (*p >= ' ' && *p <= '~')
405 putc(*p, tracefile);
406 else {
407 putc('\\', tracefile);
408 putc(*p >> 6 & 03, tracefile);
409 putc(*p >> 3 & 07, tracefile);
410 putc(*p & 07, tracefile);
411 }
412 break;
413 }
414 }
415 putc('"', tracefile);
416 }
417 #endif
418
419
420 void
421 trargs(char **ap)
422 {
423 #ifdef DEBUG
424 if (debug != 1 || !tracefile)
425 return;
426 while (*ap) {
427 trstring(*ap++);
428 if (*ap)
429 putc(' ', tracefile);
430 else
431 putc('\n', tracefile);
432 }
433 #endif
434 }
435
436
437 #ifdef DEBUG
438 void
439 opentrace(void)
440 {
441 char s[100];
442 #ifdef O_APPEND
443 int flags;
444 #endif
445
446 if (debug != 1) {
447 if (tracefile)
448 fflush(tracefile);
449 /* leave open because libedit might be using it */
450 return;
451 }
452 #ifdef not_this_way
453 {
454 char *p;
455 if ((p = getenv("HOME")) == NULL) {
456 if (geteuid() == 0)
457 p = "/";
458 else
459 p = "/tmp";
460 }
461 scopy(p, s);
462 strcat(s, "/trace");
463 }
464 #else
465 snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
466 #endif /* not_this_way */
467 if (tracefile) {
468 if (!freopen(s, "a", tracefile)) {
469 fprintf(stderr, "Can't re-open %s\n", s);
470 tracefile = NULL;
471 debug = 0;
472 return;
473 }
474 } else {
475 if ((tracefile = fopen(s, "a")) == NULL) {
476 fprintf(stderr, "Can't open %s\n", s);
477 debug = 0;
478 return;
479 }
480 }
481 #ifdef O_APPEND
482 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
483 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
484 #endif
485 setlinebuf(tracefile);
486 fputs("\nTracing started.\n", tracefile);
487 }
488 #endif /* DEBUG */
489