Home | History | Annotate | Line # | Download | only in sh
show.c revision 1.32
      1 /*	$NetBSD: show.c,v 1.32 2016/02/29 23:52:04 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.32 2016/02/29 23:52:04 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 #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 #ifdef not_this_way
    506 	{
    507 		char *p;
    508 		if ((p = getenv("HOME")) == NULL) {
    509 			if (geteuid() == 0)
    510 				p = "/";
    511 			else
    512 				p = "/tmp";
    513 		}
    514 		scopy(p, s);
    515 		strcat(s, "/trace");
    516 	}
    517 #else
    518 	snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
    519 #endif /* not_this_way */
    520 	if (tracefile) {
    521 		if (!freopen(s, "a", tracefile)) {
    522 			fprintf(stderr, "Can't re-open %s\n", s);
    523 			tracefile = NULL;
    524 			debug = 0;
    525 			return;
    526 		}
    527 	} else {
    528 		if ((tracefile = fopen(s, "a")) == NULL) {
    529 			fprintf(stderr, "Can't open %s\n", s);
    530 			debug = 0;
    531 			return;
    532 		}
    533 	}
    534 #ifdef O_APPEND
    535 	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
    536 		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
    537 #endif
    538 	setlinebuf(tracefile);
    539 	fputs("\nTracing started.\n", tracefile);
    540 }
    541 #endif /* DEBUG */
    542