Commit Diff


commit - 02f38ca68ce484b2aad15fad4d59c4d43ef7eb1b
commit + 9aa1c92f743a7bf2ac0b062b0c075dc610b3e335
blob - 0a084a654e4e23cbb0bd46e557d8fe31a93cf1d1
blob + 8df159e31f7b1ce73d1691364cb0ec5e9d98ba59
--- src/cmd/mk/fns.h
+++ src/cmd/mk/fns.h
@@ -11,10 +11,8 @@ void	atouch(char*);
 void	bufcpy(Bufblock *, char *, int);
 Envy	*buildenv(Job*, int);
 void	catchnotes(void);
-char 	*charin(char *, char *);
 int	chgtime(char*);
 void	clrmade(Node*);
-char	*copyq(char*, Rune, Bufblock*);
 void	delete(char*);
 void	delword(Word*);
 int	dorecipe(Node*);
@@ -24,24 +22,23 @@ void	dumpn(char*, Node*);
 void	dumpr(char*, Rule*);
 void	dumpv(char*);
 void	dumpw(char*, Word*);
-int	escapetoken(Biobuf*, Bufblock*, int, int);
 void	execinit(void);
-int	execsh(char*, char*, Bufblock*, Envy*);
+int	execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*);
 void	Exit(void);
-char	*expandquote(char*, Rune, Bufblock*);
 void	expunge(int, char*);
 void	freebuf(Bufblock*);
 void	front(char*);
 Node	*graph(char*);
 void	growbuf(Bufblock *);
 void	initenv(void);
+void	initshell(void);
 void	insert(Bufblock *, int);
 void	ipop(void);
 void	ipush(void);
 void	killchildren(char*);
 void	*Malloc(int);
 char	*maketmp(int*);
-int	match(char*, char*, char*);
+int	match(char*, char*, char*, Shell*);
 char *membername(char*, int, char*);
 void	mk(char*);
 ulong	mkmtime(char*);
@@ -56,17 +53,21 @@ void	nproc(void);
 void	nrep(void);
 int	outofdate(Node*, Arc*, int);
 void	parse(char*, int, int);
-int	pipecmd(char*, Envy*, int*);
+int	pipecmd(char*, Envy*, int*, Shell*, Word*);
+void	popshell(void);
 void	prusage(void);
+void	pushshell(void);
 void	rcopy(char**, Resub*, int);
 void	readenv(void);
 void	*Realloc(void*, int);
 void	rinsert(Bufblock *, Rune);
 char	*rulecnt(void);
 void	run(Job*);
+char	*setshell(Word*);
 void	setvar(char*, void*);
+int	shargv(Word*, int, char***);
 char	*shname(char*);
-void	shprint(char*, Envy*, Bufblock*);
+void	shprint(char*, Envy*, Bufblock*, Shell*);
 Word	*stow(char*);
 void	subst(char*, char*, char*);
 void	symdel(char*, int);
blob - fdb028811514c503b2b6b33ebfee2ccc3e73ac5b
blob + 80721237c021d54ceb05e3de1b9167f1ad7c7c93
--- src/cmd/mk/graph.c
+++ src/cmd/mk/graph.c
@@ -84,7 +84,7 @@ applyrules(char *target, char *cnt)
 			if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
 				continue;
 		} else {
-			if(!match(node->name, r->target, stem)) continue;
+			if(!match(node->name, r->target, stem, r->shellt)) continue;
 		}
 		if(cnt[r->rule] >= nreps) continue;
 		cnt[r->rule]++;
blob - 3ee244f184e6af975e48fc973bcee89e0b62c051
blob + 6fd7b5c79a9b208d1b9c1dcd39de926964a7cd6d
--- src/cmd/mk/lex.c
+++ src/cmd/mk/lex.c
@@ -28,7 +28,7 @@ assline(Biobuf *bp, Bufblock *buf)
 		case '\'':
 		case '"':
 			rinsert(buf, c);
-			if (escapetoken(bp, buf, 1, c) == 0)
+			if (shellt->escapetoken(bp, buf, 1, c) == 0)
 				Exit();
 			break;
 		case '`':
