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