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