Merge from vendor branch LESS:
[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.23 2006/04/14 13:59:03 schweikh Exp $
38  * $DragonFly: src/bin/sh/show.c,v 1.4 2007/01/14 06:21:52 pavalos Exp $
39  */
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                 vfprintf(tracefile, fmt, va);
302                 if (strchr(fmt, '\n'))
303                         fflush(tracefile);
304         }
305         va_end(va);
306 }
307
308
309 void
310 trputs(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                 scopy(p, s);
394                 strcat(s, "/trace");
395         }
396 #else
397         scopy("./trace", s);
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 */