Home | History | Annotate | Line # | Download | only in sh
show.c revision 1.33.2.2
      1 /*	$NetBSD: show.c,v 1.33.2.2 2017/03/20 06:51:32 pgoyette 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.2.2 2017/03/20 06:51:32 pgoyette 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 	int len = 0;
    174 
    175 	first = 1;
    176 	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
    177 		if (! first)
    178 			len++, fputc(' ', fp);
    179 		len += sharg(np, fp);
    180 		first = 0;
    181 	}
    182 	return len + shredir(cmd, fp, first);
    183 }
    184 
    185 static int
    186 shsubsh(union node *cmd, FILE *fp)
    187 {
    188 	int len = 6;
    189 
    190 	fputs(" ( ", fp);
    191 	len += shtree(cmd->nredir.n, -1, 0, NULL, fp);
    192 	fputs(" ) ", fp);
    193 	len += shredir(cmd, fp, 1);
    194 
    195 	return len;
    196 }
    197 
    198 static int
    199 shredir(union node *cmd, FILE *fp, int first)
    200 {
    201 	union node *np;
    202 	const char *s;
    203 	int dftfd;
    204 	int len = 0;
    205 	char buf[106];
    206 
    207 	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
    208 		if (! first)
    209 			len++, fputc(' ', fp);
    210 		switch (np->nfile.type) {
    211 			case NTO:	s = ">";  dftfd = 1; len += 1; break;
    212 			case NCLOBBER:	s = ">|"; dftfd = 1; len += 2; break;
    213 			case NAPPEND:	s = ">>"; dftfd = 1; len += 2; break;
    214 			case NTOFD:	s = ">&"; dftfd = 1; len += 2; break;
    215 			case NFROM:	s = "<";  dftfd = 0; len += 1; break;
    216 			case NFROMFD:	s = "<&"; dftfd = 0; len += 2; break;
    217 			case NFROMTO:	s = "<>"; dftfd = 0; len += 2; break;
    218 			case NXHERE:	/* FALLTHROUGH */
    219 			case NHERE:	s = "<<"; dftfd = 0; len += 2; break;
    220 			default:   s = "*error*"; dftfd = 0; len += 7; break;
    221 		}
    222 		if (np->nfile.fd != dftfd)
    223 			len += fprintf(fp, "%d", np->nfile.fd);
    224 		fputs(s, fp);
    225 		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
    226 			len += fprintf(fp, "%d", np->ndup.dupfd);
    227 		} else
    228 		    if (np->nfile.type == NHERE || np->nfile.type == NXHERE) {
    229 			if (np->nfile.type == NHERE)
    230 				fputc('\\', fp);
    231 			fputs("!!!\n", fp);
    232 			s = np->nhere.doc->narg.text;
    233 			if (strlen(s) > 100) {
    234 				memmove(buf, s, 100);
    235 				buf[100] = '\0';
    236 				strcat(buf, " ...");
    237 				s = buf;
    238 			}
    239 			fputs(s, fp);
    240 			fputs("!!!", fp);
    241 			len = 3;
    242 		} else {
    243 			len += sharg(np->nfile.fname, fp);
    244 		}
    245 		first = 0;
    246 	}
    247 	return len;
    248 }
    249 
    250 
    251 
    252 static int
    253 sharg(union node *arg, FILE *fp)
    254 {
    255 	char *p;
    256 	struct nodelist *bqlist;
    257 	int subtype;
    258 	int len = 0;
    259 
    260 	if (arg->type != NARG) {
    261 		fprintf(fp, "<node type %d>\n", arg->type);
    262 		abort();
    263 	}
    264 	bqlist = arg->narg.backquote;
    265 	for (p = arg->narg.text ; *p ; p++) {
    266 		switch (*p) {
    267 		case CTLESC:
    268 			putc(*++p, fp);
    269 			len++;
    270 			break;
    271 		case CTLVAR:
    272 			putc('$', fp);
    273 			putc('{', fp);
    274 			len += 2;
    275 			subtype = *++p;
    276 			if (subtype == VSLENGTH)
    277 				len++, putc('#', fp);
    278 
    279 			while (*++p != '=')
    280 				len++, putc(*p, fp);
    281 
    282 			if (subtype & VSNUL)
    283 				len++, putc(':', fp);
    284 
    285 			switch (subtype & VSTYPE) {
    286 			case VSNORMAL:
    287 				putc('}', fp);
    288 				len++;
    289 				break;
    290 			case VSMINUS:
    291 				putc('-', fp);
    292 				len++;
    293 				break;
    294 			case VSPLUS:
    295 				putc('+', fp);
    296 				len++;
    297 				break;
    298 			case VSQUESTION:
    299 				putc('?', fp);
    300 				len++;
    301 				break;
    302 			case VSASSIGN:
    303 				putc('=', fp);
    304 				len++;
    305 				break;
    306 			case VSTRIMLEFT:
    307 				putc('#', fp);
    308 				len++;
    309 				break;
    310 			case VSTRIMLEFTMAX:
    311 				putc('#', fp);
    312 				putc('#', fp);
    313 				len += 2;
    314 				break;
    315 			case VSTRIMRIGHT:
    316 				putc('%', fp);
    317 				len++;
    318 				break;
    319 			case VSTRIMRIGHTMAX:
    320 				putc('%', fp);
    321 				putc('%', fp);
    322 				len += 2;
    323 				break;
    324 			case VSLENGTH:
    325 				break;
    326 			default:
    327 				len += fprintf(fp, "<subtype %d>", subtype);
    328 			}
    329 			break;
    330 		case CTLENDVAR:
    331 		     putc('}', fp);
    332 		     len++;
    333 		     break;
    334 		case CTLBACKQ:
    335 		case CTLBACKQ|CTLQUOTE:
    336 			putc('$', fp);
    337 			putc('(', fp);
    338 			len += shtree(bqlist->n, -1, 0, NULL, fp) + 3;
    339 			putc(')', fp);
    340 			break;
    341 		default:
    342 			putc(*p, fp);
    343 			len++;
    344 			break;
    345 		}
    346 	}
    347 	return len;
    348 }
    349 
    350 
    351 static int
    352 indent(int amount, char *pfx, FILE *fp)
    353 {
    354 	int i;
    355 	int len = 0;
    356 
    357 	/*
    358 	 * in practice, pfx is **always** NULL
    359 	 * but here, we assume if it were not, at least strlen(pfx) < 8
    360 	 * if that is invalid, output will look messy
    361 	 */
    362 	for (i = 0 ; i < amount ; i++) {
    363 		if (pfx && i == amount - 1)
    364 			fputs(pfx, fp);
    365 		putc('\t', fp);
    366 		len |= 7;
    367 		len++;
    368 	}
    369 	return len;
    370 }
    371 #endif
    372 
    373 
    374 
    375 /*
    376  * Debugging stuff.
    377  */
    378 
    379 
    380 
    381 
    382 #ifdef DEBUG
    383 void
    384 trputc(int c)
    385 {
    386 	if (debug != 1 || !tracefile)
    387 		return;
    388 	putc(c, tracefile);
    389 }
    390 #endif
    391 
    392 void
    393 trace(const char *fmt, ...)
    394 {
    395 #ifdef DEBUG
    396 	va_list va;
    397 
    398 	if (debug != 1 || !tracefile)
    399 		return;
    400 	va_start(va, fmt);
    401 	(void) vfprintf(tracefile, fmt, va);
    402 	va_end(va);
    403 #endif
    404 }
    405 
    406 void
    407 tracev(const char *fmt, va_list va)
    408 {
    409 #ifdef DEBUG
    410 	va_list ap;
    411 	if (debug != 1 || !tracefile)
    412 		return;
    413 	va_copy(ap, va);
    414 	(void) vfprintf(tracefile, fmt, ap);
    415 	va_end(ap);
    416 #endif
    417 }
    418 
    419 
    420 #ifdef DEBUG
    421 void
    422 trputs(const char *s)
    423 {
    424 	if (debug != 1 || !tracefile)
    425 		return;
    426 	fputs(s, tracefile);
    427 }
    428 
    429 
    430 static void
    431 trstring(char *s)
    432 {
    433 	char *p;
    434 	char c;
    435 
    436 	if (debug != 1 || !tracefile)
    437 		return;
    438 	putc('"', tracefile);
    439 	for (p = s ; *p ; p++) {
    440 		switch (*p) {
    441 		case '\n':  c = 'n';  goto backslash;
    442 		case '\t':  c = 't';  goto backslash;
    443 		case '\r':  c = 'r';  goto backslash;
    444 		case '"':  c = '"';  goto backslash;
    445 		case '\\':  c = '\\';  goto backslash;
    446 		case CTLESC:  c = 'e';  goto backslash;
    447 		case CTLVAR:  c = 'v';  goto backslash;
    448 		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
    449 		case CTLBACKQ:  c = 'q';  goto backslash;
    450 		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
    451 backslash:	  putc('\\', tracefile);
    452 			putc(c, tracefile);
    453 			break;
    454 		default:
    455 			if (*p >= ' ' && *p <= '~')
    456 				putc(*p, tracefile);
    457 			else {
    458 				putc('\\', tracefile);
    459 				putc(*p >> 6 & 03, tracefile);
    460 				putc(*p >> 3 & 07, tracefile);
    461 				putc(*p & 07, tracefile);
    462 			}
    463 			break;
    464 		}
    465 	}
    466 	putc('"', tracefile);
    467 }
    468 #endif
    469 
    470 
    471 void
    472 trargs(char **ap)
    473 {
    474 #ifdef DEBUG
    475 	if (debug != 1 || !tracefile)
    476 		return;
    477 	while (*ap) {
    478 		trstring(*ap++);
    479 		if (*ap)
    480 			putc(' ', tracefile);
    481 		else
    482 			putc('\n', tracefile);
    483 	}
    484 #endif
    485 }
    486 
    487 
    488 #ifdef DEBUG
    489 void
    490 opentrace(void)
    491 {
    492 	char s[100];
    493 #ifdef O_APPEND
    494 	int flags;
    495 #endif
    496 
    497 	if (debug != 1) {
    498 		if (tracefile)
    499 			fflush(tracefile);
    500 		/* leave open because libedit might be using it */
    501 		return;
    502 	}
    503 	snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
    504 	if (tracefile) {
    505 		if (!freopen(s, "a", tracefile)) {
    506 			fprintf(stderr, "Can't re-open %s\n", s);
    507 			tracefile = NULL;
    508 			debug = 0;
    509 			return;
    510 		}
    511 	} else {
    512 		if ((tracefile = fopen(s, "a")) == NULL) {
    513 			fprintf(stderr, "Can't open %s\n", s);
    514 			debug = 0;
    515 			return;
    516 		}
    517 	}
    518 #ifdef O_APPEND
    519 	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
    520 		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
    521 #endif
    522 	setlinebuf(tracefile);
    523 	fputs("\nTracing started.\n", tracefile);
    524 }
    525 #endif /* DEBUG */
    526