767 lines · 15.2 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * command tree climbing */ #include "sh.h" #define INDENT	4 #define tputc(c, shf)	shf_putchar(c, shf);static void 	ptree ARGS((struct op *t, int indent, struct shf *f));static void 	pioact ARGS((struct shf *f, int indent, struct ioword *iop));static void	tputC ARGS((int c, struct shf *shf));static void	tputS ARGS((char *wp, struct shf *shf));static void	vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va));static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap));static void     iofree ARGS((struct ioword **iow, Area *ap)); /* * print a command tree */ static voidptree(t, indent, shf)	register struct op *t;	int indent;	register struct shf *shf;{	register char **w;	struct ioword **ioact;	struct op *t1;  Chain:	if (t == NULL)		return;	switch (t->type) {	  case TCOM:		if (t->vars)			for (w = t->vars; *w != NULL; )				fptreef(shf, indent, "%S ", *w++);		else			fptreef(shf, indent, "#no-vars# ");		if (t->args)			for (w = t->args; *w != NULL; )				fptreef(shf, indent, "%S ", *w++);		else			fptreef(shf, indent, "#no-args# ");		break;	  case TEXEC:#if 0 /* ?not useful - can't be called? */		/* Print original vars */		if (t->left->vars)			for (w = t->left->vars; *w != NULL; )				fptreef(shf, indent, "%S ", *w++);		else			fptreef(shf, indent, "#no-vars# ");		/* Print expanded vars */		if (t->args)			for (w = t->args; *w != NULL; )				fptreef(shf, indent, "%s ", *w++);		else			fptreef(shf, indent, "#no-args# ");		/* Print original io */		t = t->left;#else		t = t->left;		goto Chain;#endif	  case TPAREN:		fptreef(shf, indent + 2, "( %T) ", t->left);		break;	  case TPIPE:		fptreef(shf, indent, "%T| ", t->left);		t = t->right;		goto Chain;	  case TLIST:		fptreef(shf, indent, "%T%;", t->left);		t = t->right;		goto Chain;	  case TOR:	  case TAND:		fptreef(shf, indent, "%T%s %T",			t->left, (t->type==TOR) ? "||" : "&&", t->right);		break;	  case TBANG:		fptreef(shf, indent, "! ");		t = t->right;		goto Chain;	  case TDBRACKET:	  {		int i; 		fptreef(shf, indent, "[[");		for (i = 0; t->args[i]; i++)			fptreef(shf, indent, " %S", t->args[i]);		fptreef(shf, indent, " ]] ");		break;	  }#ifdef KSH	  case TSELECT:		fptreef(shf, indent, "select %s ", t->str);		/* fall through */#endif /* KSH */	  case TFOR:		if (t->type == TFOR)			fptreef(shf, indent, "for %s ", t->str);		if (t->vars != NULL) {			fptreef(shf, indent, "in ");			for (w = t->vars; *w; )				fptreef(shf, indent, "%S ", *w++);			fptreef(shf, indent, "%;");		}		fptreef(shf, indent + INDENT, "do%N%T", t->left);		fptreef(shf, indent, "%;done ");		break;	  case TCASE:		fptreef(shf, indent, "case %S in", t->str);		for (t1 = t->left; t1 != NULL; t1 = t1->right) {			fptreef(shf, indent, "%N(");			for (w = t1->vars; *w != NULL; w++)				fptreef(shf, indent, "%S%c", *w,					(w[1] != NULL) ? '|' : ')');			fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);		}		fptreef(shf, indent, "%Nesac ");		break;	  case TIF:	  case TELIF:		/* 3 == strlen("if ") */		fptreef(shf, indent + 3, "if %T", t->left);		for (;;) {			t = t->right;			if (t->left != NULL) {				fptreef(shf, indent, "%;");				fptreef(shf, indent + INDENT, "then%N%T",					t->left);			}			if (t->right == NULL || t->right->type != TELIF)				break;			t = t->right;			fptreef(shf, indent, "%;");			/* 5 == strlen("elif ") */			fptreef(shf, indent + 5, "elif %T", t->left);		}		if (t->right != NULL) {			fptreef(shf, indent, "%;");			fptreef(shf, indent + INDENT, "else%;%T", t->right);		}		fptreef(shf, indent, "%;fi ");		break;	  case TWHILE:	  case TUNTIL:		/* 6 == strlen("while"/"until") */		fptreef(shf, indent + 6, "%s %T",			(t->type==TWHILE) ? "while" : "until",			t->left);		fptreef(shf, indent, "%;do");		fptreef(shf, indent + INDENT, "%;%T", t->right);		fptreef(shf, indent, "%;done ");		break;	  case TBRACE:		fptreef(shf, indent + INDENT, "{%;%T", t->left);		fptreef(shf, indent, "%;} ");		break;	  case TCOPROC:		fptreef(shf, indent, "%T|& ", t->left);		break;	  case TASYNC:		fptreef(shf, indent, "%T& ", t->left);		break;	  case TFUNCT:		fptreef(shf, indent,			t->u.ksh_func ? "function %s %T" : "%s() %T",				t->str, t->left);		break;	  case TTIME:		fptreef(shf, indent, "time %T", t->left);		break;	  default:		fptreef(shf, indent, "<botch>");		break;	}	if ((ioact = t->ioact) != NULL) {		int	need_nl = 0; 		while (*ioact != NULL)			pioact(shf, indent, *ioact++);		/* Print here documents after everything else... */		for (ioact = t->ioact; *ioact != NULL; ) {			struct ioword *iop = *ioact++; 			/* heredoc is 0 when tracing (set -x) */			if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {				tputc('\n', shf);				shf_puts(iop->heredoc, shf);				fptreef(shf, indent, "%s",					evalstr(iop->delim, 0));				need_nl = 1;			}		}		/* Last delimiter must be followed by a newline (this often		 * leads to an extra blank line, but its not worth worrying		 * about)		 */		if (need_nl)			tputc('\n', shf);	}} static voidpioact(shf, indent, iop)	register struct shf *shf;	int indent;	register struct ioword *iop;{	int flag = iop->flag;	int type = flag & IOTYPE;	int expected; 	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0		    : (type == IOCAT || type == IOWRITE) ? 1		    : (type == IODUP && (iop->unit == !(flag & IORDUP))) ?			iop->unit		    : iop->unit + 1;	if (iop->unit != expected)		tputc('0' + iop->unit, shf); 	switch (type) {	case IOREAD:		fptreef(shf, indent, "< ");		break;	case IOHERE:		if (flag&IOSKIP)			fptreef(shf, indent, "<<- ");		else			fptreef(shf, indent, "<< ");		break;	case IOCAT:		fptreef(shf, indent, ">> ");		break;	case IOWRITE:		if (flag&IOCLOB)			fptreef(shf, indent, ">| ");		else			fptreef(shf, indent, "> ");		break;	case IORDWR:		fptreef(shf, indent, "<> ");		break;	case IODUP:		if (flag & IORDUP)			fptreef(shf, indent, "<&");		else			fptreef(shf, indent, ">&");		break;	}	/* name/delim are 0 when printing syntax errors */	if (type == IOHERE) {		if (iop->delim)			fptreef(shf, indent, "%S ", iop->delim);	} else if (iop->name)		fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",			iop->name);}  /* * variants of fputc, fputs for ptreef and snptreef */ static voidtputC(c, shf)	register int c;	register struct shf *shf;{	if ((c&0x60) == 0) {		/* C0|C1 */		tputc((c&0x80) ? '$' : '^', shf);		tputc(((c&0x7F)|0x40), shf);	} else if ((c&0x7F) == 0x7F) {	/* DEL */		tputc((c&0x80) ? '$' : '^', shf);		tputc('?', shf);	} else		tputc(c, shf);} static voidtputS(wp, shf)	register char *wp;	register struct shf *shf;{	register int c, quoted=0; 	/* problems:	 *	`...` -> $(...)	 *	'foo' -> "foo"	 * could change encoding to:	 *	OQUOTE ["'] ... CQUOTE ["']	 * 	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)	 */	while (1)		switch ((c = *wp++)) {		  case EOS:			return;		  case CHAR:			tputC(*wp++, shf);			break;		  case QCHAR:			c = *wp++;			if (!quoted || (c == '"' || c == '`' || c == '$'))				tputc('\\', shf);			tputC(c, shf);			break;		  case COMSUB:			tputc('$', shf);			tputc('(', shf);			while (*wp != 0)				tputC(*wp++, shf);			tputc(')', shf);			wp++;			break;		  case EXPRSUB:			tputc('$', shf);			tputc('(', shf);			tputc('(', shf);			while (*wp != 0)				tputC(*wp++, shf);			tputc(')', shf);			tputc(')', shf);			wp++;			break;		  case OQUOTE:		  	quoted = 1;			tputc('"', shf);			break;		  case CQUOTE:			quoted = 0;			tputc('"', shf);			break;		  case OSUBST:			tputc('$', shf);			if (*wp++ == '{')				tputc('{', shf);			while ((c = *wp++) != 0)				tputC(c, shf);			break;		  case CSUBST:			if (*wp++ == '}')				tputc('}', shf);			break;#ifdef KSH		  case OPAT:			tputc(*wp++, shf);			tputc('(', shf);			break;		  case SPAT:			tputc('|', shf);			break;		  case CPAT:			tputc(')', shf);			break;#endif /* KSH */		}} /* * this is the _only_ way to reliably handle * variable args with an ANSI compiler *//* VARARGS */int#ifdef HAVE_PROTOTYPESfptreef(struct shf *shf, int indent, const char *fmt, ...)#elsefptreef(shf, indent, fmt, va_alist)   struct shf *shf;  int indent;  const char *fmt;  va_dcl#endif{  va_list	va;   SH_VA_START(va, fmt);    vfptreef(shf, indent, fmt, va);  va_end(va);  return 0;} /* VARARGS */char *#ifdef HAVE_PROTOTYPESsnptreef(char *s, int n, const char *fmt, ...)#elsesnptreef(s, n, fmt, va_alist)  char *s;  int n;  const char *fmt;  va_dcl#endif{  va_list va;  struct shf shf;   shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);   SH_VA_START(va, fmt);  vfptreef(&shf, 0, fmt, va);  va_end(va);   return shf_sclose(&shf); /* null terminates */} static voidvfptreef(shf, indent, fmt, va)	register struct shf *shf;	int indent;	const char *fmt;	register va_list va;{	register int c; 	while ((c = *fmt++))	    if (c == '%') {		register long n;		register char *p;		int neg; 		switch ((c = *fmt++)) {		  case 'c':			tputc(va_arg(va, int), shf);			break;		  case 's':			p = va_arg(va, char *);			while (*p)				tputc(*p++, shf);			break;		  case 'S':	/* word */			p = va_arg(va, char *);			tputS(p, shf);			break;		  case 'd': case 'u': /* decimal */			n = (c == 'd') ? va_arg(va, int)				       : va_arg(va, unsigned int);			neg = c=='d' && n<0;			p = ulton((neg) ? -n : n, 10);			if (neg)				*--p = '-';			while (*p)				tputc(*p++, shf);			break;		  case 'T':	/* format tree */			ptree(va_arg(va, struct op *), indent, shf);			break;		  case ';':	/* newline or ; */		  case 'N':	/* newline or space */			if (shf->flags & SHF_STRING) {				if (c == ';')					tputc(';', shf);				tputc(' ', shf);			} else {				int i; 				tputc('\n', shf);				for (i = indent; i >= 8; i -= 8)					tputc('\t', shf);				for (; i > 0; --i)					tputc(' ', shf);			}			break;		  case 'R':			pioact(shf, indent, va_arg(va, struct ioword *));			break;		  default:			tputc(c, shf);			break;		}	    } else		tputc(c, shf);} /* * copy tree (for function definition) */ struct op *tcopy(t, ap)	register struct op *t;	Area *ap;{	register struct op *r;	register char **tw, **rw;

Lines 1–500 of 767.