Correct BSD License clause numbering from 1-2-4 to 1-2-3.
[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. 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  * @(#)show.c   8.3 (Berkeley) 5/4/95
33  * $FreeBSD: head/bin/sh/show.c 213811 2010-10-13 22:18:03Z obrien $
34  */
35
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <errno.h>
41
42 #include "shell.h"
43 #include "parser.h"
44 #include "nodes.h"
45 #include "mystring.h"
46 #include "show.h"
47
48
49 #ifdef DEBUG
50 static void shtree(union node *, int, char *, FILE*);
51 static void shcmd(union node *, FILE *);
52 static void sharg(union node *, FILE *);
53 static void indent(int, char *, FILE *);
54 static void trstring(char *);
55
56
57 void
58 showtree(union node *n)
59 {
60         trputs("showtree called\n");
61         shtree(n, 1, NULL, stdout);
62 }
63
64
65 static void
66 shtree(union node *n, int ind, char *pfx, FILE *fp)
67 {
68         struct nodelist *lp;
69         char *s;
70
71         if (n == NULL)
72                 return;
73
74         indent(ind, pfx, fp);
75         switch(n->type) {
76         case NSEMI:
77                 s = "; ";
78                 goto binop;
79         case NAND:
80                 s = " && ";
81                 goto binop;
82         case NOR:
83                 s = " || ";
84 binop:
85                 shtree(n->nbinary.ch1, ind, NULL, fp);
86            /*    if (ind < 0) */
87                         fputs(s, fp);
88                 shtree(n->nbinary.ch2, ind, NULL, fp);
89                 break;
90         case NCMD:
91                 shcmd(n, fp);
92                 if (ind >= 0)
93                         putc('\n', fp);
94                 break;
95         case NPIPE:
96                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
97                         shcmd(lp->n, fp);
98                         if (lp->next)
99                                 fputs(" | ", fp);
100                 }
101                 if (n->npipe.backgnd)
102                         fputs(" &", fp);
103                 if (ind >= 0)
104                         putc('\n', fp);
105                 break;
106         default:
107                 fprintf(fp, "<node type %d>", n->type);
108                 if (ind >= 0)
109                         putc('\n', fp);
110                 break;
111         }
112 }
113
114
115
116 static void
117 shcmd(union node *cmd, FILE *fp)
118 {
119         union node *np;
120         int first;
121         char *s;
122         int dftfd;
123
124         first = 1;
125         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
126                 if (! first)
127                         putchar(' ');
128                 sharg(np, fp);
129                 first = 0;
130         }
131         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
132                 if (! first)
133                         putchar(' ');
134                 switch (np->nfile.type) {
135                         case NTO:       s = ">";  dftfd = 1; break;
136                         case NAPPEND:   s = ">>"; dftfd = 1; break;
137                         case NTOFD:     s = ">&"; dftfd = 1; break;
138                         case NCLOBBER:  s = ">|"; dftfd = 1; break;
139                         case NFROM:     s = "<";  dftfd = 0; break;
140                         case NFROMTO:   s = "<>"; dftfd = 0; break;
141                         case NFROMFD:   s = "<&"; dftfd = 0; break;
142                         case NHERE:     s = "<<"; dftfd = 0; break;
143                         case NXHERE:    s = "<<"; dftfd = 0; break;
144                         default:        s = "*error*"; dftfd = 0; break;
145                 }
146                 if (np->nfile.fd != dftfd)
147                         fprintf(fp, "%d", np->nfile.fd);
148                 fputs(s, fp);
149                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
150                         if (np->ndup.dupfd >= 0)
151                                 fprintf(fp, "%d", np->ndup.dupfd);
152                         else
153                                 fprintf(fp, "-");
154                 } else if (np->nfile.type == NHERE) {
155                                 fprintf(fp, "HERE");
156                 } else if (np->nfile.type == NXHERE) {
157                                 fprintf(fp, "XHERE");
158                 } else {
159                         sharg(np->nfile.fname, fp);
160                 }
161                 first = 0;
162         }
163 }
164
165
166
167 static void
168 sharg(union node *arg, FILE *fp)
169 {
170         char *p;
171         struct nodelist *bqlist;
172         int subtype;
173
174         if (arg->type != NARG) {
175                 printf("<node type %d>\n", arg->type);
176                 fflush(stdout);
177                 abort();
178         }
179         bqlist = arg->narg.backquote;
180         for (p = arg->narg.text ; *p ; p++) {
181                 switch (*p) {
182                 case CTLESC:
183                         putc(*++p, fp);
184                         break;
185                 case CTLVAR:
186                         putc('$', fp);
187                         putc('{', fp);
188                         subtype = *++p;
189                         if (subtype == VSLENGTH)
190                                 putc('#', fp);
191
192                         while (*p != '=')
193                                 putc(*p++, fp);
194
195                         if (subtype & VSNUL)
196                                 putc(':', fp);
197
198                         switch (subtype & VSTYPE) {
199                         case VSNORMAL:
200                                 putc('}', fp);
201                                 break;
202                         case VSMINUS:
203                                 putc('-', fp);
204                                 break;
205                         case VSPLUS:
206                                 putc('+', fp);
207                                 break;
208                         case VSQUESTION:
209                                 putc('?', fp);
210                                 break;
211                         case VSASSIGN:
212                                 putc('=', fp);
213                                 break;
214                         case VSTRIMLEFT:
215                                 putc('#', fp);
216                                 break;
217                         case VSTRIMLEFTMAX:
218                                 putc('#', fp);
219                                 putc('#', fp);
220                                 break;
221                         case VSTRIMRIGHT:
222                                 putc('%', fp);
223                                 break;
224                         case VSTRIMRIGHTMAX:
225                                 putc('%', fp);
226                                 putc('%', fp);
227                                 break;
228                         case VSLENGTH:
229                                 break;
230                         default:
231                                 printf("<subtype %d>", subtype);
232                         }
233                         break;
234                 case CTLENDVAR:
235                      putc('}', fp);
236                      break;
237                 case CTLBACKQ:
238                 case CTLBACKQ|CTLQUOTE:
239                         putc('$', fp);
240                         putc('(', fp);
241                         shtree(bqlist->n, -1, NULL, fp);
242                         putc(')', fp);
243                         break;
244                 default:
245                         putc(*p, fp);
246                         break;
247                 }
248         }
249 }
250
251
252 static void
253 indent(int amount, char *pfx, FILE *fp)
254 {
255         int i;
256
257         for (i = 0 ; i < amount ; i++) {
258                 if (pfx && i == amount - 1)
259                         fputs(pfx, fp);
260                 putc('\t', fp);
261         }
262 }
263
264
265 /*
266  * Debugging stuff.
267  */
268
269
270 FILE *tracefile;
271
272 #if DEBUG >= 2
273 int debug = 1;
274 #else
275 int debug = 0;
276 #endif
277
278
279 void
280 trputc(int c)
281 {
282         if (tracefile == NULL)
283                 return;
284         putc(c, tracefile);
285         if (c == '\n')
286                 fflush(tracefile);
287 }
288
289
290 void
291 sh_trace(const char *fmt, ...)
292 {
293         va_list va;
294         va_start(va, fmt);
295         if (tracefile != NULL) {
296                 vfprintf(tracefile, fmt, va);
297                 if (strchr(fmt, '\n'))
298                         fflush(tracefile);
299         }
300         va_end(va);
301 }
302
303
304 void
305 trputs(const char *s)
306 {
307         if (tracefile == NULL)
308                 return;
309         fputs(s, tracefile);
310         if (strchr(s, '\n'))
311                 fflush(tracefile);
312 }
313
314
315 static void
316 trstring(char *s)
317 {
318         char *p;
319         char c;
320
321         if (tracefile == NULL)
322                 return;
323         putc('"', tracefile);
324         for (p = s ; *p ; p++) {
325                 switch (*p) {
326                 case '\n':  c = 'n';  goto backslash;
327                 case '\t':  c = 't';  goto backslash;
328                 case '\r':  c = 'r';  goto backslash;
329                 case '"':  c = '"';  goto backslash;
330                 case '\\':  c = '\\';  goto backslash;
331                 case CTLESC:  c = 'e';  goto backslash;
332                 case CTLVAR:  c = 'v';  goto backslash;
333                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
334                 case CTLBACKQ:  c = 'q';  goto backslash;
335                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
336 backslash:        putc('\\', tracefile);
337                         putc(c, tracefile);
338                         break;
339                 default:
340                         if (*p >= ' ' && *p <= '~')
341                                 putc(*p, tracefile);
342                         else {
343                                 putc('\\', tracefile);
344                                 putc(*p >> 6 & 03, tracefile);
345                                 putc(*p >> 3 & 07, tracefile);
346                                 putc(*p & 07, tracefile);
347                         }
348                         break;
349                 }
350         }
351         putc('"', tracefile);
352 }
353
354
355 void
356 trargs(char **ap)
357 {
358         if (tracefile == NULL)
359                 return;
360         while (*ap) {
361                 trstring(*ap++);
362                 if (*ap)
363                         putc(' ', tracefile);
364                 else
365                         putc('\n', tracefile);
366         }
367         fflush(tracefile);
368 }
369
370
371 void
372 opentrace(void)
373 {
374         char s[100];
375         int flags;
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         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
399                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
400         fputs("\nTracing started.\n", tracefile);
401         fflush(tracefile);
402 }
403 #endif /* DEBUG */