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