@@ -87,14 +87,14 @@ bquote(Biobuf *bp, Bufblock *buf)
 			insert(buf,0);
 			buf->current = buf->start+start;
 			execinit();
-			execsh(0, buf->current, buf, envy);
+			execsh(0, buf->current, buf, envy, shellt, shellcmd);
 			return 1;
 		}
 		if(c == '\n')
 			break;
 		if(c == '\'' || c == '"' || c == '\\'){
 			insert(buf, c);
-			if(!escapetoken(bp, buf, 1, c))
+			if(!shellt->escapetoken(bp, buf, 1, c))
 				return 0;
 			continue;
 		}
blob - fdd947772d3a4f91b2d8fa9dda9eb40b3ae53c81
blob + 645eb7ae6167f12071adc94b83511d78a74092c5
--- src/cmd/mk/main.c
+++ src/cmd/mk/main.c
@@ -39,6 +39,7 @@ main(int argc, char **argv)
 	 *  instead of sharing them
 	 */
 
+	initshell();
 	Binit(&bout, 1, OWRITE);
 	buf = newbuf();
 	whatif = 0;
blob - 2a96394aa8c64f846ae09db549e0b3c44839228f
blob + 270621fb2025e70bd1bda2c9395d78b76cfcadbf
--- src/cmd/mk/match.c
+++ src/cmd/mk/match.c
@@ -1,7 +1,7 @@
 #include	"mk.h"
 
 int
-match(char *name, char *template, char *stem)
+match(char *name, char *template, char *stem, Shell *sh)
 {
 	Rune r;
 	int n;
@@ -24,7 +24,7 @@ match(char *name, char *template, char *stem)
 	strncpy(stem, name, n);
 	stem[n] = 0;
 	if(*template == '&')
-		return !charin(stem, "./");
+		return !sh->charin(stem, "./");
 	return 1;
 }
 
blob - 9ab4c538f260cc591d4dd44d3832efaa25b6d642
blob + dbb749927e3072bd615f2ba9c80e7224f1f208d3
--- src/cmd/mk/mk.c
+++ src/cmd/mk/mk.c
@@ -192,14 +192,14 @@ update(int fake, Node *node)
 }
 
 static int
