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