1 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl 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.24 2003/01/22 20:36:04 dsl 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 #include "options.h" 57 58 59 #ifdef DEBUG 60 static void shtree(union node *, int, char *, FILE*); 61 static void shcmd(union node *, FILE *); 62 static void sharg(union node *, FILE *); 63 static void indent(int, char *, FILE *); 64 static void trstring(char *); 65 66 67 void 68 showtree(union node *n) 69 { 70 trputs("showtree called\n"); 71 shtree(n, 1, NULL, stdout); 72 } 73 74 75 static void 76 shtree(union node *n, int ind, char *pfx, FILE *fp) 77 { 78 struct nodelist *lp; 79 const char *s; 80 81 if (n == NULL) 82 return; 83 84 indent(ind, pfx, fp); 85 switch(n->type) { 86 case NSEMI: 87 s = "; "; 88 goto binop; 89 case NAND: 90 s = " && "; 91 goto binop; 92 case NOR: 93 s = " || "; 94 binop: 95 shtree(n->nbinary.ch1, ind, NULL, fp); 96 /* if (ind < 0) */ 97 fputs(s, fp); 98 shtree(n->nbinary.ch2, ind, NULL, fp); 99 break; 100 case NCMD: 101 shcmd(n, fp); 102 if (ind >= 0) 103 putc('\n', fp); 104 break; 105 case NPIPE: 106 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 107 shcmd(lp->n, fp); 108 if (lp->next) 109 fputs(" | ", fp); 110 } 111 if (n->npipe.backgnd) 112 fputs(" &", fp); 113 if (ind >= 0) 114 putc('\n', fp); 115 break; 116 default: 117 fprintf(fp, "<node type %d>", n->type); 118 if (ind >= 0) 119 putc('\n', fp); 120 break; 121 } 122 } 123 124 125 126 static void 127 shcmd(union node *cmd, FILE *fp) 128 { 129 union node *np; 130 int first; 131 const char *s; 132 int dftfd; 133 134 first = 1; 135 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 136 if (! first) 137 putchar(' '); 138 sharg(np, fp); 139 first = 0; 140 } 141 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 142 if (! first) 143 putchar(' '); 144 switch (np->nfile.type) { 145 case NTO: s = ">"; dftfd = 1; break; 146 case NCLOBBER: s = ">|"; dftfd = 1; break; 147 case NAPPEND: s = ">>"; dftfd = 1; break; 148 case NTOFD: s = ">&"; dftfd = 1; break; 149 case NFROM: s = "<"; dftfd = 0; break; 150 case NFROMFD: s = "<&"; dftfd = 0; break; 151 case NFROMTO: s = "<>"; dftfd = 0; break; 152 default: s = "*error*"; dftfd = 0; break; 153 } 154 if (np->nfile.fd != dftfd) 155 fprintf(fp, "%d", np->nfile.fd); 156 fputs(s, fp); 157 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 158 fprintf(fp, "%d", np->ndup.dupfd); 159 } else { 160 sharg(np->nfile.fname, fp); 161 } 162 first = 0; 163 } 164 } 165 166 167 168 static void 169 sharg(union node *arg, FILE *fp) 170 { 171 char *p; 172 struct nodelist *bqlist; 173 int subtype; 174 175 if (arg->type != NARG) { 176 printf("<node type %d>\n", arg->type); 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 #endif 264 265 266 267 /* 268 * Debugging stuff. 269 */ 270 271 272 FILE *tracefile; 273 274 275 #ifdef DEBUG 276 void 277 trputc(int c) 278 { 279 if (debug != 1) 280 return; 281 putc(c, tracefile); 282 } 283 #endif 284 285 void 286 trace(const char *fmt, ...) 287 { 288 #ifdef DEBUG 289 va_list va; 290 291 if (debug != 1) 292 return; 293 va_start(va, fmt); 294 (void) vfprintf(tracefile, fmt, va); 295 va_end(va); 296 #endif 297 } 298 299 void 300 tracev(const char *fmt, va_list va) 301 { 302 #ifdef DEBUG 303 if (debug != 1) 304 return; 305 (void) vfprintf(tracefile, fmt, va); 306 #endif 307 } 308 309 310 #ifdef DEBUG 311 void 312 trputs(const char *s) 313 { 314 if (debug != 1) 315 return; 316 fputs(s, tracefile); 317 } 318 319 320 static void 321 trstring(char *s) 322 { 323 char *p; 324 char c; 325 326 if (debug != 1) 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 #endif 359 360 361 void 362 trargs(char **ap) 363 { 364 #ifdef DEBUG 365 if (debug != 1) 366 return; 367 while (*ap) { 368 trstring(*ap++); 369 if (*ap) 370 putc(' ', tracefile); 371 else 372 putc('\n', tracefile); 373 } 374 #endif 375 } 376 377 378 #ifdef DEBUG 379 void 380 opentrace(void) 381 { 382 char s[100]; 383 #ifdef O_APPEND 384 int flags; 385 #endif 386 387 if (debug != 1) { 388 if (tracefile) 389 fflush(tracefile); 390 /* leave open because libedit might be using it */ 391 return; 392 } 393 #ifdef not_this_way 394 { 395 char *p; 396 if ((p = getenv("HOME")) == NULL) { 397 if (geteuid() == 0) 398 p = "/"; 399 else 400 p = "/tmp"; 401 } 402 scopy(p, s); 403 strcat(s, "/trace"); 404 } 405 #else 406 scopy("./trace", s); 407 #endif /* not_this_way */ 408 if (tracefile) { 409 if (!freopen(s, "a", tracefile)) { 410 fprintf(stderr, "Can't re-open %s\n", s); 411 debug = 0; 412 return; 413 } 414 } else { 415 if ((tracefile = fopen(s, "a")) == NULL) { 416 fprintf(stderr, "Can't open %s\n", s); 417 debug = 0; 418 return; 419 } 420 } 421 #ifdef O_APPEND 422 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 423 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 424 #endif 425 setlinebuf(tracefile); 426 fputs("\nTracing started.\n", tracefile); 427 } 428 #endif /* DEBUG */ 429