-pcmp(char *prog, char *p, char *q)
+pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd)
 {
 	char buf[3*NAMEBLOCK];
 	int pid;
 
 	Bflush(&bout);
 	snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
-	pid = pipecmd(buf, 0, 0);
+	pid = pipecmd(buf, 0, 0, sh, shcmd);
 	while(waitup(-3, &pid) >= 0)
 		;
 	return(pid? 2:1);
@@ -219,7 +219,7 @@ outofdate(Node *node, Arc *arc, int eval)
 		if(sym == 0 || eval){
 			if(sym == 0)
 				str = strdup(buf);
-			ret = pcmp(arc->prog, node->name, arc->n->name);
+			ret = pcmp(arc->prog, node->name, arc->n->name, arc->r->shellt, arc->r->shellcmd);
 			if(sym)
 				sym->value = (void *)ret;
 			else
blob - 33402de0a0c44a3fd027ea5f50d1ba22f65c4e29
blob + 81f9d70c5232014cb6a7b7c82e613c567a18b85e
--- src/cmd/mk/mk.h
+++ src/cmd/mk/mk.h
@@ -26,6 +26,18 @@ typedef struct Envy
 
 extern Envy *envy;
 
+typedef struct Shell
+{
+	char *name;
+	char	*termchars;	/* used in parse.c to isolate assignment attribute */
+	int	iws;			/* inter-word separator in environment */
+	char	*(*charin)(char*, char*);	/* search for unescaped characters */
+	char	*(*expandquote)(char*, Rune, Bufblock*);	/* extract escaped token */
+	int	(*escapetoken)(Biobuf*, Bufblock*, int, int);	/* input escaped token */
+	char	*(*copyq)(char*, Rune, Bufblock*);	/* check for quoted strings */
+	int	(*matchname)(char*);	/* does name match */
+} Shell;
+
 typedef struct Rule
 {
 	char 		*target;	/* one target */
@@ -40,6 +52,8 @@ typedef struct Rule
 	char		*prog;		/* to use in out of date */
 	struct Rule	*chain;		/* hashed per target */
 	struct Rule	*next;
+	Shell		*shellt;	/* shell to use with this rule */
+	Word	*shellcmd;
 } Rule;
 
 extern Rule *rules, *metarules, *patrule;
@@ -143,12 +157,11 @@ extern	int	mkinline;
 extern	char	*infile;
 extern	int	nreps;
 extern	char	*explain;
-extern	char	*termchars;
-extern	int	IWS;
-extern	char 	*shell;
-extern	char 	*shellname;
-extern	char 	*shflags;
+extern	Shell	*shellt;
+extern	Word	*shellcmd;
 
+extern	Shell	shshell, rcshell;
+
 #define	SYNERR(l)	(fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline))
 #define	RERR(r)		(fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line))
 #define	NAMEBLOCK	1000
blob - 5c1c0edaffa699225488fdf5a9e8b04a1951addc
blob + b5bd6dbbc74f437952c65a55ee809110c6ffd777
--- src/cmd/mk/mkfile.test
+++ src/cmd/mk/mkfile.test
@@ -1,5 +1,12 @@
-a: b
-	cp b a
+|$PLAN9/bin/rc
+use-rc:V:
+	for(i in a b c)
+		echo $i
 
-c:V:
-	echo hello world
+|/bin/sh
+use-sh:V:
+	for i in a b c
+	do
+		echo $i
+	done
+
blob - b7737ef9bbe9db1e75937ddcb1e1b70e96c7a54f
blob + 2d1816b9eb26c03f01b04cd7f4675bece41dede6
--- src/cmd/mk/parse.c
+++ src/cmd/mk/parse.c
@@ -17,11 +17,13 @@ parse(char *f, int fd, int varoverride)
 	int newfd;
 	Biobuf in;
 	Bufblock *buf;
+	char *err;
 
 	if(fd < 0){
 		fprint(2, "open %s: %r\n", f);
 		Exit();
 	}
+	pushshell();
 	ipush();
 	infile = strdup(f);
 	mkinline = 1;
@@ -52,7 +54,7 @@ parse(char *f, int fd, int varoverride)
 				Exit();
 			}
 			execinit();
-			pid=pipecmd(p, envy, &newfd);
+			pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
 			if(newfd < 0){
 				fprint(2, "warning: skipping missing program file %s: %r\n", p);
 			} else
@@ -93,6 +95,14 @@ cp = wtos(tail, ' '); print("assign %s to %s\n", head-
 			if(attr)
 				symlook(head->s, S_NOEXPORT, (void *)"");
 			break;
+		case 'S':
+			if((err = setshell(tail)) != nil){
+				SYNERR(hline);
+				fprint(2, "%s\n", err);
+				Exit();
+				break;
+			}
+			break;
 		default:
 			SYNERR(hline);
 			fprint(2, "expected one of :<=\n");
@@ -103,6 +113,7 @@ cp = wtos(tail, ' '); print("assign %s to %s\n", head-
 	close(fd);
 	freebuf(buf);
 	ipop();
+	popshell();
 }
 
 void
@@ -114,7 +125,7 @@ addrules(Word *head, Word *tail, char *body, int attr,
 		/* tuck away first non-meta rule as default target*/
 	if(target1 == 0 && !(attr&REGEXP)){
 		for(w = head; w; w = w->next)
-			if(charin(w->s, "%&"))
+			if(shellt->charin(w->s, "%&"))
 				break;
 		if(w == 0)
 			target1 = wdup(head);
@@ -133,19 +144,24 @@ rhead(char *line, Word **h, Word **t, int *attr, char 
 	int n;
 	Word *w;
 
-	p = charin(line,":=<");
-	if(p == 0)
-		return('?');
-	sep = *p;
-	*p++ = 0;
-	if(sep == '<' && *p == '|'){
-		sep = '|';
-		p++;
+	if(*line == '|'){
+		sep = 'S';	/* shell */
+		p = line+1;
+	}else{
+		p = shellt->charin(line,":=<");
+		if(p == 0)
+			return('?');
+		sep = *p;
+		*p++ = 0;
+		if(sep == '<' && *p == '|'){
+			sep = '|';
+			p++;
+		}
 	}
 	*attr = 0;
 	*prog = 0;
 	if(sep == '='){
-		pp = charin(p, termchars);	/* termchars is shell-dependent */
+		pp = shellt->charin(p, shellt->termchars);	/* termchars is shell-dependent */
 		if (pp && *pp == '=') {
 			while (p != pp) {
 				n = chartorune(&r, p);
@@ -219,7 +235,7 @@ rhead(char *line, Word **h, Word **t, int *attr, char 
 		}
 	}
 	*h = w = stow(line);
-	if(*w->s == 0 && sep != '<' && sep != '|') {
+	if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
 		SYNERR(mkinline-1);
 		fprint(2, "no var on left side of assignment/rule\n");
 		Exit();
blob - 657ddf2783019a0b34309bf0a10162f301e18b81
blob + 53f5d5a5fb93c5d87d1e0aaa4b8c131215dfacb3
--- src/cmd/mk/rc.c
+++ src/cmd/mk/rc.c
@@ -1,9 +1,5 @@
 #include	"mk.h"
 
-char	*termchars = "'= \t";	/*used in parse.c to isolate assignment attribute*/
-char	*shflags = "-I";	/* rc flag to force non-interactive mode */
-int	IWS = '\1';		/* inter-word separator in env - not used in plan 9 */
-
 /*
  *	This file contains functions that depend on rc's syntax.  Most
  *	of the routines extract strings observing rc's escape conventions
@@ -38,7 +34,7 @@ squote(char *cp)
  *	characters in quotes and variable generators are escaped
  */
 char *
-charin(char *cp, char *pat)
+rccharin(char *cp, char *pat)
 {
 	Rune r;
 	int n, vargen;
@@ -82,7 +78,7 @@ charin(char *cp, char *pat)
  *	others are just inserted into the receiving buffer.
  */
 char*
-expandquote(char *s, Rune r, Bufblock *b)
+rcexpandquote(char *s, Rune r, Bufblock *b)
 {
 	if (r != '\'') {
 		rinsert(b, r);
@@ -108,7 +104,7 @@ expandquote(char *s, Rune r, Bufblock *b)
  *	rc; the others are just inserted into the receiving buffer.
  */
 int
-escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
+rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
 {
 	int c, line;
 
@@ -155,7 +151,7 @@ copysingle(char *s, Bufblock *buf)
  *	s points to char after opening quote, q.
  */
 char *
-copyq(char *s, Rune q, Bufblock *buf)
+rccopyq(char *s, Rune q, Bufblock *buf)
 {
 	if(q == '\'')				/* copy quoted string */
 		return copysingle(s, buf);
@@ -173,3 +169,26 @@ copyq(char *s, Rune q, Bufblock *buf)
 	}
 	return s;
 }
+
+static int
+rcmatchname(char *name)
+{
+	char *p;
+
+	if((p = strchr(name, '/')) != nil)
+		name = p+1;
+	if(name[0] == 'r' && name[1] == 'c')
+		return 1;
+	return 0;
+}
+
+Shell rcshell = {
+	"rc",
+	"'= \t",
+	'\1',
+	rccharin,
+	rcexpandquote,
+	rcescapetoken,
+	rccopyq,
+	rcmatchname,
+};
blob - 662f067f1a242a13fe08ab311b9ec91ee5e8e572
blob + d73595d2614c113977806f2d5b7e82ff3b544ff7
--- src/cmd/mk/rule.c
+++ src/cmd/mk/rule.c
@@ -23,6 +23,8 @@ addrule(char *head, Word *tail, char *body, Word *ahea
 	}
 	if(r == 0)
 		r = (Rule *)Malloc(sizeof(Rule));
+	r->shellt = shellt;
+	r->shellcmd = shellcmd;
 	r->target = head;
 	r->tail = tail;
 	r->recipe = body;
@@ -42,7 +44,7 @@ addrule(char *head, Word *tail, char *body, Word *ahea
 	}
 	if(!reuse)
 		r->next = 0;
-	if((attr&REGEXP) || charin(head, "%&")){
+	if((attr&REGEXP) || shellt->charin(head, "%&")){
 		r->attr |= META;
 		if(reuse)
 			return;
@@ -72,7 +74,8 @@ addrule(char *head, Word *tail, char *body, Word *ahea
 void
 dumpr(char *s, Rule *r)
 {
-	Bprint(&bout, "%s: start=%ld\n", s, r);
+	Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n", 
+		s, r, r->shellt->name, wtos(r->shellcmd, ' '));
 	for(; r; r = r->next){
 		Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'",
 			r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));
blob - 3c0c7f3e213307b3d69c3b574f8230995568ee8d
blob + 439cc0a5c85fee67304c6b05ea25b63c00eed081
--- src/cmd/mk/run.c
+++ src/cmd/mk/run.c
@@ -59,7 +59,7 @@ sched(void)
 	events[slot].job = j;
 	buf = newbuf();
 	e = buildenv(j, slot);
-	shprint(j->r->recipe, e, buf);
+	shprint(j->r->recipe, e, buf, j->r->shellt);
 	if(!tflag && (nflag || !(j->r->attr&QUIET)))
 		Bwrite(&bout, buf->start, (long)strlen(buf->start));
 	freebuf(buf);
@@ -82,7 +82,7 @@ sched(void)
 			flags = 0;
 		else
 			flags = "-e";
-		events[slot].pid = execsh(flags, j->r->recipe, 0, e);
+		events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd);
 		usage();
 		nrunning++;
 		if(DEBUG(D_EXEC))
@@ -145,7 +145,7 @@ again:		/* rogue processes */
 	if(buf[0]){
 		e = buildenv(j, slot);
 		bp = newbuf();
-		shprint(j->r->recipe, e, bp);
+		shprint(j->r->recipe, e, bp, j->r->shellt);
 		front(bp->start);
 		fprint(2, "mk: %s: exit status=%s", bp->start, buf);
 		freebuf(bp);
blob - 524167a52bc1b3c948134574351c015646433a37
blob + ba80162bfa090629d4e48beb4f6073e7e437b32d
--- src/cmd/mk/sh.c
+++ src/cmd/mk/sh.c
@@ -1,9 +1,5 @@
 #include	"mk.h"
 
-char	*termchars = "\"'= \t";	/*used in parse.c to isolate assignment attribute*/
-char	*shflags = 0;
-int	IWS = ' ';		/* inter-word separator in env */
-
 /*
  *	This file contains functions that depend on the shell's syntax.  Most
  *	of the routines extract strings observing the shell's escape conventions.
@@ -34,8 +30,8 @@ squote(char *cp, int c)
 /*
  *	search a string for unescaped characters in a pattern set
  */
-char *
-charin(char *cp, char *pat)
+static char *
+shcharin(char *cp, char *pat)
 {
 	Rune r;
 	int n, vargen;
@@ -82,8 +78,8 @@ charin(char *cp, char *pat)
  *	extract an escaped token.  Possible escape chars are single-quote,
  *	double-quote,and backslash.
  */
-char*
-expandquote(char *s, Rune esc, Bufblock *b)
+static char*
+shexpandquote(char *s, Rune esc, Bufblock *b)
 {
 	Rune r;
 
@@ -110,8 +106,8 @@ expandquote(char *s, Rune esc, Bufblock *b)
  *	Input an escaped token.  Possible escape chars are single-quote,
  *	double-quote and backslash.
  */
-int
-escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
+static int
+shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
 {
 	int c, line;
 
@@ -168,8 +164,8 @@ copysingle(char *s, Rune q, Bufblock *buf)
  *	check for quoted strings.  backquotes are handled here; single quotes above.
  *	s points to char after opening quote, q.
  */
-char *
-copyq(char *s, Rune q, Bufblock *buf)
+static char *
+shcopyq(char *s, Rune q, Bufblock *buf)
 {
 	if(q == '\'' || q == '"')		/* copy quoted string */
 		return copysingle(s, q, buf);
@@ -187,3 +183,24 @@ copyq(char *s, Rune q, Bufblock *buf)
 	}
 	return s;
 }
+
+static int
+shmatchname(char *name)
+{
+	USED(name);
+
+	return 1;
+}
+
+
+Shell shshell = {
+	"sh",
+	"\"'= \t",	/*used in parse.c to isolate assignment attribute*/
+	' ',	/* inter-word separator in env */
+	shcharin,
+	shexpandquote,
+	shescapetoken,
+	shcopyq,
+	shmatchname,
+};
+
blob - 7cfa5f4c17c229805c4d0f28743fa5a4a61ecad6
blob + eb12fabca179a07b9e0a083d6a66cc5888ca5cdf
--- src/cmd/mk/shprint.c
+++ src/cmd/mk/shprint.c
@@ -40,7 +40,7 @@ getfields(char *str, char **args, int max, int mflag, 
 }
 
 void
-shprint(char *s, Envy *env, Bufblock *buf)
+shprint(char *s, Envy *env, Bufblock *buf, Shell *sh)
 {
 	int n;
 	Rune r;
@@ -52,7 +52,7 @@ shprint(char *s, Envy *env, Bufblock *buf)
 		else {
 			rinsert(buf, r);
 			s += n;
-			s = copyq(s, r, buf);	/*handle quoted strings*/
+			s = sh->copyq(s, r, buf);	/*handle quoted strings*/
 		}
 	}
 	insert(buf, 0);
blob - /dev/null
blob + a4ac3f9355c097eb009994a269a4c8e9b707233d (mode 644)
--- /dev/null
+++ src/cmd/mk/shell.c
@@ -0,0 +1,76 @@
+#include "mk.h"
+
+static Shell *shells[] = {
+	&shshell,
+	&rcshell
+};
+
+Shell *shellt;
+Word *shellcmd;
+
+typedef struct Shellstack Shellstack;
+struct Shellstack
+{
+	Shell *t;
+	Word *w;
+	Shellstack *next;
+};
+
+Shellstack *shellstack;
+
+char*
+setshell(Word *w)
+{
+	int i;
+
+	if(w->s == nil)
+		return "shell name not found on line";
+
+	for(i=0; i<nelem(shells); i++)
+		if(shells[i]->matchname(w->s))
+			break;
+	if(i == nelem(shells))
+		return "cannot determine shell type";
+	shellt = shells[i];
+	shellcmd = w;
+	return nil;
+}
+
+void
+initshell(void)
+{
+	shellcmd = stow(shells[0]->name);
+	shellt = shells[0];
+}
+
+void
+pushshell(void)
+{
+	Shellstack *s;
+
+	/* save */
+	s = Malloc(sizeof *s);
+	s->t = shellt;
+	s->w = shellcmd;
+	s->next = shellstack;
+	shellstack = s;
+
+	initshell();	/* reset to defaults */
+}
+
+void
+popshell(void)
+{
+	Shellstack *s;
+
+	if(shellstack == nil){
+		fprint(2, "internal shellstack error\n");
+		Exit();
+	}
+
+	s = shellstack;
+	shellstack = s->next;
+	shellt = s->t;
+	shellcmd = s->w;
+	free(s);
+}
blob - 9e4fcea9949ab4c0ee5e6a710e8a24b77131575b
blob + 97356105e8f095c008648850319823a8097348d3
--- src/cmd/mk/unix.c
+++ src/cmd/mk/unix.c
@@ -51,7 +51,7 @@ readenv(void)
  *	to exec immediately after this.
  */
 void
-exportenv(Envy *e)
+exportenv(Envy *e, Shell *sh)
 {
 	int i;
 	char **p;
@@ -61,7 +61,7 @@ exportenv(Envy *e)
 	for(i = 0; e->name; e++, i++) {
 		p = (char**) Realloc(p, (i+2)*sizeof(char*));
 		if(e->values)
-			snprint(buf, sizeof buf, "%s=%s", e->name,  wtos(e->values, IWS));
+			snprint(buf, sizeof buf, "%s=%s", e->name,  wtos(e->values, sh->iws));
 		else
 			snprint(buf, sizeof buf, "%s=", e->name);
 		p[i] = strdup(buf);
@@ -102,9 +102,29 @@ expunge(int pid, char *msg)
 int mypid;
 
 int
-execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
+shargv(Word *cmd, int extra, char ***pargv)
 {
-	char *p;
+	char **argv;
+	int i, n;
+	Word *w;
+
+	n = 0;
+	for(w=cmd; w; w=w->next)
+		n++;
+	
+	argv = Malloc((n+extra+1)*sizeof(argv[0]));
+	i = 0;
+	for(w=cmd; w; w=w->next)
+		argv[i++] = w->s;
+	argv[n] = 0;
+	*pargv = argv;
+	return n;
+}	
+
+int
+execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd)
+{
+	char *p, **argv;
 	int tot, n, pid, in[2], out[2];
 
 	if(buf && pipe(out) < 0){
@@ -138,11 +158,11 @@ execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
 			close(in[0]);
 			close(in[1]);
 			if (e)
-				exportenv(e);
-			if(shflags)
-				execl(shell, shellname, shflags, args, 0);
-			else
-				execl(shell, shellname, args, 0);
+				exportenv(e, sh);
+			n = shargv(shellcmd, 1, &argv);
+			argv[n++] = args;
+			argv[n] = 0;
+			execvp(argv[0], argv);
 			mkperror(shell);
 			_exit(1);
 		}
@@ -180,9 +200,11 @@ execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
 }
 
 int
-pipecmd(char *cmd, Envy *e, int *fd)
+pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd)
 {
 	int pid, pfd[2];
+	int n;
+	char **argv;
 
 	if(DEBUG(D_EXEC))
 		fprint(1, "pipecmd='%s'\n", cmd);/**/
@@ -203,11 +225,12 @@ pipecmd(char *cmd, Envy *e, int *fd)
 			close(pfd[1]);
 		}
 		if(e)
-			exportenv(e);
-		if(shflags)
-			execl(shell, shellname, shflags, "-c", cmd, 0);
-		else
-			execl(shell, shellname, "-c", cmd, 0);
+			exportenv(e, sh);
+		n = shargv(shellcmd, 2, &argv);
+		argv[n++] = "-c";
+		argv[n++] = cmd;
+		argv[n] = 0;
+		execvp(argv[0], argv);
 		mkperror(shell);
 		_exit(1);
 	}
blob - /dev/null
blob + 836d7ad7cb54d31e10ab4d409b1c61ebbebef3a7 (mode 644)
--- /dev/null
+++ src/cmd/mk/sys.std.h
@@ -0,0 +1,22 @@
+#include <utf.h>
+#include <fmt.h>
+#include <bio.h>
+#include <regexp9.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#define OREAD		O_RDONLY
+#define OWRITE	O_WRONLY
+#define ORDWR	O_RDWR
+#define nil 0
+#define nelem(x) sizeof((x)/sizeof((x)[0]))
+#define seek lseek
+#define remove unlink
+#define exits(x)	exit(x && *(char*)x ? 1 : 0)
+#define USED(x)	if(x){}else
+#define create(name, mode, perm)	open(name, mode|O_CREAT, perm)
+#define ERRMAX	256
blob - 2a9ad9878af452db998f1e01afb4a541f0226b58
blob + 5b7c984a72529dd3fec588acabe3c464ac19d051
--- src/cmd/mk/varsub.c
+++ src/cmd/mk/varsub.c
@@ -103,7 +103,7 @@ expandvar(char **s)
 		return 0;
 	}
 	cp++;
-	end = charin(cp , "}");
+	end = shellt->charin(cp , "}");
 	if(end == 0){
 		SYNERR(-1);
 		fprint(2, "missing '}': %s\n", begin);
@@ -128,7 +128,7 @@ extractpat(char *s, char **r, char *term, char *end)
 	char *cp;
 	Word *w;
 
-	cp = charin(s, term);
+	cp = shellt->charin(s, term);
 	if(cp){
 		*r = cp;
 		if(cp == s)
blob - ac34c47be4aa35a5dc3f85131448439b52a341e3
blob + b0e344eabd834a2e3d6c518914f215d90b33f95d
--- src/cmd/mk/word.c
+++ src/cmd/mk/word.c
@@ -114,7 +114,7 @@ nextword(char **s)
 		case '\\':
 		case '\'':
 		case '"':
-			cp = expandquote(cp, r, b);
+			cp = shellt->expandquote(cp, r, b);
 			if(cp == 0){
 				fprint(2, "missing closing quote: %s\n", *s);
 				Exit();