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