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