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