1 /* $NetBSD: show.c,v 1.33 2016/05/11 17:28:30 kre 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.33 2016/05/11 17:28:30 kre 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 #ifndef SMALL 56 #define DEFINE_NODENAMES 57 #include "nodenames.h" 58 #endif 59 60 61 FILE *tracefile; 62 63 #ifdef DEBUG 64 static int shtree(union node *, int, int, char *, FILE*); 65 static int shcmd(union node *, FILE *); 66 static int shsubsh(union node *, FILE *); 67 static int shredir(union node *, FILE *, int); 68 static int sharg(union node *, FILE *); 69 static int indent(int, char *, FILE *); 70 static void trstring(char *); 71 72 void 73 showtree(union node *n) 74 { 75 FILE *fp; 76 77 fp = tracefile ? tracefile : stdout; 78 79 trputs("showtree("); 80 if (n == NULL) 81 trputs("NULL"); 82 else if (n == NEOF) 83 trputs("NEOF"); 84 trputs(") called\n"); 85 if (n != NULL && n != NEOF) 86 shtree(n, 1, 1, NULL, fp); 87 } 88 89 90 static int 91 shtree(union node *n, int ind, int nl, char *pfx, FILE *fp) 92 { 93 struct nodelist *lp; 94 const char *s; 95 int len; 96 97 if (n == NULL) { 98 if (nl) 99 fputc('\n', fp); 100 return 0; 101 } 102 103 len = indent(ind, pfx, fp); 104 switch (n->type) { 105 case NSEMI: 106 s = "; "; 107 len += 2; 108 goto binop; 109 case NAND: 110 s = " && "; 111 len += 4; 112 goto binop; 113 case NOR: 114 s = " || "; 115 len += 4; 116 binop: 117 len += shtree(n->nbinary.ch1, 0, 0, NULL, fp); 118 fputs(s, fp); 119 if (len >= 60) { 120 putc('\n', fp); 121 len = indent(ind < 0 ? 2 : ind + 1, pfx, fp); 122 } 123 len += shtree(n->nbinary.ch2, 0, nl, NULL, fp); 124 break; 125 case NCMD: 126 len += shcmd(n, fp); 127 if (nl && len > 0) 128 len = 0, putc('\n', fp); 129 break; 130 case NPIPE: 131 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 132 len += shcmd(lp->n, fp); 133 if (lp->next) { 134 len += 3, fputs(" | ", fp); 135 if (len >= 60) { 136 fputc('\n', fp); 137 len = indent(ind < 0 ? 2 : ind + 1, 138 pfx, fp); 139 } 140 } 141 } 142 if (n->npipe.backgnd) 143 len += 2, fputs(" &", fp); 144 if (nl || len >= 60) 145 len = 0, fputc('\n', fp); 146 break; 147 case NSUBSHELL: 148 len += shsubsh(n, fp); 149 if (nl && len > 0) 150 len = 0, putc('\n', fp); 151 break; 152 default: 153 #ifdef NODETYPENAME 154 len += fprintf(fp, "<node type %d [%s]>", n->type, 155 NODETYPENAME(n->type)); 156 #else 157 len += fprintf(fp, "<node type %d>", n->type); 158 #endif 159 if (nl) 160 len = 0, putc('\n', fp); 161 break; 162 } 163 return len; 164 } 165 166 167 168 static int 169 shcmd(union node *cmd, FILE *fp) 170 { 171 union node *np; 172 int first; 173 const char *s; 174 int dftfd; 175 int len = 0; 176 177 first = 1; 178 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 179 if (! first) 180 len++, fputc(' ', fp); 181 len += sharg(np, fp); 182 first = 0; 183 } 184 return len + shredir(cmd, fp, first); 185 } 186 187 static int 188 shsubsh(union node *cmd, FILE *fp) 189 { 190 int len = 6; 191 192 fputs(" ( ", fp); 193 len += shtree(cmd->nredir.n, -1, 0, NULL, fp); 194 fputs(" ) ", fp); 195 len += shredir(cmd, fp, 1); 196 197 return len; 198 } 199 200 static int 201 shredir(union node *cmd, FILE *fp, int first) 202 { 203 union node *np; 204 const char *s; 205 int dftfd; 206 int len = 0; 207 char buf[106]; 208 209 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 210 if (! first) 211 len++, fputc(' ', fp); 212 switch (np->nfile.type) { 213 case NTO: s = ">"; dftfd = 1; len += 1; break; 214 case NCLOBBER: s = ">|"; dftfd = 1; len += 2; break; 215 case NAPPEND: s = ">>"; dftfd = 1; len += 2; break; 216 case NTOFD: s = ">&"; dftfd = 1; len += 2; break; 217 case NFROM: s = "<"; dftfd = 0; len += 1; break; 218 case NFROMFD: s = "<&"; dftfd = 0; len += 2; break; 219 case NFROMTO: s = "<>"; dftfd = 0; len += 2; break; 220 case NXHERE: /* FALLTHROUGH */ 221 case NHERE: s = "<<"; dftfd = 0; len += 2; break; 222 default: s = "*error*"; dftfd = 0; len += 7; break; 223 } 224 if (np->nfile.fd != dftfd) 225 len += fprintf(fp, "%d", np->nfile.fd); 226 fputs(s, fp); 227 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 228 len += fprintf(fp, "%d", np->ndup.dupfd); 229 } else 230 if (np->nfile.type == NHERE || np->nfile.type == NXHERE) { 231 if (np->nfile.type == NHERE) 232 fputc('\\', fp); 233 fputs("!!!\n", fp); 234 s = np->nhere.doc->narg.text; 235 if (strlen(s) > 100) { 236 memmove(buf, s, 100); 237 buf[100] = '\0'; 238 strcat(buf, " ..."); 239 s = buf; 240 } 241 fputs(s, fp); 242 fputs("!!!", fp); 243 len = 3; 244 } else { 245 len += sharg(np->nfile.fname, fp); 246 } 247 first = 0; 248 } 249 return len; 250 } 251 252 253 254 static int 255 sharg(union node *arg, FILE *fp) 256 { 257 char *p; 258 struct nodelist *bqlist; 259 int subtype; 260 int len = 0; 261 262 if (arg->type != NARG) { 263 fprintf(fp, "<node type %d>\n", arg->type); 264 abort(); 265 } 266 bqlist = arg->narg.backquote; 267 for (p = arg->narg.text ; *p ; p++) { 268 switch (*p) { 269 case CTLESC: 270 putc(*++p, fp); 271 len++; 272 break; 273 case CTLVAR: 274 putc('$', fp); 275 putc('{', fp); 276 len += 2; 277 subtype = *++p; 278 if (subtype == VSLENGTH) 279 len++, putc('#', fp); 280 281 while (*++p != '=') 282 len++, putc(*p, fp); 283 284 if (subtype & VSNUL) 285 len++, putc(':', fp); 286 287 switch (subtype & VSTYPE) { 288 case VSNORMAL: 289 putc('}', fp); 290 len++; 291 break; 292 case VSMINUS: 293 putc('-', fp); 294 len++; 295 break; 296 case VSPLUS: 297 putc('+', fp); 298 len++; 299 break; 300 case VSQUESTION: 301 putc('?', fp); 302 len++; 303 break; 304 case VSASSIGN: 305 putc('=', fp); 306 len++; 307 break; 308 case VSTRIMLEFT: 309 putc('#', fp); 310 len++; 311 break; 312 case VSTRIMLEFTMAX: 313 putc('#', fp); 314 putc('#', fp); 315 len += 2; 316 break; 317 case VSTRIMRIGHT: 318 putc('%', fp); 319 len++; 320 break; 321 case VSTRIMRIGHTMAX: 322 putc('%', fp); 323 putc('%', fp); 324 len += 2; 325 break; 326 case VSLENGTH: 327 break; 328 default: 329 len += fprintf(fp, "<subtype %d>", subtype); 330 } 331 break; 332 case CTLENDVAR: 333 putc('}', fp); 334 len++; 335 break; 336 case CTLBACKQ: 337 case CTLBACKQ|CTLQUOTE: 338 putc('$', fp); 339 putc('(', fp); 340 len += shtree(bqlist->n, -1, 0, NULL, fp) + 3; 341 putc(')', fp); 342 break; 343 default: 344 putc(*p, fp); 345 len++; 346 break; 347 } 348 } 349 return len; 350 } 351 352 353 static int 354 indent(int amount, char *pfx, FILE *fp) 355 { 356 int i; 357 int len = 0; 358 359 /* 360 * in practice, pfx is **always** NULL 361 * but here, we assume if it were not, at least strlen(pfx) < 8 362 * if that is invalid, output will look messy 363 */ 364 for (i = 0 ; i < amount ; i++) { 365 if (pfx && i == amount - 1) 366 fputs(pfx, fp); 367 putc('\t', fp); 368 len |= 7; 369 len++; 370 } 371 return len; 372 } 373 #endif 374 375 376 377 /* 378 * Debugging stuff. 379 */ 380 381 382 383 384 #ifdef DEBUG 385 void 386 trputc(int c) 387 { 388 if (debug != 1 || !tracefile) 389 return; 390 putc(c, tracefile); 391 } 392 #endif 393 394 void 395 trace(const char *fmt, ...) 396 { 397 #ifdef DEBUG 398 va_list va; 399 400 if (debug != 1 || !tracefile) 401 return; 402 va_start(va, fmt); 403 (void) vfprintf(tracefile, fmt, va); 404 va_end(va); 405 #endif 406 } 407 408 void 409 tracev(const char *fmt, va_list va) 410 { 411 #ifdef DEBUG 412 va_list ap; 413 if (debug != 1 || !tracefile) 414 return; 415 va_copy(ap, va); 416 (void) vfprintf(tracefile, fmt, ap); 417 va_end(ap); 418 #endif 419 } 420 421 422 #ifdef DEBUG 423 void 424 trputs(const char *s) 425 { 426 if (debug != 1 || !tracefile) 427 return; 428 fputs(s, tracefile); 429 } 430 431 432 static void 433 trstring(char *s) 434 { 435 char *p; 436 char c; 437 438 if (debug != 1 || !tracefile) 439 return; 440 putc('"', tracefile); 441 for (p = s ; *p ; p++) { 442 switch (*p) { 443 case '\n': c = 'n'; goto backslash; 444 case '\t': c = 't'; goto backslash; 445 case '\r': c = 'r'; goto backslash; 446 case '"': c = '"'; goto backslash; 447 case '\\': c = '\\'; goto backslash; 448 case CTLESC: c = 'e'; goto backslash; 449 case CTLVAR: c = 'v'; goto backslash; 450 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 451 case CTLBACKQ: c = 'q'; goto backslash; 452 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 453 backslash: putc('\\', tracefile); 454 putc(c, tracefile); 455 break; 456 default: 457 if (*p >= ' ' && *p <= '~') 458 putc(*p, tracefile); 459 else { 460 putc('\\', tracefile); 461 putc(*p >> 6 & 03, tracefile); 462 putc(*p >> 3 & 07, tracefile); 463 putc(*p & 07, tracefile); 464 } 465 break; 466 } 467 } 468 putc('"', tracefile); 469 } 470 #endif 471 472 473 void 474 trargs(char **ap) 475 { 476 #ifdef DEBUG 477 if (debug != 1 || !tracefile) 478 return; 479 while (*ap) { 480 trstring(*ap++); 481 if (*ap) 482 putc(' ', tracefile); 483 else 484 putc('\n', tracefile); 485 } 486 #endif 487 } 488 489 490 #ifdef DEBUG 491 void 492 opentrace(void) 493 { 494 char s[100]; 495 #ifdef O_APPEND 496 int flags; 497 #endif 498 499 if (debug != 1) { 500 if (tracefile) 501 fflush(tracefile); 502 /* leave open because libedit might be using it */ 503 return; 504 } 505 snprintf(s, sizeof(s), "./trace.%d", (int)getpid()); 506 if (tracefile) { 507 if (!freopen(s, "a", tracefile)) { 508 fprintf(stderr, "Can't re-open %s\n", s); 509 tracefile = NULL; 510 debug = 0; 511 return; 512 } 513 } else { 514 if ((tracefile = fopen(s, "a")) == NULL) { 515 fprintf(stderr, "Can't open %s\n", s); 516 debug = 0; 517 return; 518 } 519 } 520 #ifdef O_APPEND 521 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 522 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 523 #endif 524 setlinebuf(tracefile); 525 fputs("\nTracing started.\n", tracefile); 526 } 527 #endif /* DEBUG */ 528