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