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