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