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