hlfw.ca

drawcpu

Download patch

ref: 8df6746590a6bf6ebebbbc5509c6bbf5da889c59
parent: f6d48501c4c475c5c9cad077ae6b206e72e0c65d
author: halfwit <michaelmisch1985@gmail.com>
date: Sat May 24 20:32:50 PDT 2025

Remove the librc, start fixing memory

--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 **/*.o
 **/*.a
-
+bin/*
 *.a
-*.o
\ No newline at end of file
+*.o
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,6 @@
 LIBS1=\
 	kern/libkern.a\
 	libip/libip.a\
-	librc/librc.a\
 	libmemdraw/libmemdraw.a\
 	libmemlayer/libmemlayer.a\
 	libdraw/libdraw.a\
@@ -52,6 +51,3 @@
 
 gui-$(GUI)/libgui.a:
 	(cd gui-$(GUI); $(MAKE))
-
-librc/librc.a:
-	(cd librc; $(MAKE))
--- a/drawcpu.h
+++ b/drawcpu.h
@@ -1,4 +1,3 @@
 extern char *getuser(void);
-extern void rc(int, char**, int);
 extern int aanclient(char*, int);
 extern int dbg;
\ No newline at end of file
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -221,8 +221,8 @@
 void		osmsleep(int);
 ulong	ticks(void);
 void	osproc(Proc*);
-void    osexec(Proc*);
-void    *osbuildmem(Chan *, uintptr, uintptr, uintptr, int);
+void    *osbuildmem(Chan *, uintptr, uintptr, uintptr, int, uintptr);
+void    osprepmem(void*, uintptr, uintptr, uintptr, uintptr);
 void	osnewproc(Proc*);
 void    osclrmem(uintptr, uintptr);
 void	procsleep(void);
--- a/kern/posix.c
+++ b/kern/posix.c
@@ -13,6 +13,18 @@
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <sys/select.h>
+
+#if defined (__APPLE__)
+#include <mach/mach.h>
+#include <mach/vm_map.h>
+#include <mach/mach_error.h>
+#include <mach/mach_vm.h> 
+#ifdef panic
+#undef panic
+#endif
+mach_port_t task;
+#endif
+
 #include <sys/mman.h>
 #include <signal.h>
 #include <pwd.h>
@@ -59,6 +71,10 @@
 	if(pthread_key_create(&prdakey, 0))
 		panic("cannot pthread_key_create");
 
+#if defined __APPLE__
+    task = mach_task_self();
+#endif
+
 	signal(SIGPIPE, SIG_IGN);
 }
 
@@ -253,34 +269,83 @@
 void
 osclrmem(uintptr mem, uintptr ms)
 {
+
 	if(mem)
+#if defined __APPLE__
+		mach_vm_deallocate(task, (mach_vm_address_t)mem, (mach_vm_size_t)ms);
+#else
 		munmap((void*)mem, ms);
+#endif
 }
 
 void *
-osbuildmem(Chan *tc, uintptr ts, uintptr ds, uintptr bss, int offset)
+osbuildmem(Chan *tc, uintptr ts, uintptr ds, uintptr bss, int offset, uintptr align)
 {
-	int n;
-	void *exec, *binary;
+    int n;
+    void *exec, *binary;
+    size_t total_size;
 
-	/* Read in initial datum */
-	exec = mallocz(ts+ds, 1);
-	n = devtab[tc->type]->read(tc, exec, ts+ds, offset);
-	if(!exec || n < (ts+ds))
-		error("read error");
+    /* Read in initial datum */
+    exec = mallocz(ts+ds, 1);
+    n = devtab[tc->type]->read(tc, exec, ts+ds, offset);
+    if(!exec || n < (ts+ds) || n < 0)
+        error("read error: %r");
 
-	/* Contiguous memory block for text/data/bss */
-	binary = mmap(nil, n+bss, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-	if(binary == MAP_FAILED)
-		error("Failed: %r");
+#if defined __APPLE__
+    kern_return_t kr;
+    mach_vm_address_t base = 0;
+    mach_vm_size_t size = (mach_vm_size_t)(n + bss + align);
 
-	/* Mark text portion executable */
-	memcpy(binary, exec, n);
-	if(mprotect(binary, ts, PROT_EXEC|PROT_READ) != 0)
-		error("Unable to mprotect: %r");
+    kr = mach_vm_allocate(task, &base, size, VM_FLAGS_ANYWHERE);
+    if(kr != KERN_SUCCESS) 
+		error("unable to allocate: %r");
+    
+    binary = (void*)base;
+#else
+    /* Contiguous memory block - start with RW for setup */
+    binary = mmap(nil, n+bss+align, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+    if(binary == MAP_FAILED)
+        error("Failed: %r");
+#endif
+    /* Copy the binary data (text + data sections) */
+    memcpy(binary, exec, n);
+    free(exec);
+    return binary;
+}
 
-	free(exec);
-	return binary;
+void
+osprepmem(void *base, uintptr b, uintptr text, uintptr data, uintptr bss)
+{
+	uintptr *ptr, end, offset;
+
+	end = (uintptr)b+text+data;
+	offset = (uintptr)b;
+
+	/* If we needed to align, copy the data to the aligned location */
+	if(b != (uintptr)base)
+		memmove((void*)b, base, text+data);
+
+	/* Zero out BSS section at aligned location */
+	memset((void*)b + text + data, 0, bss);
+
+	/* Patch the text + data sections to meet our new base */
+    for(ptr = (uintptr*)b; (uintptr)ptr < end; ptr++) {
+        uintptr val = *ptr;
+        if(val >= UTZERO && val <= (UTZERO + text + data)) {
+            *ptr = val + offset;
+        }
+    }
+
+#if defined __APPLE__
+    kern_return_t kr;
+    kr = mach_vm_protect(task, (mach_vm_address_t)b, (mach_vm_size_t)text, FALSE, VM_PROT_READ|VM_PROT_EXECUTE);
+    if(kr != KERN_SUCCESS)
+        print("Unable to vm_protect aligned text section: %s\n", mach_error_string(kr));
+#else
+	/* Set proper memory permissions for aligned sections */
+	if(mprotect((void*)b, text, PROT_READ|PROT_EXEC) != 0)
+		print("Unable to mprotect aligned text section: %r\n");
+#endif
 }
 
 int
--- a/kern/sysproc.c
+++ b/kern/sysproc.c
@@ -13,7 +13,6 @@
 #undef rfork
 
 jmp_buf exec_jmp;
-typedef void (*Entry)(int, char**);
 
 static void
 nop(int x)
@@ -24,7 +23,7 @@
 static void
 sigsegv(int sig)
 {
-    print("Segfaultin'\n");
+    print("Segfault: %d: %r\n", sig);
     longjmp(exec_jmp, 2);
 }
 
@@ -31,11 +30,18 @@
 static void
 sigquit(int sig)
 {
-    print("Sigquittin'\n");
+    print("Sigquittin': %r\n");
     longjmp(exec_jmp, 1);
 }
 
 static void
+sigbus(int sig)
+{
+    print("Bussin': %r\n");
+    longjmp(exec_jmp, 2);
+}
+
+static void
 sigsys(int sig)
 {
     print("We here!!! sig %d\n", sig);
@@ -226,13 +232,12 @@
         } ehdr;
         char buf[256];
     } u;
-
+    void (*_main)(int, char*[]);
     char line[256];
     char *progarg[32+1];
     char *file, *elem;
     void *base;
     Chan *tc;
-    Tos tos;
     ulong magic;
     uintptr t, b, entry, text, data, bss, align;
     int n, indir;
@@ -298,15 +303,18 @@
         cclose(tc);
     }
 
-    entry -= sizeof(u.ehdr);
-    text = beswal(u.ehdr.ex.text);
+    text -= UTZERO;
+    entry -= UTZERO;
 	data = beswal(u.ehdr.ex.data);
 	bss = beswal(u.ehdr.ex.bss);
 
     /* Set up text, data, and bss. OS dependent. */
-    base = osbuildmem(tc, text, data, bss, sizeof(u.ehdr));
+    base = osbuildmem(tc, text, data, bss, sizeof(u.ehdr), align);
     b = ((uintptr)base + align) & ~align;
 
+    /* Handle alignment, BSS setup, and memory protection. OS dependent. */
+    osprepmem(base, b, text, data, bss);
+
     poperror();
     cclose(tc);
 
@@ -315,23 +323,24 @@
     signal(SIGQUIT, sigquit);
     signal(SIGINT, sigquit);
     signal(SIGSYS, sigsys);
+    signal(SIGBUS, sigbus);
 
     switch(setjmp(exec_jmp)) {
     case 0:
-        tos.pid = getpid();
-        print("Base %ux, Entry %ux, Text %ux\n", b, entry, text);
-        start(b+entry, &tos, argc, argv);
+        print("Base %p, Aligned base %p, Entry offset %lx, Text %lx\n", base, (void*)b, entry, text);
+
+        _main = (void (*)(int, char*[]))(b+entry);
+        _main(argc, argv);
+
         longjmp(exec_jmp, 1);
         break;
     case 1:
-        print("Normal exit\n");
-        osclrmem((uintptr)base, text+data+bss);
-        return 0;
+        osclrmem((uintptr)b, text+data+bss);
+        break;
     case 2:
-        print("SIGSEGV!\n");
+        //error("Signal: %r");
         return -1;
     }
 
-    /* Can't happen */
-    return 1;
+    return 0;
 }
\ No newline at end of file
--- a/librc/Makefile
+++ /dev/null
@@ -1,30 +1,0 @@
-ROOT=..
-include ../Make.config
-LIB=librc.a
-
-OFILES=\
-	code.$O\
-	exec.$O\
-	getflags.$O\
-	glob.$O\
-	here.$O\
-	io.$O\
-	lex.$O\
-	pcmd.$O\
-	pfnc.$O\
-	simple.$O\
-	subr.$O\
-	trap.$O\
-	tree.$O\
-	var.$O\
-	havefork.$O\
-	drawcpu.$O\
-	y.tab.$O\
-
-default: $(LIB)
-$(LIB): $(OFILES)
-	$(AR) r $(LIB) $(OFILES)
-	$(RANLIB) $(LIB)
-
-%.$O: %.c
-	$(CC) $(CFLAGS) $*.c
\ No newline at end of file
--- a/librc/code.c
+++ /dev/null
@@ -1,547 +1,0 @@
-#include "rc.h"
-#include "io.h"
-#include "exec.h"
-#include "fns.h"
-#include "getflags.h"
-#define	c0	t->child[0]
-#define	c1	t->child[1]
-#define	c2	t->child[2]
-code *codebuf;
-static int codep, ncode, codeline;
-#define	emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
-#define	emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
-#define	emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
-
-void stuffdot(int);
-void outcode(tree*, int);
-void codeswitch(tree*, int);
-int iscase(tree*);
-code *codecopy(code*);
-void codefree(code*);
-
-int
-morecode(void)
-{
-	ncode+=ncode;
-	codebuf = (code *)erealloc((char *)codebuf, ncode*sizeof codebuf[0]);
-	return 0;
-}
-
-void
-stuffdot(int a)
-{
-	if(a<0 || codep<=a)
-		panic("Bad address %d in stuffdot", a);
-	codebuf[a].i = codep;
-}
-
-int
-compile(tree *t)
-{
-	ncode = 100;
-	codebuf = emalloc(ncode*sizeof codebuf[0]);
-	codep = 0;
-	codeline = 0;			/* force source */
-	emiti(0);			/* reference count */
-	emits(estrdup(lex->file));	/* source file name */
-	outcode(t, !lex->qflag && flag['e']!=0);
-	if(nerror){
-		free(codebuf);
-		return 0;
-	}
-	emitf(Xreturn);
-	emitf(0);
-	return 1;
-}
-
-/*
- * called on a tree where we expect eigther
- * a pattern or a string instead of a glob to
- * remove the GLOB chars from the strings
- * or set glob to 2 for pattern so Xglob
- * is not inserted when compiling the tree.
- */
-void
-noglobs(tree *t, int pattern)
-{
-Again:
-	if(t==0)
-		return;
-	if(t->type==WORD && t->glob){
-		if(pattern)
-			t->glob=2;
-		else{
-			deglob(t->str);
-			t->glob=0;
-		}
-	}
-	if(t->type==PAREN || t->type==WORDS || t->type=='^'){
-		t->glob=0;
-		noglobs(c1, pattern);
-		t = c0;
-		goto Again;
-	}
-}
-
-void
-outcode(tree *t, int eflag)
-{
-	void (*f)(void);
-	int p, q;
-	tree *tt;
-	if(t==0)
-		return;
-	if(t->type!=NOT && t->type!=';')
-		lex->iflast = 0;
-	if(t->line != codeline){
-		codeline = t->line;
-		if(codebuf && codep >= 2 && codebuf[codep-2].f == Xsrcline)
-			codebuf[codep-1].i = codeline;
-		else {
-			emitf(Xsrcline);
-			emiti(codeline);
-		}
-	}
-	switch(t->type){
-	default:
-		pfmt(err, "bad type %d in outcode\n", t->type);
-		break;
-	case '$':
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		emitf(Xdol);
-		break;
-	case '"':
-		emitf(Xmark);
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		emitf(Xdol);
-		emitf(Xqw);
-		emitf(Xpush);
-		break;
-	case SUB:
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		emitf(Xmark);
-		noglobs(c1, 0);
-		outcode(c1, eflag);
-		emitf(Xsub);
-		break;
-	case '&':
-		emitf(Xasync);
-		p = emiti(0);
-
-		/* undocumented? */
-		emitf(Xmark);
-		emitf(Xword);
-		emits(estrdup("/dev/null"));
-		emitf(Xread);
-		emiti(0);
-
-		/* insert rfork s for plan9 */
-		f = builtinfunc("rfork");
-		if(f){
-			emitf(Xmark);
-			emitf(Xword);
-			emits(estrdup("s"));
-			emitf(Xword);
-			emits(estrdup("rfork"));
-			emitf(f);
-		}
-
-		codeline = 0;	/* force source */
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
-		break;
-	case ';':
-		outcode(c0, eflag);
-		outcode(c1, eflag);
-		break;
-	case '^':
-		emitf(Xmark);
-		outcode(c1, eflag);
-		emitf(Xmark);
-		outcode(c0, eflag);
-		emitf(Xconc);
-		break;
-	case '`':
-		emitf(Xmark);
-		if(c0){
-			noglobs(c0, 0);
-			outcode(c0, 0);
-		} else {
-			emitf(Xmark);
-			emitf(Xword);
-			emits(estrdup("ifs"));
-			emitf(Xdol);
-		}
-		emitf(Xqw);
-		emitf(Xbackq);
-		p = emiti(0);
-		codeline = 0;	/* force source */
-		outcode(c1, 0);
-		emitf(Xexit);
-		stuffdot(p);
-		break;
-	case ANDAND:
-		outcode(c0, 0);
-		emitf(Xtrue);
-		p = emiti(0);
-		outcode(c1, eflag);
-		stuffdot(p);
-		break;
-	case ARGLIST:
-		outcode(c1, eflag);
-		outcode(c0, eflag);
-		break;
-	case BANG:
-		outcode(c0, eflag);
-		emitf(Xbang);
-		break;
-	case PCMD:
-	case BRACE:
-		outcode(c0, eflag);
-		break;
-	case COUNT:
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		emitf(Xcount);
-		break;
-	case FN:
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		if(c1){
-			emitf(Xfn);
-			p = emiti(0);
-			emits(fnstr(c1));
-			codeline = 0;	/* force source */
-			outcode(c1, eflag);
-			emitf(Xreturn);
-			stuffdot(p);
-		}
-		else
-			emitf(Xdelfn);
-		break;
-	case IF:
-		outcode(c0, 0);
-		emitf(Xif);
-		p = emiti(0);
-		outcode(c1, eflag);
-		emitf(Xwastrue);
-		stuffdot(p);
-		break;
-	case NOT:
-		if(!lex->iflast)
-			yyerror("`if not' does not follow `if(...)'");
-		emitf(Xifnot);
-		p = emiti(0);
-		outcode(c0, eflag);
-		stuffdot(p);
-		break;
-	case OROR:
-		outcode(c0, 0);
-		emitf(Xfalse);
-		p = emiti(0);
-		outcode(c1, eflag);
-		stuffdot(p);
-		break;
-	case PAREN:
-		outcode(c0, eflag);
-		break;
-	case SIMPLE:
-		emitf(Xmark);
-		outcode(c0, eflag);
-		emitf(Xsimple);
-		if(eflag)
-			emitf(Xeflag);
-		break;
-	case SUBSHELL:
-		emitf(Xsubshell);
-		p = emiti(0);
-		codeline = 0;	/* force source */
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
-		if(eflag)
-			emitf(Xeflag);
-		break;
-	case SWITCH:
-		codeswitch(t, eflag);
-		break;
-	case TWIDDLE:
-		emitf(Xmark);
-		noglobs(c1, 1);
-		outcode(c1, eflag);
-		emitf(Xmark);
-		outcode(c0, eflag);
-		emitf(Xqw);
-		emitf(Xmatch);
-		if(eflag)
-			emitf(Xeflag);
-		break;
-	case WHILE:
-		q = codep;
-		outcode(c0, 0);
-		if(q==codep)
-			emitf(Xsettrue);	/* empty condition == while(true) */
-		emitf(Xtrue);
-		p = emiti(0);
-		outcode(c1, eflag);
-		emitf(Xjump);
-		emiti(q);
-		stuffdot(p);
-		break;
-	case WORDS:
-		outcode(c1, eflag);
-		outcode(c0, eflag);
-		break;
-	case FOR:
-		emitf(Xmark);
-		if(c1){
-			outcode(c1, eflag);
-		}
-		else{
-			emitf(Xmark);
-			emitf(Xword);
-			emits(estrdup("*"));
-			emitf(Xdol);
-		}
-		emitf(Xmark);		/* dummy value for Xlocal */
-		emitf(Xmark);
-		noglobs(c0, 0);
-		outcode(c0, eflag);
-		emitf(Xlocal);
-		p = emitf(Xfor);
-		q = emiti(0);
-		outcode(c2, eflag);
-		emitf(Xjump);
-		emiti(p);
-		stuffdot(q);
-		emitf(Xunlocal);
-		break;
-	case WORD:
-		emitf(Xword);
-		emits(t->str);
-		t->str=0;	/* passed ownership */
-		break;
-	case DUP:
-		if(t->rtype==DUPFD){
-			emitf(Xdup);
-			emiti(t->fd0);
-			emiti(t->fd1);
-		}
-		else{
-			emitf(Xclose);
-			emiti(t->fd0);
-		}
-		outcode(c1, eflag);
-		emitf(Xpopredir);
-		break;
-	case PIPEFD:
-		emitf(Xpipefd);
-		emiti(t->rtype);
-		p = emiti(0);
-		codeline = 0;	/* force source */
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
-		break;
-	case REDIR:
-		if(t->rtype!=HERE){
-			emitf(Xmark);
-			outcode(c0, eflag);
-		}
-		switch(t->rtype){
-		case APPEND:
-			emitf(Xappend);
-			break;
-		case WRITE:
-			emitf(Xwrite);
-			break;
-		case READ:
-			emitf(Xread);
-			break;
-		case RDWR:
-			emitf(Xrdwr);
-			break;
-		case HERE:
-			emitf(c0->quoted?Xhereq:Xhere);
-			emits(t->str);
-			t->str=0;	/* passed ownership */
-			break;
-		}
-		emiti(t->fd0);
-		outcode(c1, eflag);
-		emitf(Xpopredir);
-		break;
-	case '=':
-		tt = t;
-		for(;t && t->type=='=';t = c2);
-		if(t){					/* var=value cmd */
-			for(t = tt;t->type=='=';t = c2){
-				emitf(Xmark);
-				outcode(c1, eflag);
-				emitf(Xmark);
-				noglobs(c0, 0);
-				outcode(c0, eflag);
-				emitf(Xlocal);		/* push var for cmd */
-			}
-			outcode(t, eflag);		/* gen. code for cmd */
-			for(t = tt; t->type == '='; t = c2)
-				emitf(Xunlocal);	/* pop var */
-		}
-		else{					/* var=value */
-			for(t = tt;t;t = c2){
-				emitf(Xmark);
-				outcode(c1, eflag);
-				emitf(Xmark);
-				noglobs(c0, 0);
-				outcode(c0, eflag);
-				emitf(Xassign);	/* set var permanently */
-			}
-		}
-		t = tt;	/* so tests below will work */
-		break;
-	case PIPE:
-		emitf(Xpipe);
-		emiti(t->fd0);
-		emiti(t->fd1);
-		p = emiti(0);
-		q = emiti(0);
-		codeline = 0;	/* force source */
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
-		codeline = 0;	/* force source */
-		outcode(c1, eflag);
-		emitf(Xreturn);
-		stuffdot(q);
-		emitf(Xpipewait);
-		break;
-	}
-	if(t->glob==1)
-		emitf(Xglob);
-	if(t->type!=NOT && t->type!=';')
-		lex->iflast = t->type==IF;
-	else if(c0)
-		lex->iflast = c0->type==IF;
-}
-/*
- * switch code looks like this:
- *	Xmark
- *	(get switch value)
- *	Xjump	1f
- * out:	Xjump	leave
- * 1:	Xmark
- *	(get case values)
- *	Xcase	1f
- *	(commands)
- *	Xjump	out
- * 1:	Xmark
- *	(get case values)
- *	Xcase	1f
- *	(commands)
- *	Xjump	out
- * 1:
- * leave:
- *	Xpopm
- */
-
-void
-codeswitch(tree *t, int eflag)
-{
-	int leave;		/* patch jump address to leave switch */
-	int out;		/* jump here to leave switch */
-	int nextcase;	/* patch jump address to next case */
-	tree *tt;
-	if(c1->child[0]==0
-	|| c1->child[0]->type!=';'
-	|| !iscase(c1->child[0]->child[0])){
-		yyerror("case missing in switch");
-		return;
-	}
-	emitf(Xmark);
-	outcode(c0, eflag);
-	emitf(Xqw);
-	emitf(Xjump);
-	nextcase = emiti(0);
-	out = emitf(Xjump);
-	leave = emiti(0);
-	stuffdot(nextcase);
-	t = c1->child[0];
-	while(t->type==';'){
-		tt = c1;
-		emitf(Xmark);
-		for(t = c0->child[0];t->type==ARGLIST;t = c0) {
-			noglobs(c1, 1);
-			outcode(c1, eflag);
-		}
-		emitf(Xcase);
-		nextcase = emiti(0);
-		t = tt;
-		for(;;){
-			if(t->type==';'){
-				if(iscase(c0)) break;
-				outcode(c0, eflag);
-				t = c1;
-			}
-			else{
-				if(!iscase(t)) outcode(t, eflag);
-				break;
-			}
-		}
-		emitf(Xjump);
-		emiti(out);
-		stuffdot(nextcase);
-	}
-	stuffdot(leave);
-	emitf(Xpopm);
-}
-
-int
-iscase(tree *t)
-{
-	if(t->type!=SIMPLE)
-		return 0;
-	do t = c0; while(t->type==ARGLIST);
-	return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
-}
-
-code*
-codecopy(code *cp)
-{
-	cp[0].i++;
-	return cp;
-}
-
-void
-codefree(code *cp)
-{
-	code *p;
-	if(--cp[0].i!=0)
-		return;
-	for(p = cp+2;p->f;p++){
-		if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
-		|| p->f==Xrdwr
-		|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
-		|| p->f==Xfor || p->f==Xjump
-		|| p->f==Xsrcline
-		|| p->f==Xsubshell || p->f==Xtrue) p++;
-		else if(p->f==Xdup || p->f==Xpipefd) p+=2;
-		else if(p->f==Xpipe) p+=4;
-		else if(p->f==Xhere || p->f==Xhereq) free(p[1].s), p+=2;
-		else if(p->f==Xword) free((++p)->s);
-		else if(p->f==Xfn){
-			free(p[2].s);
-			p+=2;
-		}
-	}
-	free(cp[1].s);
-	free(cp);
-}
\ No newline at end of file
--- a/librc/drawcpu.c
+++ /dev/null
@@ -1,444 +1,0 @@
-/*
- * Drawcpu versions of system-specific functions
- *	By convention, exported routines herein have names beginning with an
- *	upper case letter.
- */
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-#include "getflags.h"
-
-static void execfinit(void);
-
-builtin Builtin[] = {
-	"cd",		execcd,
-	"whatis",	execwhatis, 
-	"eval",		execeval,
-	"exec",		execexec,	/* but with popword first */
-	"exit",		execexit,
-	"shift",	execshift,
-	"wait",		execwait,
-	".",		execdot,
-	"flag",		execflag,
-	"finit",	execfinit,
-	"rfork",	execrfork,
-    "mount",    execmount,
-    "bind",     execbind,
-    "ls",       execls, // TODO: Remove
-    "cat",      execcat, // TODO: Remove
-	0
-};
-
-char Rcmain[]="/usr/local/lib/rcmain";
-char Fdprefix[]="/fd/";
-
-char *Signame[] = {
-	"sigexit",	"sighup",	"sigint",	"sigquit",
-	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
-	0
-};
-
-static char *syssigname[] = {
-	"exit",		/* can't happen */
-	"hangup",
-	"interrupt",
-	"quit",		/* can't happen */
-	"alarm",
-	"kill",
-	"sys: fp: ",
-	"term",
-	0
-};
-
-/*
- * finit could be removed but is kept for
- * backwards compatibility, see: rcmain.plan9
- */
-static void
-execfinit(void)
-{
-	char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
-	int line = runq->line;
-	poplist();
-	execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
-	runq->lex->line = line;
-	runq->lex->qflag = 1;
-}
-
-char*
-Env(char *name, int fn)
-{
-	static char buf[128];
-
-	strcpy(buf, "/env/");
-	if(fn) strcat(buf, "fn#");
-	return strncat(buf, name, sizeof(buf)-1);
-}
-
-void
-Vinit(void)
-{
-	int dir, fd, i, n;
-	Dir *ent;
-
-	dir = Open(Env("", 0), 0);
-	if(dir<0){
-		pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		return;
-	}
-	for(;;){
-		ent = 0;
-		n = dirread(dir, &ent);
-		if(n <= 0)
-			break;
-		for(i = 0; i<n; i++){
-			if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0)
-				continue;
-			if((fd = Open(Env(ent[i].name, 0), 0))>=0){
-				io *f = openiofd(fd);
-				word *w = 0, **wp = &w;
-				char *s;
-				while((s = rstr(f, "")) != 0){
-					*wp = Newword(s, (word*)0);
-					wp = &(*wp)->next;
-				}
-				closeio(f);
-				setvar(ent[i].name, w);
-				vlook(ent[i].name)->changed = 0;
-			}
-		}
-		free(ent);
-	}
-	Close(dir);
-}
-
-char*
-Errstr(void)
-{
-	static char err[ERRMAX];
-	rerrstr(err, sizeof err);
-	return err;
-}
-
-int
-Waitfor(int pid)
-{
-	thread *p;
-	Waitmsg *w;
-
-	if(pid >= 0 && !havewaitpid(pid))
-		return 0;
-
-	while((w = wait()) != nil){
-		delwaitpid(w->pid);
-		if(w->pid==pid){
-			setstatus(w->msg);
-			free(w);
-			return 0;
-		}
-		for(p = runq->ret;p;p = p->ret)
-			if(p->pid==w->pid){
-				p->pid=-1;
-				p->status = estrdup(w->msg);
-				break;
-			}
-		free(w);
-	}
-
-	if(strcmp(Errstr(), "interrupted")==0) return -1;
-	return 0;
-}
-
-static void
-addenv(var *v)
-{
-	word *w;
-	int fd;
-	io *f;
-
-	if(v->changed){
-		v->changed = 0;
-		if((fd = Creat(Env(v->name, 0)))<0)
-			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		else{
-			f = openiofd(fd);
-			for(w = v->val;w;w = w->next){
-				pstr(f, w->word);
-				pchr(f, '\0');
-			}
-			flushio(f);
-			closeio(f);
-		}
-	}
-	if(v->fnchanged){
-		v->fnchanged = 0;
-		if((fd = Creat(Env(v->name, 1)))<0)
-			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		else{
-			f = openiofd(fd);
-			if(v->fn)
-				pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
-			flushio(f);
-			closeio(f);
-		}
-	}
-}
-
-static void
-updenvlocal(var *v)
-{
-	if(v){
-		updenvlocal(v->next);
-		addenv(v);
-	}
-}
-
-void
-Updenv(void)
-{
-	var *v, **h;
-	for(h = gvar;h!=&gvar[NVAR];h++)
-		for(v=*h;v;v = v->next)
-			addenv(v);
-	if(runq)
-		updenvlocal(runq->local);
-	if(err)
-		flushio(err);
-}
-
-void
-Exec(char **argv)
-{
-	int argc = 0;
-
-	while(argv[argc]) argc++;
-	exec(argc, argv);
-}
-
-int
-Fork(void)
-{
-	Updenv();
-	// TODO: Tie into the rendezvous so we can block 'em in rfork
-	return rfork(RFPROC|RFFDG/*|RFREND*/);
-}
-
-
-typedef struct readdir readdir;
-struct readdir {
-	Dir	*dbuf;
-	int	i, n;
-	int	fd;
-};
-
-void*
-Opendir(char *name)
-{
-	readdir *rd;
-	int fd;
-	if((fd = Open(name, 0))<0)
-		return 0;
-	rd = new(readdir);
-	rd->dbuf = 0;
-	rd->i = 0;
-	rd->n = 0;
-	rd->fd = fd;
-	return rd;
-}
-
-static int
-trimdirs(Dir *d, int nd)
-{
-	int r, w;
-
-	for(r=w=0; r<nd; r++)
-		if(d[r].mode&DMDIR)
-			d[w++] = d[r];
-	return w;
-}
-
-char*
-Readdir(void *arg, int onlydirs)
-{
-	readdir *rd = arg;
-	int n;
-Again:
-	if(rd->i>=rd->n){	/* read */
-		free(rd->dbuf);
-		rd->dbuf = 0;
-		n = dirread(rd->fd, &rd->dbuf);
-		if(n>0){
-			if(onlydirs){
-				n = trimdirs(rd->dbuf, n);
-				if(n == 0)
-					goto Again;
-			}	
-			rd->n = n;
-		}else
-			rd->n = 0;
-		rd->i = 0;
-	}
-	if(rd->i>=rd->n)
-		return 0;
-	return rd->dbuf[rd->i++].name;
-}
-
-void
-Closedir(void *arg)
-{
-	readdir *rd = arg;
-	Close(rd->fd);
-	free(rd->dbuf);
-	free(rd);
-}
-
-static int interrupted = 0;
-
-static void
-notifyf(void* _, char *s)
-{
-	int i;
-
-	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
-		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
-		goto Out;
-	}
-	noted(NDFLT);
-	return;
-Out:
-	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
-		trap[i]++;
-		ntrap++;
-	}
-	noted(NCONT);
-}
-
-void
-Trapinit(void)
-{
-	notify(notifyf);
-}
-
-long
-Write(int fd, void *buf, long cnt)
-{
-	return write(fd, buf, cnt);
-}
-
-long
-Read(int fd, void *buf, long cnt)
-{
-	return read(fd, buf, cnt);
-}
-
-long
-Seek(int fd, long cnt, long whence)
-{
-	return seek(fd, cnt, whence);
-}
-
-int
-Executable(char *file)
-{
-	Dir *statbuf;
-	int ret;
-
-	statbuf = dirstat(file);
-	if(statbuf == nil)
-		return 0;
-	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
-	free(statbuf);
-	return ret;
-}
-
-int
-Open(char *file, int mode)
-{
-	int fd;
-	static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE};
-	fd = open(file, tab[mode&3]);
-	/* TODO: Remove the need for this */
-	if(fd != 0 && strcmp(file, "/fd/0") == 0)
-		fd = lfdfd(0);
-	if(fd != 1 && strcmp(file, "/fd/1") == 0)
-		fd = lfdfd(1);
-	return fd;
-}
-
-void
-Close(int fd)
-{
-	close(fd);
-}
-
-int
-Creat(char *file)
-{
-	return create(file, OWRITE, 0666L);
-}
-
-int
-Dup(int a, int b)
-{
-	return dup(a, b);
-}
-
-int
-Dup1(int a)
-{
-	return dup(a, -1);
-}
-
-void
-Exit(void)
-{
-	Updenv();
-	exits(truestatus()?"":getstatus());
-}
-
-void
-Noerror(void)
-{
-	interrupted = 0;
-}
-
-int
-Isatty(int fd)
-{
-	return isatty(fd);
-}
-
-void
-Abort(void)
-{
-	abort();
-}
-
-static int newwdir;
-
-int
-Chdir(char *dir)
-{
-	newwdir = 1;
-	return chdir(dir);
-}
-
-void
-Prompt(char *s)
-{
-	pstr(err, s);
-	flushio(err);
-
-	if(newwdir){
-		char dir[4096];
-		int fd;
-		/* TODO: We should have this in our stack, test after */
-		if((fd=Creat("/dev/wdir"))>=0){
-			getwd(dir, sizeof(dir));
-			Write(fd, dir, strlen(dir));
-			Close(fd);
-		}
-		newwdir = 0;
-	}
-}
\ No newline at end of file
--- a/librc/exec.c
+++ /dev/null
@@ -1,1171 +1,0 @@
-#include "rc.h"
-#include "getflags.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-#include "drawcpu.h"
-
-#include <errno.h>
-
-char *argv0="rc";
-io *err;
-int mypid;
-thread *runq;
-
-/*
- * Start executing the given code at the given pc with the given redirection
- */
-void
-startexec(code *c, int pc, var *local, redir *redir)
-{
-	thread *p = new(thread);
-	p->code = codecopy(c);
-	p->line = 0;
-	p->pc = pc;
-	p->argv = 0;
-	p->redir = p->startredir = redir;
-	p->lex = 0;
-	p->local = local;
-	p->iflag = 0;
-	p->pid = 0;
-	p->status = 0;
-	p->ret = runq;
-	runq = p;
-}
-
-void
-startfunc(var *func, word *starval, var *local, redir *redir)
-{
-	startexec(func->fn, func->pc, local, redir);
-	runq->local = newvar("*", runq->local);
-	runq->local->val = starval;
-	runq->local->changed = 1;
-}
-
-static void
-popthread(void)
-{
-	thread *p = runq;
-	while(p->argv) poplist();
-	while(p->local && (p->ret==0 || p->local!=p->ret->local))
-		Xunlocal();
-	runq = p->ret;
-	if(p->lex) freelexer(p->lex);
-	codefree(p->code);
-	free(p->status);
-	free(p);
-}
-
-word*
-Newword(char *s, word *next)
-{
-	word *p=new(word);
-	p->word = s;
-	p->next = next;
-	return p;
-}
-word*
-newword(char *s, word *next)
-{
-	return Newword(estrdup(s), next);
-}
-word*
-Pushword(char *s)
-{
-	word *p;
-	if(s==0)
-		panic("null pushword", 0);
-	if(runq->argv==0)
-		panic("pushword but no argv!", 0);
-	p = Newword(s, runq->argv->words);
-	runq->argv->words = p;
-	return p;
-}
-word*
-pushword(char *s)
-{
-	return Pushword(estrdup(s));
-}
-char*
-Freeword(word *p)
-{
-	char *s = p->word;
-	free(p);
-	return s;
-}
-void
-freewords(word *w)
-{
-	word *p;
-	while((p = w)!=0){
-		w = w->next;
-		free(Freeword(p));
-	}
-}
-char*
-Popword(void)
-{
-	word *p;
-	if(runq->argv==0)
-		panic("popword but no argv!", 0);
-	p = runq->argv->words;
-	if(p==0)
-		panic("popword but no word!", 0);
-	runq->argv->words = p->next;
-	return Freeword(p);
-}
-void
-popword(void)
-{
-	free(Popword());
-}
-
-void
-pushlist(void)
-{
-	list *p = new(list);
-	p->words = 0;
-	p->next = runq->argv;
-	runq->argv = p;
-}
-word*
-Poplist(void)
-{
-	word *w;
-	list *p = runq->argv;
-	if(p==0)
-		panic("poplist but no argv", 0);
-	w = p->words;
-	runq->argv = p->next;
-	free(p);
-	return w;
-}
-void
-poplist(void)
-{
-	freewords(Poplist());
-}
-
-int
-count(word *w)
-{
-	int n;
-	for(n = 0;w;n++) w = w->next;
-	return n;
-}
-
-void
-pushredir(int type, int from, int to)
-{
-	redir *rp = new(redir);
-	rp->type = type;
-	rp->from = from;
-	rp->to = to;
-	rp->next = runq->redir;
-	runq->redir = rp;
-}
-
-static void
-dontclose(int fd)
-{
-	redir *rp;
-
-	if(fd<0)
-		return;
-	for(rp = runq->redir; rp != runq->startredir; rp = rp->next){
-		if(rp->type == RCLOSE && rp->from == fd){
-			rp->type = 0;
-			break;
-		}
-	}
-}
-
-/*
- * we are about to start a new thread that should exit on
- * return, so the current stack is not needed anymore.
- * free all the threads and lexers, but preserve the
- * redirections and anything referenced by local.
- */
-void
-turfstack(var *local)
-{
-	while(local){
-		thread *p;
-
-		for(p = runq; p && p->local == local; p = p->ret)
-			p->local = local->next;
-		local = local->next;
-	}
-	while(runq) {
-		if(runq->lex) dontclose(runq->lex->input->fd);
-		popthread();
-	}
-}
-
-void
-shuffleredir(void)
-{
-	redir **rr, *rp;
-
-	rp = runq->redir;
-	if(rp==0)
-		return;
-	runq->redir = rp->next;
-	rp->next = runq->startredir;
-	for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))
-		;
-	*rr = rp;
-}
-
-/*
- * get command line flags, initialize keywords & traps.
- * get values from environment.
- * set $pid, $cflag, $*
- * fabricate bootstrap code and start it (*=(argv);. -bq /usr/lib/rcmain $*)
- * start interpreting code
- */
-void
-rc(int argc, char **argv, int efd)
-{
-	code bootstrap[20];
-	char num[12];
-	char *rcmain=Rcmain;
-
-	int i;
-	argv0 = argv[0];
-	argc = getflags(argc, argv, "srdiIlxebpvVc:1m:1[command]", 1);
-	if(argc==-1)
-		usage("[file [arg ...]]");
-	if(argv[0][0]=='-')
-		flag['l'] = flagset;
-	if(flag['I'])
-		flag['i'] = 0;
-	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
-	if(flag['m']) rcmain = flag['m'][0];
-	err = openiofd(efd);
-
-	kinit();
-	Trapinit();
-	Vinit();
-	inttoascii(num, mypid = getpid());
-	setvar("pid", newword(num, (word *)0));
-	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
-				:(word *)0);
-	setvar("rcname", newword(argv[0], (word *)0));
-	// TODO: Move the rcmain to a straight up bootstrap instead
-	bootstrap[0].i = 1;
-	bootstrap[1].s="*bootstrap*";
-	bootstrap[2].f = Xmark;
-	bootstrap[3].f = Xword;
-	bootstrap[4].s="*";
-	bootstrap[5].f = Xassign;
-	bootstrap[6].f = Xmark;
-	bootstrap[7].f = Xmark;
-	bootstrap[8].f = Xword;
-	bootstrap[9].s="*";
-	bootstrap[10].f = Xdol;
-	bootstrap[11].f = Xword;
-	bootstrap[12].s = rcmain;
-	bootstrap[13].f = Xword;
-	bootstrap[14].s="-bq";
-	bootstrap[15].f = Xword;
-	bootstrap[16].s=".";
-	bootstrap[17].f = Xsimple;
-	bootstrap[18].f = Xexit;
-	bootstrap[19].f = 0;
-	startexec(bootstrap, 2, (var*)0, (redir*)0);
-	/* prime bootstrap argv */
-	pushlist();
-	for(i = argc-1;i!=0;--i) pushword(argv[i]);
-	for(;;){
-		if(flag['r'])
-			pfnc(err, runq);
-		(*runq->code[runq->pc++].f)();
-		if(ntrap)
-			dotrap();
-	}
-}
-
-/*
- * Opcode routines
- * Arguments on stack (...)
- * Arguments in line [...]
- * Code in line with jump around {...}
- *
- * Xappend(file)[fd]			open file to append
- * Xassign(name, val)			assign val to name
- * Xasync{... Xexit}			make thread for {}, no wait
- * Xbackq(split){... Xreturn}		make thread for {}, push stdout
- * Xbang				complement condition
- * Xcase(pat, value){...}		exec code on match, leave (value) on
- * 					stack
- * Xclose[i]				close file descriptor
- * Xconc(left, right)			concatenate, push results
- * Xcount(name)				push var count
- * Xdelfn(name)				delete function definition
- * Xdol(name)				get variable value
- * Xdup[i j]				dup file descriptor
- * Xexit				rc exits with status
- * Xfalse{...}				execute {} if false
- * Xfn(name){... Xreturn}		define function
- * Xfor(var, list){... Xreturn}		for loop
- * Xglob(list)				glob a list of words inplace
- * Xjump[addr]				goto
- * Xlocal(name, val)			create local variable, assign value
- * Xmark				mark stack
- * Xmatch(pat, str)			match pattern, set status
- * Xpipe[i j]{... Xreturn}{... Xreturn}	construct a pipe between 2 new threads,
- * 					wait for both
- * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
- * 					depending on type), push /dev/fd/??
- * Xpopm(value)				pop value from stack
- * Xpush(words)				push words down a list
- * Xqw(words)				quote words inplace
- * Xrdwr(file)[fd]			open file for reading and writing
- * Xread(file)[fd]			open file to read
- * Xreturn				kill thread
- * Xsimple(args)			run command and wait
- * Xsrcline[line]			set current source line number
- * Xsubshell{... Xexit}			execute {} in a subshell and wait
- * Xtrue{...}				execute {} if true
- * Xunlocal				delete local variable
- * Xword[string]			push string
- * Xwrite(file)[fd]			open file to write
- */
-
-void
-Xappend(void)
-{
-	char *file;
-	int fd;
-
-	switch(count(runq->argv->words)){
-	default:
-		Xerror1(">> requires singleton");
-		return;
-	case 0:
-		Xerror1(">> requires file");
-		return;
-	case 1:
-		break;
-	}
-	file = runq->argv->words->word;
-	if((fd = Open(file, 1))<0 && (fd = Creat(file))<0){
-		Xerror3(">> can't open", file, Errstr());
-		return;
-	}
-	Seek(fd, 0L, 2);
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-	poplist();
-}
-
-void
-Xsettrue(void)
-{
-	setstatus("");
-}
-
-void
-Xbang(void)
-{
-	setstatus(truestatus()?"false":"");
-}
-
-void
-Xclose(void)
-{
-	pushredir(RCLOSE, runq->code[runq->pc++].i, 0);
-}
-
-void
-Xdup(void)
-{
-	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
-	runq->pc+=2;
-}
-
-void
-Xeflag(void)
-{
-	if(!truestatus()) Xexit();
-}
-
-void
-Xexit(void)
-{
-	static int beenhere = 0;
-
-	if(getpid()==mypid && !beenhere){
-		var *trapreq = vlook("sigexit");
-		word *starval = vlook("*")->val;
-		if(trapreq->fn){
-			beenhere = 1;
-			--runq->pc;
-			startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0);
-			return;
-		}
-	}
-	Exit();
-}
-
-void
-Xfalse(void)
-{
-	if(truestatus()) runq->pc = runq->code[runq->pc].i;
-	else runq->pc++;
-}
-int ifnot;		/* dynamic if not flag */
-
-void
-Xifnot(void)
-{
-	if(ifnot)
-		runq->pc++;
-	else
-		runq->pc = runq->code[runq->pc].i;
-}
-
-void
-Xjump(void)
-{
-	runq->pc = runq->code[runq->pc].i;
-}
-
-void
-Xmark(void)
-{
-	pushlist();
-}
-
-void
-Xpopm(void)
-{
-	poplist();
-}
-
-void
-Xpush(void)
-{
-	word *t, *h = Poplist();
-	for(t = h; t->next; t = t->next)
-		;
-	t->next = runq->argv->words;
-	runq->argv->words = h;
-}
-
-static int
-herefile(char *tmp)
-{
-	char *s = tmp+strlen(tmp)-1;
-	static int ser;
-	int fd, i;
-
-	i = ser++;
-	while(*s == 'Y'){
-		*s-- = (i%26) + 'A';
-		i = i/26;
-	}
-	i = getpid();
-	while(*s == 'X'){
-		*s-- = (i%10) + '0';
-		i = i/10;
-	}
-	s++;
-	for(i='a'; i<'z'; i++){
-		if(access(tmp, 0)!=0 && (fd = Creat(tmp))>=0)
-			return fd;
-		*s = i;
-	}
-	return -1;
-}
-
-void
-Xhere(void)
-{
-	char file[]="/tmp/hereXXXXXXXXXXYY";
-	int fd;
-	io *io;
-
-	if((fd = herefile(file))<0){
-		Xerror3("<< can't get temp file", file, Errstr());
-		return;
-	}
-	io = openiofd(fd);
-	psubst(io, (unsigned char*)runq->code[runq->pc++].s);
-	flushio(io);
-	closeio(io);
-
-	/* open for reading and unlink */
-	if((fd = Open(file, 3))<0){
-		Xerror3("<< can't open", file, Errstr());
-		return;
-	}
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-}
-
-void
-Xhereq(void)
-{
-	char file[]="/tmp/hereXXXXXXXXXXYY", *body;
-	int fd;
-
-	if((fd = herefile(file))<0){
-		Xerror3("<< can't get temp file", file, Errstr());
-		return;
-	}
-	body = runq->code[runq->pc++].s;
-	Write(fd, body, strlen(body));
-	Close(fd);
-
-	/* open for reading and unlink */
-	if((fd = Open(file, 3))<0){
-		Xerror3("<< can't open", file, Errstr());
-		return;
-	}
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-}
-
-void
-Xread(void)
-{
-	char *file;
-	int fd;
-
-	switch(count(runq->argv->words)){
-	default:
-		Xerror1("< requires singleton");
-		return;
-	case 0:
-		Xerror1("< requires file");
-		return;
-	case 1:
-		break;
-	}
-	file = runq->argv->words->word;
-	if((fd = Open(file, 0))<0){
-		Xerror3("< can't open", file, Errstr());
-		return;
-	}
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-	poplist();
-}
-
-void
-Xrdwr(void)
-{
-	char *file;
-	int fd;
-
-	switch(count(runq->argv->words)){
-	default:
-		Xerror1("<> requires singleton");
-		return;
-	case 0:
-		Xerror1("<> requires file");
-		return;
-	case 1:
-		break;
-	}
-	file = runq->argv->words->word;
-	if((fd = Open(file, 2))<0){
-		Xerror3("<> can't open", file, Errstr());
-		return;
-	}
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-	poplist();
-}
-
-void
-Xpopredir(void)
-{
-	redir *rp = runq->redir;
-
-	if(rp==0)
-		panic("Xpopredir null!", 0);
-	runq->redir = rp->next;
-	if(rp->type==ROPEN)
-		Close(rp->from);
-	free(rp);
-}
-
-void
-Xreturn(void)
-{
-	while(runq->redir!=runq->startredir)
-		Xpopredir();
-	popthread();
-	if(runq==0)
-		Exit();
-}
-
-void
-Xtrue(void)
-{
-	if(truestatus()) runq->pc++;
-	else runq->pc = runq->code[runq->pc].i;
-}
-
-void
-Xif(void)
-{
-	ifnot = 1;
-	if(truestatus()) runq->pc++;
-	else runq->pc = runq->code[runq->pc].i;
-}
-
-void
-Xwastrue(void)
-{
-	ifnot = 0;
-}
-
-void
-Xword(void)
-{
-	pushword(runq->code[runq->pc++].s);
-}
-
-void
-Xwrite(void)
-{
-	char *file;
-	int fd;
-
-	switch(count(runq->argv->words)){
-	default:
-		Xerror1("> requires singleton");
-		return;
-	case 0:
-		Xerror1("> requires file");
-		return;
-	case 1:
-		break;
-	}
-	file = runq->argv->words->word;
-	if((fd = Creat(file))<0){
-		Xerror3("> can't create", file, Errstr());
-		return;
-	}
-	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
-	poplist();
-}
-
-void
-Xmatch(void)
-{
-	word *p;
-	char *s;
-
-	setstatus("no match");
-	s = runq->argv->words->word;
-	for(p = runq->argv->next->words;p;p = p->next)
-		if(match(s, p->word, '\0')){
-			setstatus("");
-			break;
-		}
-	poplist();
-	poplist();
-}
-
-void
-Xcase(void)
-{
-	word *p;
-	char *s;
-	int ok = 0;
-
-	s = runq->argv->next->words->word;
-	for(p = runq->argv->words;p;p = p->next){
-		if(match(s, p->word, '\0')){
-			ok = 1;
-			break;
-		}
-	}
-	if(ok)
-		runq->pc++;
-	else
-		runq->pc = runq->code[runq->pc].i;
-	poplist();
-}
-
-static word*
-conclist(word *lp, word *rp, word *tail)
-{
-	word *v, *p, **end;
-	int ln, rn;
-
-	for(end = &v;;){
-		ln = strlen(lp->word), rn = strlen(rp->word);
-		p = Newword(emalloc(ln+rn+1), (word *)0);
-		memmove(p->word, lp->word, ln);
-		memmove(p->word+ln, rp->word, rn+1);
-		*end = p, end = &p->next;
-		if(lp->next == 0 && rp->next == 0)
-			break;
-		if(lp->next) lp = lp->next;
-		if(rp->next) rp = rp->next;
-	}
-	*end = tail;
-	return v;
-}
-
-void
-Xconc(void)
-{
-	word *lp = runq->argv->words;
-	word *rp = runq->argv->next->words;
-	word *vp = runq->argv->next->next->words;
-	int lc = count(lp), rc = count(rp);
-	if(lc!=0 || rc!=0){
-		if(lc==0 || rc==0){
-			Xerror1("null list in concatenation");
-			return;
-		}
-		if(lc!=1 && rc!=1 && lc!=rc){
-			Xerror1("mismatched list lengths in concatenation");
-			return;
-		}
-		vp = conclist(lp, rp, vp);
-	}
-	poplist();
-	poplist();
-	runq->argv->words = vp;
-}
-
-void
-Xassign(void)
-{
-	var *v;
-
-	if(count(runq->argv->words)!=1){
-		Xerror1("= variable name not singleton!");
-		return;
-	}
-	v = vlook(runq->argv->words->word);
-	poplist();
-	freewords(v->val);
-	v->val = Poplist();
-	v->changed = 1;
-}
-
-/*
- * copy arglist a, adding the copy to the front of tail
- */
-word*
-copywords(word *a, word *tail)
-{
-	word *v = 0, **end;
-
-	for(end=&v;a;a = a->next,end=&(*end)->next)
-		*end = newword(a->word, 0);
-	*end = tail;
-	return v;
-}
-
-void
-Xdol(void)
-{
-	word *a, *star;
-	char *s, *t;
-	int n;
-
-	if(count(runq->argv->words)!=1){
-		Xerror1("$ variable name not singleton!");
-		return;
-	}
-	n = 0;
-	s = runq->argv->words->word;
-	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
-	a = runq->argv->next->words;
-	if(n==0 || *t)
-		a = copywords(vlook(s)->val, a);
-	else{
-		star = vlook("*")->val;
-		if(star && 1<=n && n<=count(star)){
-			while(--n) star = star->next;
-			a = newword(star->word, a);
-		}
-	}
-	poplist();
-	runq->argv->words = a;
-}
-
-void
-Xqw(void)
-{
-	char *s, *d;
-	word *a, *p;
-	int n;
-
-	a = runq->argv->words;
-	if(a==0){
-		pushword("");
-		return;
-	}
-	if(a->next==0)
-		return;
-	n=0;
-	for(p=a;p;p=p->next)
-		n+=1+strlen(p->word);
-	s = emalloc(n+1);
-	d = s;
-	d += strlen(strcpy(d, a->word));
-	for(p=a->next;p;p=p->next){
-		*d++=' ';
-		d += strlen(strcpy(d, p->word));
-	}
-	free(a->word);
-	freewords(a->next);
-	a->word = s;
-	a->next = 0;
-}
-
-static word*
-copynwords(word *a, word *tail, int n)
-{
-	word *v, **end;
-	
-	v = 0;
-	end = &v;
-	while(n-- > 0){
-		*end = newword(a->word, 0);
-		end = &(*end)->next;
-		a = a->next;
-	}
-	*end = tail;
-	return v;
-}
-
-static word*
-subwords(word *val, int len, word *sub, word *a)
-{
-	int n, m;
-	char *s;
-
-	if(sub==0)
-		return a;
-	a = subwords(val, len, sub->next, a);
-	s = sub->word;
-	m = 0;
-	n = 0;
-	while('0'<=*s && *s<='9')
-		n = n*10+ *s++ -'0';
-	if(*s == '-'){
-		if(*++s == 0)
-			m = len - n;
-		else{
-			while('0'<=*s && *s<='9')
-				m = m*10+ *s++ -'0';
-			m -= n;
-		}
-	}
-	if(n<1 || n>len || m<0)
-		return a;
-	if(n+m>len)
-		m = len-n;
-	while(--n > 0)
-		val = val->next;
-	return copynwords(val, a, m+1);
-}
-
-void
-Xsub(void)
-{
-	word *a, *v;
-	char *s;
-
-	if(count(runq->argv->next->words)!=1){
-		Xerror1("$() variable name not singleton!");
-		return;
-	}
-	s = runq->argv->next->words->word;
-	a = runq->argv->next->next->words;
-	v = vlook(s)->val;
-	a = subwords(v, count(v), runq->argv->words, a);
-	poplist();
-	poplist();
-	runq->argv->words = a;
-}
-
-void
-Xcount(void)
-{
-	word *a;
-	char *s, *t, num[12];
-	int n;
-
-	if(count(runq->argv->words)!=1){
-		Xerror1("$# variable name not singleton!");
-		return;
-	}
-	n = 0;
-	s = runq->argv->words->word;
-	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
-	if(n==0 || *t){
-		a = vlook(s)->val;
-		inttoascii(num, count(a));
-	}
-	else{
-		a = vlook("*")->val;
-		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
-	}
-	poplist();
-	pushword(num);
-}
-
-void
-Xlocal(void)
-{
-	if(count(runq->argv->words)!=1){
-		Xerror1("local variable name must be singleton");
-		return;
-	}
-	runq->local = newvar(runq->argv->words->word, runq->local);
-	poplist();
-	runq->local->val = Poplist();
-	runq->local->changed = 1;
-}
-
-void
-Xunlocal(void)
-{
-	var *hid, *v = runq->local;
-	if(v==0)
-		panic("Xunlocal: no locals!", 0);
-	runq->local = v->next;
-	hid = vlook(v->name);
-	hid->changed = 1;
-	freevar(v);
-}
-
-void
-Xfn(void)
-{
-	var *v;
-	word *a;
-	int pc = runq->pc;
-	runq->pc = runq->code[pc].i;
-	for(a = runq->argv->words;a;a = a->next){
-		v = gvlook(a->word);
-		if(v->fn)
-			codefree(v->fn);
-		v->fn = codecopy(runq->code);
-		v->pc = pc+2;
-		v->fnchanged = 1;
-	}
-	poplist();
-}
-
-void
-Xdelfn(void)
-{
-	var *v;
-	word *a;
-	for(a = runq->argv->words;a;a = a->next){
-		v = gvlook(a->word);
-		if(v->fn)
-			codefree(v->fn);
-		v->fn = 0;
-		v->fnchanged = 1;
-	}
-	poplist();
-}
-
-static char*
-concstatus(char *s, char *t)
-{
-	int n, m;
-
-	if(t==0) return s;
-	if(s==0) return t;
-	n = strlen(s);
-	m = strlen(t);
-	s = erealloc(s, n+m+2);
-	if(n > 0) s[n++]='|';
-	memmove(s+n, t, m+1);
-	free(t);
-	return s;
-}
-
-void
-Xpipewait(void)
-{
-	char *old = Getstatus();
-	if(runq->pid==-1){
-		Setstatus(concstatus(runq->status, old));
-		runq->status=0;
-	}else{
-		while(Waitfor(runq->pid) < 0)
-			;
-		runq->pid=-1;
-		Setstatus(concstatus(Getstatus(), old));
-	}
-}
-
-static char *promptstr;
-
-void
-Xrdcmds(void)
-{
-	thread *p = runq;
-
-	if(flag['s'] && !truestatus())
-		pfmt(err, "status=%v\n", vlook("status")->val);
-	flushio(err);
-
-	lex = p->lex;
-	if(p->iflag){
-		word *prompt = vlook("prompt")->val;
-		if(prompt)
-			promptstr = prompt->word;
-		else
-			promptstr="% ";
-	}
-	Noerror();
-	nerror = 0;
-	if(yyparse()){
-		if(p->iflag && (!lex->eof || errno==EINTR)){
-			if(errno==EINTR){
-				pchr(err, '\n');
-				lex->eof = 0;
-			}
-			--p->pc;	/* go back for next command */
-		}
-	}
-	else{
-		if(lex->eof){
-			dontclose(lex->input->fd);
-			freelexer(lex);
-			p->lex = 0;
-		} else
-			--p->pc;	/* re-execute Xrdcmds after codebuf runs */
-		startexec(codebuf, 2, p->local, p->redir);
-	}
-	lex = 0;
-	freenodes();
-}
-
-void
-pprompt(void)
-{
-	word *prompt;
-
-	if(!runq->iflag)
-		return;
-
-	Prompt(promptstr);
-	doprompt = 0;
-
-	prompt = vlook("prompt")->val;
-	if(prompt && prompt->next)
-		promptstr = prompt->next->word;
-	else
-		promptstr = "\t";
-}
-
-char*
-srcfile(thread *p)
-{
-	return p->code[1].s;
-}
-
-void
-Xerror1(char *s)
-{
-	setstatus("error");
-	pfln(err, srcfile(runq), runq->line);
-	pfmt(err, ": %s\n", s);
-	flushio(err);
-	while(!runq->iflag) Xreturn();
-}
-void
-Xerror2(char *s, char *e)
-{
-	setstatus(e);
-	pfln(err, srcfile(runq), runq->line);
-	pfmt(err, ": %s: %s\n", s, e);
-	flushio(err);
-	while(!runq->iflag) Xreturn();
-}
-void
-Xerror3(char *s, char *m, char *e)
-{
-	setstatus(e);
-	pfln(err, srcfile(runq), runq->line);
-	pfmt(err, ": %s: %s: %s\n", s, m, e);
-	flushio(err);
-	while(!runq->iflag) Xreturn();
-}
-
-void
-Setstatus(char *s)
-{
-	setvar("status", Newword(s?s:estrdup(""), (word *)0));
-}
-void
-setstatus(char *s)
-{
-	Setstatus(estrdup(s));
-}
-char*
-Getstatus(void)
-{
-	var *status = vlook("status");
-	word *val = status->val;
-	if(val==0) return 0;
-	status->val=0;
-	status->changed=1;
-	freewords(val->next);
-	return Freeword(val);
-}
-char*
-getstatus(void)
-{
-	var *status = vlook("status");
-	return status->val?status->val->word:"";
-}
-
-int
-truestatus(void)
-{
-	char *s;
-	for(s = getstatus();*s;s++)
-		if(*s!='|' && *s!='0')
-			return 0;
-	return 1;
-}
-
-void
-Xfor(void)
-{
-	word *a = runq->argv->words;
-	if(a==0){
-		poplist();
-		runq->pc = runq->code[runq->pc].i;
-	}
-	else{
-		runq->argv->words = a->next;
-		a->next = 0;
-		freewords(runq->local->val);
-		runq->local->val = a;
-		runq->local->changed = 1;
-		runq->pc++;
-	}
-}
-
-void
-Xglob(void)
-{
-	word *a, *x;
-
-	for(a = runq->argv->words; a; a = x){
-		x = a->next;
-		globword(a);
-	}
-}
-
-void
-Xsrcline(void)
-{
-	runq->line = runq->code[runq->pc++].i;
-}
\ No newline at end of file
--- a/librc/exec.h
+++ /dev/null
@@ -1,88 +1,0 @@
-/*
- * Definitions used in the interpreter
- */
-extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
-extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void);
-extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
-extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void), Xhere(void), Xhereq(void);
-extern void Xrdwr(void), Xsrcline(void);
-extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
-extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
-extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void), Xpush(void);
-extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
-extern void Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
-extern void Xerror1(char*);
-extern void Xerror2(char*,char*);
-extern void Xerror3(char*,char*,char*);
-
-/*
- * word lists are in correct order,
- * i.e. word0->word1->word2->word3->0
- */
-struct word{
-	char *word;
-	word *next;
-};
-struct list{
-	word *words;
-	list *next;
-};
-word *newword(char *, word *), *copywords(word *, word *);
-
-struct redir{
-	int type;			/* what to do */
-	int from, to;			/* what to do it to */
-	redir *next;			/* what else to do (reverse order) */
-};
-
-/*
- * redir types
- */
-#define	ROPEN	1			/* dup2(from, to); close(from); */
-#define	RDUP	2			/* dup2(from, to); */
-#define	RCLOSE	3			/* close(from); */
-void	shuffleredir(void);
-
-struct thread{
-	code *code;			/* code for this thread */
-	int pc;				/* code[pc] is the next instruction */
-	int line;			/* source code line for Xsrcline */
-	list *argv;			/* argument stack */
-	redir *redir;			/* redirection stack */
-	redir *startredir;		/* redir inheritance point */
-	var *local;			/* list of local variables */
-	lexer *lex;			/* lexer for Xrdcmds */
-	int iflag;			/* interactive? */
-	int pid;			/* process for Xpipewait to wait for */
-	char *status;			/* status for Xpipewait */
-	thread *ret;			/* who continues when this finishes */
-};
-extern thread *runq;
-void turfstack(var*);
-
-extern int mypid;
-extern int ntrap;			/* number of outstanding traps */
-extern int trap[NSIG];			/* number of outstanding traps per type */
-
-code *codecopy(code*);
-extern code *codebuf;			/* compiler output */
-extern int ifnot;
-
-struct builtin{
-	char *name;
-	void (*fnc)(void);
-};
-extern void (*builtinfunc(char *name))(void);
-
-void execcd(void), execwhatis(void), execeval(void), execexec(void);
-int execforkexec(void);
-void execexit(void), execshift(void), execrfork(void);
-void execwait(void), execdot(void), execflag(void);
-void execfunc(var*), execcmds(io*, char*, var*, redir*);
-void execmount(void), execbind(void);
-void execls(void), execcat(void); // TODO: Remove
-
-void startfunc(var*, word*, var*, redir*);
-
-char *srcfile(thread*);
-char *getstatus(void);
\ No newline at end of file
--- a/librc/fns.h
+++ /dev/null
@@ -1,69 +1,0 @@
-void	Abort(void);
-int	Chdir(char*);
-void	Close(int);
-void	Closedir(void*);
-int	Creat(char*);
-int	Dup(int, int);
-int	Dup1(int);
-int	Executable(char*);
-void	Exec(char**);
-void	Exit(void);
-char*	Errstr(void);
-char*	Freeword(word*);
-int	Fork(void);
-char*	Getstatus(void);
-int	Isatty(int);
-word*	Newword(char*,word*);
-void	Noerror(void);
-int	Open(char*, int);
-void*	Opendir(char*);
-word*	Poplist(void);
-char*	Popword(void);
-word*	Pushword(char*);
-long	Read(int, void*, long);
-char*	Readdir(void*, int);
-long	Seek(int, long, long);
-void	Setstatus(char*);
-void	Trapinit(void);
-void	Updenv(void);
-void	Vinit(void);
-int	Waitfor(int);
-long	Write(int, void*, long);
-void	addwaitpid(int);
-void	clearwaitpids(void);
-void	codefree(code*);
-int	compile(tree*);
-int	count(word*);
-char*	deglob(char*);
-void	delwaitpid(int);
-void	dotrap(void);
-void	freenodes(void);
-void	freewords(word*);
-void	globword(word*);
-int	havewaitpid(int);
-int	idchr(int);
-void	inttoascii(char*, int);
-void	kinit(void);
-int	mapfd(int);
-int	match(char*, char*, int);
-char*	makercpath(char*, char*);
-void	pfln(io*, char*, int);
-void	poplist(void);
-void	popword(void);
-void	pprompt(void);
-void	Prompt(char*);
-void	psubst(io*, unsigned char*);
-void	pushlist(void);
-void	pushredir(int, int, int);
-word*	pushword(char*);
-void	readhere(io*);
-void	heredoc(tree*);
-void	setstatus(char*);
-void	skipnl(void);
-void    startexec(code*, int, var*, redir*);
-int	truestatus(void);
-void	usage(char*);
-int	wordchr(int);
-void	yyerror(char*);
-int	yylex(void);
-int	yyparse(void);
\ No newline at end of file
--- a/librc/getflags.c
+++ /dev/null
@@ -1,234 +1,0 @@
-#include "rc.h"
-#include "getflags.h"
-#include "fns.h"
-char *flagset[] = {"<flag>"};
-char **flag[NFLAG];
-char *cmdname;
-static char *flagarg="";
-static void reverse(char**, char**);
-static int scanflag(int, char*);
-static void errn(char*, int);
-static void errs(char*);
-static void errc(int);
-static int reason;
-#define	RESET	1
-#define	FEWARGS	2
-#define	FLAGSYN	3
-#define	BADFLAG	4
-static int badflag;
-
-int
-getflags(int argc, char *argv[], char *flags, int stop)
-{
-	char *s;
-	int i, j, c, count;
-	flagarg = flags;
-	if(cmdname==0)
-		cmdname = argv[0];
-
-	i = 1;
-	while(i!=argc){
-		if(argv[i][0] != '-' || argv[i][1] == '\0'){
-			if(stop)		/* always true in rc */
-				return argc;
-			i++;
-			continue;
-		}
-		s = argv[i]+1;
-		while(*s){
-			c=*s++;
-			count = scanflag(c, flags);
-			if(count==-1)
-				return -1;
-			if(flag[c]){ reason = RESET; badflag = c; return -1; }
-			if(count==0){
-				flag[c] = flagset;
-				if(*s=='\0'){
-					for(j = i+1;j<=argc;j++)
-						argv[j-1] = argv[j];
-					--argc;
-				}
-			}
-			else{
-				if(*s=='\0'){
-					for(j = i+1;j<=argc;j++)
-						argv[j-1] = argv[j];
-					--argc;
-					s = argv[i];
-				}
-				if(argc-i<count){
-					reason = FEWARGS;
-					badflag = c;
-					return -1;
-				}
-				reverse(argv+i, argv+argc);
-				reverse(argv+i, argv+argc-count);
-				reverse(argv+argc-count+1, argv+argc);
-				argc-=count;
-				flag[c] = argv+argc+1;
-				flag[c][0] = s;
-				s="";
-			}
-		}
-	}
-	return argc;
-}
-
-static void
-reverse(char **p, char **q)
-{
-	char *t;
-	for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
-}
-
-static int
-scanflag(int c, char *f)
-{
-	int fc, count;
-	if(0<=c && c<NFLAG)
-		while(*f){
-			if(*f==' '){
-				f++;
-				continue;
-			}
-			fc=*f++;
-			if(*f==':'){
-				f++;
-				if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; }
-				count = 0;
-				while('0'<=*f && *f<='9') count = count*10+*f++-'0';
-			}
-			else
-				count = 0;
-			if(*f=='['){
-				do{
-					f++;
-					if(*f=='\0'){ reason = FLAGSYN; return -1; }
-				}while(*f!=']');
-				f++;
-			}
-			if(c==fc)
-				return count;
-		}
-	reason = BADFLAG;
-	badflag = c;
-	return -1;
-}
-
-void
-usage(char *tail)
-{
-	char *s, *t, c;
-	int count, nflag = 0;
-	switch(reason){
-	case RESET:
-		errs("Flag -");
-		errc(badflag);
-		errs(": set twice\n");
-		break;
-	case FEWARGS:
-		errs("Flag -");
-		errc(badflag);
-		errs(": too few arguments\n");
-		break;
-	case FLAGSYN:
-		errs("Bad argument to getflags!\n");
-		break;
-	case BADFLAG:
-		errs("Illegal flag -");
-		errc(badflag);
-		errc('\n');
-		break;
-	}
-	errs("Usage: ");
-	errs(cmdname);
-	for(s = flagarg;*s;){
-		c=*s;
-		if(*s++==' ')
-			continue;
-		if(*s==':'){
-			s++;
-			count = 0;
-			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
-		}
-		else count = 0;
-		if(count==0){
-			if(nflag==0)
-				errs(" [-");
-			nflag++;
-			errc(c);
-		}
-		if(*s=='['){
-			s++;
-			while(*s!=']' && *s!='\0') s++;
-			if(*s==']')
-				s++;
-		}
-	}
-	if(nflag)
-		errs("]");
-	for(s = flagarg;*s;){
-		c=*s;
-		if(*s++==' ')
-			continue;
-		if(*s==':'){
-			s++;
-			count = 0;
-			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
-		}
-		else count = 0;
-		if(count!=0){
-			errs(" [-");
-			errc(c);
-			if(*s=='['){
-				s++;
-				t = s;
-				while(*s!=']' && *s!='\0') s++;
-				errs(" ");
-				errn(t, s-t);
-				if(*s==']')
-					s++;
-			}
-			else
-				while(count--) errs(" arg");
-			errs("]");
-		}
-		else if(*s=='['){
-			s++;
-			while(*s!=']' && *s!='\0') s++;
-			if(*s==']')
-				s++;
-		}
-	}
-	if(tail){
-		errs(" ");
-		errs(tail);
-	}
-	errs("\n");
-	setstatus("bad flags");
-	Exit();
-}
-
-static void
-errn(char *s, int count)
-{
-	while(count){ errc(*s++); --count; }
-}
-
-static void
-errs(char *s)
-{
-	while(*s) errc(*s++);
-}
-#define	NBUF	80
-static char buf[NBUF], *bufp = buf;
-
-static void
-errc(int c)
-{
-	*bufp++=c;
-	if(bufp==&buf[NBUF] || c=='\n'){
-		Write(2, buf, bufp-buf);
-		bufp = buf;
-	}
-}
\ No newline at end of file
--- a/librc/getflags.h
+++ /dev/null
@@ -1,7 +1,0 @@
-#define	NFLAG	128
-
-extern char **flag[NFLAG];
-extern char *cmdname;
-extern char *flagset[];
-
-int getflags(int, char*[], char*, int);
\ No newline at end of file
--- a/librc/glob.c
+++ /dev/null
@@ -1,259 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "fns.h"
-
-/*
- * delete all the GLOB marks from s, in place
- */
-char*
-deglob(char *s)
-{
-	char *r = strchr(s, GLOB);
-	if(r){
-		char *w = r++;
-		do{
-			if(*r==GLOB)
-				r++;
-			*w++=*r;
-		}while(*r++);
-	}
-	return s;
-}
-
-static int
-globcmp(const void *s, const void *t)
-{
-	return strcmp(*(char**)s, *(char**)t);
-}
-
-static void
-globsort(word *left, word *right)
-{
-	char **list;
-	word *a;
-	int n = 0;
-	for(a = left;a!=right;a = a->next) n++;
-	list = (char **)emalloc(n*sizeof(char *));
-	for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
-	qsort((void *)list, n, sizeof(void *), globcmp);
-	for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
-	free(list);
-}
-
-/*
- * Does the string s match the pattern p
- * . and .. are only matched by patterns starting with .
- * * matches any sequence of characters
- * ? matches any single character
- * [...] matches the enclosed list of characters
- */
-
-static int
-matchfn(char *s, char *p)
-{
-	if(s[0]=='.' && ((s[1]=='\0' || s[1]=='.') && s[2]=='\0') && p[0]!='.')
-		return 0;
-	return match(s, p, '/');
-}
-
-static void
-pappend(char **pdir, char *name)
-{
-	char *path = makercpath(*pdir, name);
-	free(*pdir);
-	*pdir = path;
-}
-
-static word*
-globdir(word *list, char *pattern, char *name)
-{
-	char *slash, *glob, *entry;
-	void *dir;
-
-#ifdef Plan9
-	/* append slashes, Readdir() already filtered directories */
-	while(*pattern=='/'){
-		pappend(&name, "/");
-		pattern++;
-	}
-#endif
-	if(*pattern=='\0')
-		return Newword(name, list);
-
-	/* scan the pattern looking for a component with a metacharacter in it */
-	glob=strchr(pattern, GLOB);
-
-	/* If we ran out of pattern, append the name if accessible */
-	if(glob==0){
-		pappend(&name, pattern);
-		if(access(name, 0)==0)
-			return Newword(name, list);
-		goto out;
-	}
-
-	*glob='\0';
-	slash=strrchr(pattern, '/');
-	if(slash){
-		*slash='\0';
-		pappend(&name, pattern);
-		*slash='/';
-		pattern=slash+1;
-	}
-	*glob=GLOB;
-
-	/* read the directory and recur for any entry that matches */
-	dir = Opendir(name[0]?name:".");
-	if(dir==0)
-		goto out;
-	slash=strchr(glob, '/');
-	while((entry=Readdir(dir, slash!=0)) != 0){
-		if(matchfn(entry, pattern))
-			list = globdir(list, slash?slash:"", makercpath(name, entry));
-	}
-	Closedir(dir);
-out:
-	free(name);
-	return list;
-}
-
-/*
- * Subsitute a word with its glob in place.
- */
-void
-globword(word *w)
-{
-	word *left, *right;
-
-	if(w==0 || strchr(w->word, GLOB)==0)
-		return;
-	right = w->next;
-	left = globdir(right, w->word, estrdup(""));
-	if(left == right) {
-		deglob(w->word);
-	} else {
-		free(w->word);
-		globsort(left, right);
-		w->next = left->next;
-		w->word = Freeword(left);
-	}
-}
-
-/*
- * Return a pointer to the next utf code in the string,
- * not jumping past nuls in broken utf codes!
- */
-static char*
-nextutf(char *p)
-{
-	int i, n, c = *p;
-
-	if(onebyte(c))
-		return p+1;
-	if(twobyte(c))
-		n = 2;
-	else if(threebyte(c))
-		n = 3;
-	else
-		n = 4;
-	for(i = 1; i < n; i++)
-		if(!xbyte(p[i]))
-			break;
-	return p+i;
-}
-
-/*
- * Convert the utf code at *p to a unicode value
- */
-static int
-unicode(char *p)
-{
-	int c = *p;
-
-	if(onebyte(c))
-		return c&0xFF;
-	if(twobyte(c)){
-		if(xbyte(p[1]))
-			return ((c&0x1F)<<6) | (p[1]&0x3F);
-	} else if(threebyte(c)){
-		if(xbyte(p[1]) && xbyte(p[2]))
-			return ((c&0x0F)<<12) | ((p[1]&0x3F)<<6) | (p[2]&0x3F);
-	} else if(fourbyte(c)){
-		if(xbyte(p[1]) && xbyte(p[2]) && xbyte(p[3]))
-			return ((c&0x07)<<18) | ((p[1]&0x3F)<<12) | ((p[2]&0x3F)<<6) | (p[3]&0x3F);
-	}
-	return -1;
-}
-
-/*
- * Do p and q point at equal utf codes
- */
-static int
-equtf(char *p, char *q)
-{
-	if(*p!=*q)
- 		return 0;
-	return unicode(p) == unicode(q);
-}
-
-int
-match(char *s, char *p, int stop)
-{
-	int compl, hit, lo, hi, t, c;
-
-	for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){
-		if(*p!=GLOB){
-			if(!equtf(p, s)) return 0;
-		}
-		else switch(*++p){
-		case GLOB:
-			if(*s!=GLOB)
-				return 0;
-			break;
-		case '*':
-			for(;;){
-				if(match(s, nextutf(p), stop)) return 1;
-				if(!*s)
-					break;
-				s = nextutf(s);
-			}
-			return 0;
-		case '?':
-			if(*s=='\0')
-				return 0;
-			break;
-		case '[':
-			if(*s=='\0')
-				return 0;
-			c = unicode(s);
-			p++;
-			compl=*p=='~';
-			if(compl)
-				p++;
-			hit = 0;
-			while(*p!=']'){
-				if(*p=='\0')
-					return 0;		/* syntax error */
-				lo = unicode(p);
-				p = nextutf(p);
-				if(*p!='-')
-					hi = lo;
-				else{
-					p++;
-					if(*p=='\0')
-						return 0;	/* syntax error */
-					hi = unicode(p);
-					p = nextutf(p);
-					if(hi<lo){ t = lo; lo = hi; hi = t; }
-				}
-				if(lo<=c && c<=hi)
-					hit = 1;
-			}
-			if(compl)
-				hit=!hit;
-			if(!hit)
-				return 0;
-			break;
-		}
-	}
-	return *s=='\0';
-}
\ No newline at end of file
--- a/librc/havefork.c
+++ /dev/null
@@ -1,240 +1,0 @@
-#include "rc.h"
-#include "getflags.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-
-static int *waitpids;
-static int nwaitpids;
-
-void
-addwaitpid(int pid)
-{
-	waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
-	waitpids[nwaitpids++] = pid;
-}
-
-void
-delwaitpid(int pid)
-{
-	int r, w;
-	
-	for(r=w=0; r<nwaitpids; r++)
-		if(waitpids[r] != pid)
-			waitpids[w++] = waitpids[r];
-	nwaitpids = w;
-}
-
-void
-clearwaitpids(void)
-{
-	nwaitpids = 0;
-}
-
-int
-havewaitpid(int pid)
-{
-	int i;
-
-	for(i=0; i<nwaitpids; i++)
-		if(waitpids[i] == pid)
-			return 1;
-	return 0;
-}
-
-void
-Xasync(void)
-{
-	int pid;
-	char npid[10];
-
-	switch(pid = Fork()){
-	case -1:
-		Xerror2("try again", Errstr());
-		break;
-	case 0:
-		clearwaitpids();
-		startexec(runq->code, runq->pc+1, runq->local, runq->redir);
-		runq->ret = 0;
-		break;
-	default:
-		addwaitpid(pid);
-		runq->pc = runq->code[runq->pc].i;
-		inttoascii(npid, pid);
-		setvar("apid", newword(npid, (word *)0));
-		break;
-	}
-}
-
-void
-Xpipe(void)
-{
-	thread *p = runq;
-	int pid, pc = p->pc;
-	int lfd = p->code[pc++].i;
-	int rfd = p->code[pc++].i;
-	int pfd[2];
-
-	if(pipe(pfd)<0){
-		Xerror2("can't get pipe", Errstr());
-		return;
-	}
-	switch(pid = Fork()){
-	case -1:
-		Xerror2("try again", Errstr());
-		break;
-	case 0:
-		clearwaitpids();
-		Close(pfd[PRD]);
-		startexec(p->code, pc+2, runq->local, runq->redir);
-		runq->ret = 0;
-		pushredir(ROPEN, pfd[PWR], lfd);
-		break;
-	default:
-		addwaitpid(pid);
-		Close(pfd[PWR]);
-		startexec(p->code, p->code[pc].i, runq->local, runq->redir);
-		pushredir(ROPEN, pfd[PRD], rfd);
-		p->pc = p->code[pc+1].i;
-		p->pid = pid;
-		break;
-	}
-}
-
-/*
- * Who should wait for the exit from the fork?
- */
-
-void
-Xbackq(void)
-{
-	int pid, pfd[2];
-	char *s, *split;
-	word *end, **link;
-	io *f;
-
-	if(pipe(pfd)<0){
-		Xerror2("can't make pipe", Errstr());
-		return;
-	}
-	switch(pid = Fork()){
-	case -1:
-		Xerror2("try again", Errstr());
-		Close(pfd[PRD]);
-		Close(pfd[PWR]);
-		return;
-	case 0:
-		clearwaitpids();
-		Close(pfd[PRD]);
-		startexec(runq->code, runq->pc+1, runq->local, runq->redir);
-		pushredir(ROPEN, pfd[PWR], 1);
-		return;
-	default:
-		addwaitpid(pid);
-		Close(pfd[PWR]);
-
-		split = Popword();
-		poplist();
-		f = openiofd(pfd[PRD]);
-		end = runq->argv->words;
-		link = &runq->argv->words;
-		while((s = rstr(f, split)) != 0){
-			*link = Newword(s, (word*)0);
-			link = &(*link)->next;
-		}
-		*link = end;
-		closeio(f);
-		free(split);
-
-		Waitfor(pid);
-
-		runq->pc = runq->code[runq->pc].i;
-		return;
-	}
-}
-
-void
-Xpipefd(void)
-{
-	thread *p = runq;
-	int pid, pc = p->pc;
-	char name[40];
-	int pfd[2];
-	int sidefd, mainfd;
-
-	if(pipe(pfd)<0){
-		Xerror2("can't get pipe", Errstr());
-		return;
-	}
-	if(p->code[pc].i==READ){
-		sidefd = pfd[PWR];
-		mainfd = pfd[PRD];
-	}
-	else{
-		sidefd = pfd[PRD];
-		mainfd = pfd[PWR];
-	}
-	switch(pid = Fork()){
-	case -1:
-		Xerror2("try again", Errstr());
-		break;
-	case 0:
-		clearwaitpids();
-		Close(mainfd);
-		startexec(p->code, pc+2, runq->local, runq->redir);
-		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
-		runq->ret = 0;
-		break;
-	default:
-		addwaitpid(pid);
-		Close(sidefd);
-		pushredir(ROPEN, mainfd, mainfd);
-		shuffleredir();	/* shuffle redir to bottom of stack for Xpopredir() */
-		strcpy(name, Fdprefix);
-		inttoascii(name+strlen(name), mainfd);
-		pushword(name);
-		p->pc = p->code[pc+1].i;
-		break;
-	}
-}
-
-void
-Xsubshell(void)
-{
-	int pid;
-
-	switch(pid = Fork()){
-	case -1:
-		Xerror2("try again", Errstr());
-		break;
-	case 0:
-		clearwaitpids();
-		startexec(runq->code, runq->pc+1, runq->local, runq->redir);
-		runq->ret = 0;
-		break;
-	default:
-		addwaitpid(pid);
-		while(Waitfor(pid) < 0)
-			;
-		runq->pc = runq->code[runq->pc].i;
-		break;
-	}
-}
-
-int
-execforkexec(void)
-{
-	int pid;
-
-	switch(pid = Fork()){
-	case -1:
-		return -1;
-	case 0:
-		clearwaitpids();
-		pushword("exec");
-		execexec();
-		/* does not return */
-	}
-	addwaitpid(pid);
-	return pid;
-}
\ No newline at end of file
--- a/librc/here.c
+++ /dev/null
@@ -1,137 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-
-void psubst(io*, unsigned char*);
-void pstrs(io*, word*);
-
-static char*
-readhere1(tree *tag, io *in)
-{
-	io *out;
-	char c, *m;
-
-	pprompt();
-	out = openiostr();
-	m = tag->str;
-	while((c = rchr(in)) != EOF){
-		if(c=='\0'){
-			yyerror("NUL bytes in here doc");
-			closeio(out);
-			return 0;
-		}
-		if(c=='\n'){
-			lex->line++;
-			if(m && *m=='\0'){
-				out->bufp -= m - tag->str;
-				*out->bufp='\0';
-				break;
-			}
-			pprompt();
-			m = tag->str;
-		} else if(m){
-			if(*m == c){
-				m++;
-			} else {
-				m = 0;
-			}
-		}
-		pchr(out, c);
-	}
-	doprompt = 1;
-	return closeiostr(out);
-}
-
-static tree *head, *tail;
-
-void
-heredoc(tree *redir)
-{
-	if(redir->child[0]->type!=WORD){
-		yyerror("Bad here tag");
-		return;
-	}
-	redir->child[2]=0;
-	if(head)
-		tail->child[2]=redir;
-	else
-		head=redir;
-	tail=redir;
-}
-
-void
-readhere(io *in)
-{
-	while(head){
-		tail=head->child[2];
-		head->child[2]=0;
-		head->str=readhere1(head->child[0], in);
-		head=tail;
-	}
-}
-
-void
-psubst(io *f, unsigned char *s)
-{
-	unsigned char *t, *u;
-	word *star;
-	int savec, n;
-
-	while(*s){
-		if(*s!='$'){
-			if(0xa0 <= *s && *s <= 0xf5){
-				pchr(f, *s++);
-				if(*s=='\0')
-					break;
-			}
-			else if(0xf6 <= *s && *s <= 0xf7){
-				pchr(f, *s++);
-				if(*s=='\0')
-					break;
-				pchr(f, *s++);
-				if(*s=='\0')
-					break;
-			}
-			pchr(f, *s++);
-		}
-		else{
-			t=++s;
-			if(*t=='$')
-				pchr(f, *t++);
-			else{
-				while(*t && idchr(*t)) t++;
-				savec=*t;
-				*t='\0';
-				n = 0;
-				for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
-				if(n && *u=='\0'){
-					star = vlook("*")->val;
-					if(star && 1<=n && n<=count(star)){
-						while(--n) star = star->next;
-						pstr(f, star->word);
-					}
-				}
-				else
-					pstrs(f, vlook((char *)s)->val);
-				*t = savec;
-				if(savec=='^')
-					t++;
-			}
-			s = t;
-		}
-	}
-}
-
-void
-pstrs(io *f, word *a)
-{
-	if(a){
-		while(a->next && a->next->word){
-			pstr(f, a->word);
-			pchr(f, ' ');
-			a = a->next;
-		}
-		pstr(f, a->word);
-	}
-}
\ No newline at end of file
--- a/librc/io.c
+++ /dev/null
@@ -1,302 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-
-enum {
-	NBUF = 8192,
-};
-
-void
-vpfmt(io *f, char *fmt, va_list ap)
-{
-	for(;*fmt;fmt++) {
-		if(*fmt!='%') {
-			pchr(f, *fmt);
-			continue;
-		}
-		if(*++fmt == '\0')		/* "blah%"? */
-			break;
-		switch(*fmt){
-		case 'c':
-			pchr(f, va_arg(ap, int));
-			break;
-		case 'd':
-			pdec(f, va_arg(ap, int));
-			break;
-		case 'o':
-			poct(f, va_arg(ap, unsigned));
-			break;
-		case 'p':
-			pptr(f, va_arg(ap, void*));
-			break;
-		case 'Q':
-			pquo(f, va_arg(ap, char *));
-			break;
-		case 'q':
-			pwrd(f, va_arg(ap, char *));
-			break;
-		case 's':
-			pstr(f, va_arg(ap, char *));
-			break;
-		case 't':
-			pcmd(f, va_arg(ap, tree *));
-			break;
-		case 'v':
-			pval(f, va_arg(ap, word *));
-			break;
-		default:
-			pchr(f, *fmt);
-			break;
-		}
-	}
-}
-
-void
-pfmt(io *f, char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	vpfmt(f, fmt, ap);
-	va_end(ap);
-}
-
-void
-pchr(io *b, int c)
-{
-	if(b->bufp>=b->ebuf)
-		flushio(b);
-	*b->bufp++=c;
-}
-
-int
-rchr(io *b)
-{
-	if(b->bufp>=b->ebuf)
-		return emptyiobuf(b);
-	return *b->bufp++;
-}
-
-char*
-rstr(io *b, char *stop)
-{
-	char *s, *p;
-	int l, m, n;
-
-	do {
-		l = rchr(b);
-		if(l == EOF)
-			return 0;
-	} while(l && strchr(stop, l));
-	b->bufp--;
-
-	s = 0;
-	l = 0;
-	for(;;){
-		p = (char*)b->bufp;
-		n = (char*)b->ebuf - p;
-		if(n > 0){
-			for(m = 0; m < n; m++){
-				if(strchr(stop, p[m])==0)
-					continue;
-
-				b->bufp += m+1;
-				if(m > 0 || s==0){
-					s = erealloc(s, l+m+1);
-					memmove(s+l, p, m);
-					l += m;
-				}
-				s[l]='\0';
-				return s;
-			}
-			s = erealloc(s, l+m+1);
-			memmove(s+l, p, m);
-			l += m;
-			b->bufp += m;
-		}
-		if(emptyiobuf(b) == EOF){
-			if(s) s[l]='\0';
-			return s;
-		}
-		b->bufp--;
-	}
-}
-
-void
-pquo(io *f, char *s)
-{
-	pchr(f, '\'');
-	for(;*s;s++){
-		if(*s=='\'')
-			pchr(f, *s);
-		pchr(f, *s);
-	}
-	pchr(f, '\'');
-}
-
-void
-pwrd(io *f, char *s)
-{
-	char *t;
-	for(t = s;*t;t++) if(*t >= 0 && (*t <= ' ' || strchr("`^#*[]=|\\?${}()'<>&;", *t))) break;
-	if(t==s || *t)
-		pquo(f, s);
-	else pstr(f, s);
-}
-
-void
-pptr(io *f, void *p)
-{
-	static char hex[] = "0123456789ABCDEF";
-	uvlong v;
-	int n;
-
-	v = (uvlong)p;
-	if(sizeof(v) == sizeof(p) && v>>32)
-		for(n = 60;n>=32;n-=4) pchr(f, hex[(v>>n)&0xF]);
-	for(n = 28;n>=0;n-=4) pchr(f, hex[(v>>n)&0xF]);
-}
-
-void
-pstr(io *f, char *s)
-{
-	if(s==0)
-		s="(null)";
-	while(*s) pchr(f, *s++);
-}
-
-void
-pdec(io *f, int n)
-{
-	if(n<0){
-		n=-n;
-		if(n>=0){
-			pchr(f, '-');
-			pdec(f, n);
-			return;
-		}
-		/* n is two's complement minimum integer */
-		n = 1-n;
-		pchr(f, '-');
-		pdec(f, n/10);
-		pchr(f, n%10+'1');
-		return;
-	}
-	if(n>9)
-		pdec(f, n/10);
-	pchr(f, n%10+'0');
-}
-
-void
-poct(io *f, unsigned n)
-{
-	if(n>7)
-		poct(f, n>>3);
-	pchr(f, (n&7)+'0');
-}
-
-void
-pval(io *f, word *a)
-{
-	if(a==0)
-		return;
-	while(a->next && a->next->word){
-		pwrd(f, (char *)a->word);
-		pchr(f, ' ');
-		a = a->next;
-	}
-	pwrd(f, (char *)a->word);
-}
-
-io*
-newio(unsigned char *buf, int len, int fd)
-{
-	io *f = new(io);
-	f->buf = buf;
-	f->bufp = buf;
-	f->ebuf = buf+len;
-	f->fd = fd;
-	return f;
-}
-
-/*
- * Open a string buffer for writing.
- */
-io*
-openiostr(void)
-{
-	unsigned char *buf = emalloc(100+1);
-	memset(buf, '\0', 100+1);
-	return newio(buf, 100, -1);
-}
-
-/*
- * Return the buf, free the io
- */
-char*
-closeiostr(io *f)
-{
-	void *buf = f->buf;
-	free(f);
-	return buf;
-}
-
-/*
- * Use a open file descriptor for reading.
- */
-io*
-openiofd(int fd)
-{
-	return newio(emalloc(NBUF), 0, fd);
-}
-
-/*
- * Open a corebuffer to read.  EOF occurs after reading len
- * characters from buf.
- */
-io*
-openiocore(void *buf, int len)
-{
-	return newio(buf, len, -1);
-}
-
-void
-flushio(io *f)
-{
-	int n;
-
-	if(f->fd<0){
-		n = f->ebuf - f->buf;
-		f->buf = erealloc(f->buf, n+n+1);
-		f->bufp = f->buf + n;
-		f->ebuf = f->bufp + n;
-		memset(f->bufp, '\0', n+1);
-	}
-	else{
-		n = f->bufp - f->buf;
-		if(n && Write(f->fd, f->buf, n) != n){
-			Write(2, "Write error\n", 12);
-			if(ntrap)
-				dotrap();
-		}
-		f->bufp = f->buf;
-		f->ebuf = f->buf+NBUF;
-	}
-}
-
-void
-closeio(io *f)
-{
-	if(f->fd>=0) Close(f->fd);
-	free(closeiostr(f));
-}
-
-int
-emptyiobuf(io *f)
-{
-	int n;
-	if(f->fd<0 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
-	f->bufp = f->buf;
-	f->ebuf = f->buf + n;
-	return *f->bufp++;
-}
\ No newline at end of file
--- a/librc/io.h
+++ /dev/null
@@ -1,28 +1,0 @@
-#define	EOF	(-1)
-
-struct io{
-	int	fd;
-	unsigned char *buf, *bufp, *ebuf;
-	io	*next;
-};
-
-io *openiofd(int), *openiostr(void), *openiocore(void*, int);
-void pchr(io*, int);
-int rchr(io*);
-char *rstr(io*, char*);
-char *closeiostr(io*);
-void closeio(io*);
-int emptyiobuf(io*);
-void flushio(io*);
-void pdec(io*, int);
-void poct(io*, unsigned);
-void pptr(io*, void*);
-void pquo(io*, char*);
-void pwrd(io*, char*);
-void pstr(io*, char*);
-void pcmd(io*, tree*);
-void pval(io*, word*);
-void pfun(io*, void(*)(void));
-void pfnc(io*, thread*);
-void pfmt(io*, char*, ...);
-void vpfmt(io*, char*, va_list);
\ No newline at end of file
--- a/librc/lex.c
+++ /dev/null
@@ -1,435 +1,0 @@
-#include "rc.h"
-#include "io.h"
-#include "getflags.h"
-#include "fns.h"
-
-lexer *lex;
-
-int doprompt = 1;
-int nerror;
-
-int
-wordchr(int c)
-{
-	return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
-}
-
-int
-idchr(int c)
-{
-	/*
-	 * Formerly:
-	 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
-	 *	|| c=='_' || c=='*';
-	 */
-	return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
-}
-
-lexer*
-newlexer(io *input, char *file)
-{
-	lexer *n = new(struct lexer);
-	n->input = input;
-	n->file = file;
-	n->line = 1;
-	n->eof = 0;
-	n->future = EOF;
-	n->peekc = '{';
-	n->epilog = "}\n";
-	n->lastc = 0;
-	n->inquote = 0;
-	n->incomm = 0;
-	n->lastword = 0;
-	n->lastdol = 0;
-	n->iflast = 0;
-	n->qflag = 0;
-	n->tok[0] = 0;
-	return n;
-}
-
-void
-freelexer(lexer *p)
-{
-	closeio(p->input);
-	free(p->file);
-	free(p);
-}
-
-/*
- * read a character from the input stream
- */	
-static int
-getnext(void)
-{
-	int c;
-
-	if(lex->peekc!=EOF){
-		c = lex->peekc;
-		lex->peekc = EOF;
-		return c;
-	}
-	if(lex->eof){
-epilog:
-		if(*lex->epilog)
-			return *lex->epilog++;
-		doprompt = 1;
-		return EOF;
-	}
-	if(doprompt)
-		pprompt();
-	c = rchr(lex->input);
-	if(c=='\\' && !lex->inquote){
-		c = rchr(lex->input);
-		if(c=='\n' && !lex->incomm){		/* don't continue a comment */
-			doprompt = 1;
-			c=' ';
-		}
-		else{
-			lex->peekc = c;
-			c='\\';
-		}
-	}
-	if(c==EOF){
-		lex->eof = 1;
-		goto epilog;
-	} else {
-		if(c=='\n')
-			doprompt = 1;
-		if((!lex->qflag && flag['v']!=0) || flag['V'])
-			pchr(err, c);
-	}
-	return c;
-}
-
-/*
- * Look ahead in the input stream
- */
-static int
-nextc(void)
-{
-	if(lex->future==EOF)
-		lex->future = getnext();
-	return lex->future;
-}
-
-/*
- * Consume the lookahead character.
- */
-static int
-advance(void)
-{
-	int c = nextc();
-	lex->lastc = lex->future;
-	lex->future = EOF;
-	if(c == '\n')
-		lex->line++;
-	return c;
-}
-
-static void
-skipwhite(void)
-{
-	int c;
-	for(;;){
-		c = nextc();
-		/* Why did this used to be  if(!inquote && c=='#') ?? */
-		if(c=='#'){
-			lex->incomm = 1;
-			for(;;){
-				c = nextc();
-				if(c=='\n' || c==EOF) {
-					lex->incomm = 0;
-					break;
-				}
-				advance();
-			}
-		}
-		if(c==' ' || c=='\t')
-			advance();
-		else return;
-	}
-}
-
-void
-skipnl(void)
-{
-	int c;
-	for(;;){
-		skipwhite();
-		c = nextc();
-		if(c!='\n')
-			return;
-		advance();
-	}
-}
-
-static int
-nextis(int c)
-{
-	if(nextc()==c){
-		advance();
-		return 1;
-	}
-	return 0;
-}
-
-static char*
-addtok(char *p, int val)
-{
-	if(p==0)
-		return 0;
-	if(p==&lex->tok[NTOK-1]){
-		*p = 0;
-		yyerror("token buffer too short");
-		return 0;
-	}
-	*p++=val;
-	return p;
-}
-
-static char*
-addutf(char *p, int c)
-{
-	int i, n;
-
-	p = addtok(p, c);	/* 1-byte UTF runes are special */
-	if(onebyte(c))
-		return p;
-	if(twobyte(c))
-		n = 2;
-	else if(threebyte(c))
-		n = 3;
-	else
-		n = 4;
-	for(i = 1; i < n; i++) {
-		c = nextc();
-		if(c == EOF || !xbyte(c))
-			break;
-		p = addtok(p, advance());
-	}
-	return p;
-}
-
-int
-yylex(void)
-{
-	int glob, c, d = nextc();
-	char *tok = lex->tok;
-	char *w = tok;
-	tree *t;
-
-	yylval.tree = 0;
-
-	/*
-	 * Embarassing sneakiness:  if the last token read was a quoted or unquoted
-	 * WORD then we alter the meaning of what follows.  If the next character
-	 * is `(', we return SUB (a subscript paren) and consume the `('.  Otherwise,
-	 * if the next character is the first character of a simple or compound word,
-	 * we insert a `^' before it.
-	 */
-	if(lex->lastword){
-		lex->lastword = 0;
-		if(d=='('){
-			advance();
-			strcpy(tok, "( [SUB]");
-			return SUB;
-		}
-		if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
-			strcpy(tok, "^");
-			return '^';
-		}
-	}
-	lex->inquote = 0;
-	skipwhite();
-	switch(c = advance()){
-	case EOF:
-		lex->lastdol = 0;
-		strcpy(tok, "EOF");
-		return EOF;
-	case '$':
-		lex->lastdol = 1;
-		if(nextis('#')){
-			strcpy(tok, "$#");
-			return COUNT;
-		}
-		if(nextis('"')){
-			strcpy(tok, "$\"");
-			return '"';
-		}
-		strcpy(tok, "$");
-		return '$';
-	case '&':
-		lex->lastdol = 0;
-		if(nextis('&')){
-			skipnl();
-			strcpy(tok, "&&");
-			return ANDAND;
-		}
-		strcpy(tok, "&");
-		return '&';
-	case '|':
-		lex->lastdol = 0;
-		if(nextis(c)){
-			skipnl();
-			strcpy(tok, "||");
-			return OROR;
-		}
-	case '<':
-	case '>':
-		lex->lastdol = 0;
-		/*
-		 * funny redirection tokens:
-		 *	redir:	arrow | arrow '[' fd ']'
-		 *	arrow:	'<' | '<<' | '>' | '>>' | '|'
-		 *	fd:	digit | digit '=' | digit '=' digit
-		 *	digit:	'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
-		 * some possibilities are nonsensical and get a message.
-		 */
-		*w++=c;
-		t = newtree();
-		switch(c){
-		case '|':
-			t->type = PIPE;
-			t->fd0 = 1;
-			t->fd1 = 0;
-			break;
-		case '>':
-			t->type = REDIR;
-			if(nextis(c)){
-				t->rtype = APPEND;
-				*w++=c;
-			}
-			else t->rtype = WRITE;
-			t->fd0 = 1;
-			break;
-		case '<':
-			t->type = REDIR;
-			if(nextis(c)){
-				t->rtype = HERE;
-				*w++=c;
-			} else if (nextis('>')){
-				t->rtype = RDWR;
-				*w++=c;
-			} else t->rtype = READ;
-			t->fd0 = 0;
-			break;
-		}
-		if(nextis('[')){
-			*w++='[';
-			c = advance();
-			*w++=c;
-			if(c<'0' || '9'<c){
-			RedirErr:
-				*w = 0;
-				yyerror(t->type==PIPE?"pipe syntax"
-						:"redirection syntax");
-				return EOF;
-			}
-			t->fd0 = 0;
-			do{
-				t->fd0 = t->fd0*10+c-'0';
-				*w++=c;
-				c = advance();
-			}while('0'<=c && c<='9');
-			if(c=='='){
-				*w++='=';
-				if(t->type==REDIR)
-					t->type = DUP;
-				c = advance();
-				if('0'<=c && c<='9'){
-					t->rtype = DUPFD;
-					t->fd1 = t->fd0;
-					t->fd0 = 0;
-					do{
-						t->fd0 = t->fd0*10+c-'0';
-						*w++=c;
-						c = advance();
-					}while('0'<=c && c<='9');
-				}
-				else{
-					if(t->type==PIPE)
-						goto RedirErr;
-					t->rtype = CLOSE;
-				}
-			}
-			if((c!=']'
-			|| t->type==DUP) && (t->rtype==HERE || t->rtype==APPEND))
-				goto RedirErr;
-			*w++=']';
-		}
-		*w='\0';
-		yylval.tree = t;
-		if(t->type==PIPE)
-			skipnl();
-		return t->type;
-	case '\'':
-		lex->lastdol = 0;
-		lex->lastword = 1;
-		lex->inquote = 1;
-		for(;;){
-			c = advance();
-			if(c==EOF)
-				break;
-			if(c=='\''){
-				if(nextc()!='\'')
-					break;
-				advance();
-			}
-			w = addutf(w, c);
-		}
-		if(w!=0)
-			*w='\0';
-		t = token(tok, WORD);
-		t->quoted = 1;
-		yylval.tree = t;
-		return t->type;
-	}
-	if(!wordchr(c)){
-		lex->lastdol = 0;
-		tok[0] = c;
-		tok[1]='\0';
-		return c;
-	}
-	glob = 0;
-	for(;;){
-		if(c=='*' || c=='[' || c=='?' || c==GLOB){
-			glob = 1;
-			w = addtok(w, GLOB);
-		}
-		w = addutf(w, c);
-		c = nextc();
-		if(lex->lastdol?!idchr(c):!wordchr(c)) break;
-		advance();
-	}
-
-	lex->lastword = 1;
-	lex->lastdol = 0;
-	if(w!=0)
-		*w='\0';
-	t = klook(tok);
-	if(t->type!=WORD)
-		lex->lastword = 0;
-	else
-		t->glob = glob;
-	t->quoted = 0;
-	yylval.tree = t;
-	return t->type;
-}
-
-void
-yyerror(char *m)
-{
-	pfln(err, lex->file, lex->line);
-	pstr(err, ": ");
-	if(lex->tok[0] && lex->tok[0]!='\n')
-		pfmt(err, "token %q: ", lex->tok);
-	pfmt(err, "%s\n", m);
-	flushio(err);
-
-	lex->lastword = 0;
-	lex->lastdol = 0;
-	while(lex->lastc!='\n' && lex->lastc!=EOF) advance();
-	nerror++;
-
-	setstatus(m);
-}
\ No newline at end of file
--- a/librc/pcmd.c
+++ /dev/null
@@ -1,169 +1,0 @@
-#include "rc.h"
-#include "io.h"
-#include "fns.h"
-
-#define	c0	t->child[0]
-#define	c1	t->child[1]
-#define	c2	t->child[2]
-
-static void
-pdeglob(io *f, char *s)
-{
-	while(*s){
-		if(*s==GLOB)
-			s++;
-		pchr(f, *s++);
-	}
-}
-
-static int ntab = 0;
-
-static char*
-tabs(void)
-{
-	return "\t\t\t\t\t\t\t\t"+8-(ntab%8);
-}
-
-void
-pcmd(io *f, tree *t)
-{
-	if(t==0)
-		return;
-	switch(t->type){
-	default:	pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
-	break;
-	case '$':	pfmt(f, "$%t", c0);
-	break;
-	case '"':	pfmt(f, "$\"%t", c0);
-	break;
-	case '&':	pfmt(f, "%t&", c0);
-	break;
-	case '^':	pfmt(f, "%t^%t", c0, c1);
-	break;
-	case '`':	pfmt(f, "`%t%t", c0, c1);
-	break;
-	case ANDAND:	pfmt(f, "%t && %t", c0, c1);
-	break;
-	case BANG:	pfmt(f, "! %t", c0);
-	break;
-	case BRACE:
-			ntab++;
-			pfmt(f, "{\n%s%t", tabs(), c0);
-			ntab--;
-			pfmt(f, "\n%s}", tabs());
-	break;
-	case COUNT:	pfmt(f, "$#%t", c0);
-	break;
-	case FN:	pfmt(f, "fn %t %t", c0, c1);
-	break;
-	case IF:	pfmt(f, "if%t%t", c0, c1);
-	break;
-	case NOT:	pfmt(f, "if not %t", c0);
-	break;
-	case OROR:	pfmt(f, "%t || %t", c0, c1);
-	break;
-	case PCMD:
-	case PAREN:	pfmt(f, "(%t)", c0);
-	break;
-	case SUB:	pfmt(f, "$%t(%t)", c0, c1);
-	break;
-	case SIMPLE:	pfmt(f, "%t", c0);
-	break;
-	case SUBSHELL:	pfmt(f, "@ %t", c0);
-	break;
-	case SWITCH:	pfmt(f, "switch %t %t", c0, c1);
-	break;
-	case TWIDDLE:	pfmt(f, "~ %t %t", c0, c1);
-	break;
-	case WHILE:	pfmt(f, "while %t%t", c0, c1);
-	break;
-	case ARGLIST:
-		if(c0==0)
-			pfmt(f, "%t", c1);
-		else if(c1==0)
-			pfmt(f, "%t", c0);
-		else
-			pfmt(f, "%t %t", c0, c1);
-		break;
-	case ';':
-		if(c0){
-			pfmt(f, "%t", c0);
-			if(c1){
-				if(c0->line==c1->line)
-					pstr(f, "; ");
-				else
-					pfmt(f, "\n%s", tabs());
-				pfmt(f, "%t", c1);
-			}
-		}
-		else pfmt(f, "%t", c1);
-		break;
-	case WORDS:
-		if(c0)
-			pfmt(f, "%t ", c0);
-		pfmt(f, "%t", c1);
-		break;
-	case FOR:
-		pfmt(f, "for(%t", c0);
-		if(c1)
-			pfmt(f, " in %t", c1);
-		pfmt(f, ")%t", c2);
-		break;
-	case WORD:
-		if(t->quoted)
-			pfmt(f, "%Q", t->str);
-		else pdeglob(f, t->str);
-		break;
-	case DUP:
-		if(t->rtype==DUPFD)
-			pfmt(f, ">[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
-		else
-			pfmt(f, ">[%d=]", t->fd0);
-		pfmt(f, "%t", c1);
-		break;
-	case PIPEFD:
-	case REDIR:
-		pchr(f, ' ');
-		switch(t->rtype){
-		case HERE:
-			if(c1)
-				pfmt(f, "%t ", c1);
-			pchr(f, '<');
-		case READ:
-		case RDWR:
-			pchr(f, '<');
-			if(t->rtype==RDWR)
-				pchr(f, '>');
-			if(t->fd0!=0)
-				pfmt(f, "[%d]", t->fd0);
-			break;
-		case APPEND:
-			pchr(f, '>');
-		case WRITE:
-			pchr(f, '>');
-			if(t->fd0!=1)
-				pfmt(f, "[%d]", t->fd0);
-			break;
-		}
-		pfmt(f, "%t", c0);
-		if(t->rtype == HERE)
-			pfmt(f, "\n%s%s\n", t->str, c0->str);
-		else if(c1)
-			pfmt(f, " %t", c1);
-		break;
-	case '=':
-		pfmt(f, "%t=%t", c0, c1);
-		if(c2)
-			pfmt(f, " %t", c2);
-		break;
-	case PIPE:
-		pfmt(f, "%t|", c0);
-		if(t->fd1==0){
-			if(t->fd0!=1)
-				pfmt(f, "[%d]", t->fd0);
-		}
-		else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
-		pfmt(f, "%t", c1);
-		break;
-	}
-}
\ No newline at end of file
--- a/librc/pfnc.c
+++ /dev/null
@@ -1,78 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-struct{
-	void (*f)(void);
-	char *name;
-}fname[] = {
-	Xappend, "Xappend",
-	Xasync, "Xasync",
-	Xbang, "Xbang",
-	Xclose, "Xclose",
-	Xdup, "Xdup",
-	Xeflag, "Xeflag",
-	Xexit, "Xexit",
-	Xfalse, "Xfalse",
-	Xifnot, "Xifnot",
-	Xjump, "Xjump",
-	Xmark, "Xmark",
-	Xpopm, "Xpopm",
-	Xpush, "Xpush",
-	Xrdwr, "Xrdwr",
-	Xread, "Xread",
-	Xhere, "Xhere",
-	Xhereq, "Xhereq",
-	Xreturn, "Xreturn",
-	Xtrue, "Xtrue",
-	Xif, "Xif",
-	Xwastrue, "Xwastrue",
-	Xword, "Xword",
-	Xwrite, "Xwrite",
-	Xmatch, "Xmatch",
-	Xcase, "Xcase",
-	Xconc, "Xconc",
-	Xassign, "Xassign",
-	Xdol, "Xdol",
-	Xcount, "Xcount",
-	Xlocal, "Xlocal",
-	Xunlocal, "Xunlocal",
-	Xfn, "Xfn",
-	Xdelfn, "Xdelfn",
-	Xpipe, "Xpipe",
-	Xpipewait, "Xpipewait",
-	Xpopredir, "Xpopredir",
-	Xrdcmds, "Xrdcmds",
-	Xbackq, "Xbackq",
-	Xpipefd, "Xpipefd",
-	Xsubshell, "Xsubshell",
-	Xfor, "Xfor",
-	Xglob, "Xglob",
-	Xsimple, "Xsimple",
-	Xqw, "Xqw",
-	Xsrcline, "Xsrcline",
-0};
-
-void
-pfun(io *f, void (*fn)(void))
-{
-	int i;
-	for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
-		pstr(f, fname[i].name);
-		return;
-	}
-	pfmt(f, "%p", fn);
-}
-
-void
-pfnc(io *f, thread *t)
-{
-	list *a;
-
-	pfln(f, srcfile(t), t->line);
-	pfmt(f, " pid %d cycle %p %d ", getpid(), t->code, t->pc);
-	pfun(f, t->code[t->pc].f);
-	for(a = t->argv;a;a = a->next) pfmt(f, " (%v)", a->words);
-	pchr(f, '\n');
-	flushio(f);
-}
\ No newline at end of file
--- a/librc/rc.h
+++ /dev/null
@@ -1,146 +1,0 @@
-
-#include <u.h>
-#include <libc.h>
-
-#define	SIGINT	2
-#define	SIGQUIT	3
-
-#define	YYMAXDEPTH	500
-#ifndef PAREN
-#include "y.tab.h"
-#endif
-typedef struct tree tree;
-typedef struct word word;
-typedef struct io io;
-typedef union code code;
-typedef struct var var;
-typedef struct list list;
-typedef struct lexer lexer;
-typedef struct redir redir;
-typedef struct thread thread;
-typedef struct builtin builtin;
-
-struct tree{
-	int	type;
-	int	rtype, fd0, fd1;	/* details of REDIR PIPE DUP tokens */
-	int	line;
-	char	glob;			/* 0=string, 1=glob, 2=pattern see globprop() and noglobs() */
-	char	quoted;
-	char	iskw;
-	char	*str;
-	tree	*child[3];
-	tree	*next;
-};
-tree *newtree(void);
-tree *token(char*, int), *klook(char*), *tree1(int, tree*);
-tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
-tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
-tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
-tree *simplemung(tree*);
-tree *globprop(tree*);
-char *fnstr(tree*);
-
-/*
- * The first word of any code vector is a reference count
- * and the second word is a string for srcfile().
- * Code starts at pc 2. The last code word must be a zero
- * terminator for codefree().
- * Always create a new reference to a code vector by calling codecopy(.).
- * Always call codefree(.) when deleting a reference.
- */
-union code{
-	void	(*f)(void);
-	int	i;
-	char	*s;
-};
-
-#define	NTOK	8192
-
-struct lexer{
-	io	*input;
-	char	*file;
-	int	line;
-
-	char	*prolog;
-	char	*epilog;
-
-	int	peekc;
-	int	future;
-	int	lastc;
-
-	char	eof;
-	char	inquote;
-	char	incomm;
-	char	lastword;	/* was the last token read a word or compound word terminator? */
-	char	lastdol;	/* was the last token read '$' or '$#' or '"'? */
-	char	iflast;		/* static `if not' checking */
-
-	char	qflag;
-
-	char	tok[NTOK];
-};
-extern lexer *lex;		/* current lexer */
-lexer *newlexer(io*, char*);
-void freelexer(lexer*);
-
-#define	APPEND	1
-#define	WRITE	2
-#define	READ	3
-#define	HERE	4
-#define	DUPFD	5
-#define	CLOSE	6
-#define RDWR	7
-
-struct var{
-	var	*next;		/* next on hash or local list */
-	word	*val;		/* value */
-	code	*fn;		/* pointer to function's code vector */
-	int	pc;		/* pc of start of function */
-	char	fnchanged;
-	char	changed;
-	char	name[];
-};
-var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
-void setvar(char*, word*), freevar(var*);
-
-#define	NVAR	521
-extern var *gvar[NVAR];		/* hash for globals */
-
-#define	new(type)	((type *)emalloc(sizeof(type)))
-
-void *emalloc(long);
-void *erealloc(void *, long);
-
-/*
- * Glob character escape in strings:
- *	In a string, GLOB must be followed by *?[ or GLOB.
- *	GLOB* matches any string
- *	GLOB? matches any single character
- *	GLOB[...] matches anything in the brackets
- *	GLOBGLOB matches GLOB
- */
-#define	GLOB	((char)0x01)
-/*
- * Is c the first character of a utf sequence?
- */
-#define	onebyte(c)	(((c)&0x80)==0x00)
-#define twobyte(c)	(((c)&0xe0)==0xc0)
-#define threebyte(c)	(((c)&0xf0)==0xe0)
-#define fourbyte(c)	(((c)&0xf8)==0xf0)
-#define xbyte(c)	(((c)&0xc0)==0x80)
-
-extern char *argv0;
-extern int nerror;		/* number of errors encountered during compilation */
-extern int doprompt;		/* is it time for a prompt? */
-extern io *err;
-
-/*
- * Which fds are the reading/writing end of a pipe?
- * Unfortunately, this can vary from system to system.
- * 9th edition Unix doesn't care, the following defines
- * work on plan 9.
- */
-#define	PRD	0
-#define	PWR	1
-extern char Rcmain[], Fdprefix[];
-extern char *Signame[];
\ No newline at end of file
--- a/librc/rcmain
+++ /dev/null
@@ -1,39 +1,0 @@
-# rcmain: unix version
-if(~ $#home 0) home=$HOME
-if(~ $#ifs 0) ifs=' 	
-'
-service=unix
-profile=$home/.rcrc
-prompt=('unix% ' '	')
-fn unix% {
-    $x*
-}
-if(~ $rcname ?./drawcpu) prompt=('broken! ' '	')
-
-if(flag p) path=/bin
-if not {
-	finit
-	if(~ $#path 0) path=(. /bin /usr/bin /usr/local/bin)
-}
-
-fn sigexit
-if(! ~ $#cflag 0){
-	if(flag l) {
-		. -q $profile
-	}
-	status=''
-	eval $cflag
-}
-if not if(flag i){
-	if(flag l) {
-		. -q $profile
-	}
-	status=''
-	if(! ~ $#* 0) . $*
-	. -i /fd/0
-}
-if not if(~ $#* 0) . /fd/0
-if not{
-	status=''
-	. $*
-}
\ No newline at end of file
--- a/librc/simple.c
+++ /dev/null
@@ -1,804 +1,0 @@
-/*
- * Maybe `simple' is a misnomer.
- */
-#include "rc.h"
-#include "getflags.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-
-/*
- * Search through the following code to see if we're just going to exit.
- */
-int
-exitnext(void){
-	int i=ifnot;
-	thread *p=runq;
-	code *c;
-loop:
-	c=&p->code[p->pc];
-	while(1){
-		if(c->f==Xpopredir || c->f==Xunlocal)
-			c++;
-		else if(c->f==Xsrcline)
-			c += 2;
-		else if(c->f==Xwastrue){
-			c++;
-			i=0;
-		}
-		else if(c->f==Xifnot){
-			if(i)
-				c += 2;
-			else
-				c = &p->code[c[1].i];
-		}
-		else if(c->f==Xreturn){
-			p = p->ret;
-			if(p==0)
-				return 1;
-			goto loop;
-		}else
-			break;
-	}
-	return c->f==Xexit;
-}
-
-void (*builtinfunc(char *name))(void)
-{
-	extern builtin Builtin[];
-	builtin *bp;
-
-	for(bp = Builtin;bp->name;bp++)
-		if(strcmp(name, bp->name)==0)
-			return bp->fnc;
-	return 0;
-}
-
-void
-Xsimple(void)
-{
-	void (*f)(void);
-	word *a;
-	var *v;
-	int pid;
-
-	a = runq->argv->words;
-	if(a==0){
-		Xerror1("empty argument list");
-		return;
-	}
-	if(flag['x'])
-		pfmt(err, "%v\n", a); /* wrong, should do redirs */
-	v = gvlook(a->word);
-	if(v->fn)
-		execfunc(v);
-	else{
-		if(strcmp(a->word, "builtin")==0){
-			a = a->next;
-			if(a==0){
-				Xerror1("builtin: empty argument list");
-				return;
-			}
-			popword();	/* "builtin" */
-		}
-		f = builtinfunc(a->word);
-		if(f){
-			(*f)();
-			return;
-		}
-		if(exitnext()){
-			/* fork and wait is redundant */
-			pushword("exec");
-			execexec();
-			/* does not return */
-		}
-		else{
-			if((pid = execforkexec()) < 0){
-				Xerror2("try again", Errstr());
-				return;
-			}
-			poplist();
-
-			/* interrupts don't get us out */
-			while(Waitfor(pid) < 0)
-				;
-		}
-	}
-}
-
-static void
-doredir(redir *rp)
-{
-	if(rp){
-		doredir(rp->next);
-		switch(rp->type){
-		case ROPEN:
-			if(rp->from!=rp->to){
-				Dup(rp->from, rp->to);
-				Close(rp->from);
-			}
-			break;
-		case RDUP:
-			Dup(rp->from, rp->to);
-			break;
-		case RCLOSE:
-			Close(rp->from);
-			break;
-		}
-	}
-}
-
-char*
-makercpath(char *dir, char *file)
-{
-	char *path;
-	int m, n = strlen(dir);
-	if(n==0) return estrdup(file);
-	while (n > 0 && dir[n-1]=='/') n--;
-	while (file[0]=='/') file++;
-	m = strlen(file);
-	path = emalloc(n + m + 2);
-	if(n>0) memmove(path, dir, n);
-	path[n++]='/';
-	memmove(path+n, file, m+1);
-	return path;
-}
-
-word*
-searchpath(char *w, char *v)
-{
-	static struct word nullpath = { "", 0 };
-	word *path;
-
-	if(w[0] && w[0] != '/' && w[0] != '#' &&
-	  (w[0] != '.' || (w[1] && w[1] != '/' && (w[1] != '.' || (w[2] && w[2] != '/'))))){
-		path = vlook(v)->val;
-		if(path)
-			return path;
-	}
-	return &nullpath;
-}
-
-static char**
-mkargv(word *a)
-{
-	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
-	char **argp = argv+1;
-	for(;a;a = a->next) *argp++=a->word;
-	*argp = 0;
-	return argv;
-}
-
-void
-execexec(void)
-{
-//	print("Execexec\n");
-	char **argv;
-	word *path;
-
-	popword();	/* "exec" */
-	if(runq->argv->words==0){
-		Xerror1("exec: empty argument list");
-		return;
-	}
-	argv = mkargv(runq->argv->words);
-	Updenv();
-	doredir(runq->redir);
-	for(path = searchpath(argv[1], "path"); path; path = path->next){
-		argv[0] = makercpath(path->word, argv[1]);
-		Exec(argv);
-	}
-	setstatus(Errstr());
-	pfln(err, srcfile(runq), runq->line);
-	pfmt(err, ": %s: %s\n", argv[1], getstatus());
-	Xexit();
-}
-
-void
-execfunc(var *func)
-{
-//	print("Execfunc\n");
-	popword();	/* name */
-	startfunc(func, Poplist(), runq->local, runq->redir);
-}
-
-void
-execcd(void)
-{
-	word *a = runq->argv->words;
-	word *cdpath;
-	char *dir;
-//	print("Execcd\n");
-	setstatus("can't cd");
-	switch(count(a)){
-	default:
-		pfmt(err, "Usage: cd [directory]\n");
-		break;
-	case 2:
-		a = a->next;
-		for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
-			dir = makercpath(cdpath->word, a->word);
-			if(Chdir(dir)>=0){
-				if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
-					pfmt(err, "%s\n", dir);
-				free(dir);
-				setstatus("");
-				break;
-			}
-			free(dir);
-		}
-		if(cdpath==0)
-			pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
-		break;
-	case 1:
-		a = vlook("home")->val;
-		if(a){
-			if(Chdir(a->word)>=0)
-				setstatus("");
-			else
-				pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
-		}
-		else
-			pfmt(err, "Can't cd -- $home empty\n");
-		break;
-	}
-	poplist();
-}
-
-void
-execexit(void)
-{
-//	print("Execexit\n");
-	switch(count(runq->argv->words)){
-	default:
-		pfmt(err, "Usage: exit [status]\nExiting anyway\n");
-	case 2:
-		setstatus(runq->argv->words->next->word);
-	case 1:	Xexit();
-	}
-}
-
-void
-execshift(void)
-{
-	int n;
-	word *a;
-	var *star;
-//	print("execshift\n");
-	switch(count(runq->argv->words)){
-	default:
-		pfmt(err, "Usage: shift [n]\n");
-		setstatus("shift usage");
-		poplist();
-		return;
-	case 2:
-		n = atoi(runq->argv->words->next->word);
-		break;
-	case 1:
-		n = 1;
-		break;
-	}
-	star = vlook("*");
-	for(;n>0 && star->val;--n){
-		a = star->val->next;
-		free(Freeword(star->val));
-		star->val = a;
-		star->changed = 1;
-	}
-	setstatus("");
-	poplist();
-}
-
-int
-mapfd(int fd)
-{
-	redir *rp;
-	for(rp = runq->redir;rp;rp = rp->next){
-		switch(rp->type){
-		case RCLOSE:
-			if(rp->from==fd)
-				fd=-1;
-			break;
-		case RDUP:
-		case ROPEN:
-			if(rp->to==fd)
-				fd = rp->from;
-			break;
-		}
-	}
-	return fd;
-}
-
-void
-execcmds(io *input, char *file, var *local, redir *redir)
-{
-	static union code rdcmds[5];
-//	print("Execcmds\n");
-	if(rdcmds[0].i==0){
-		rdcmds[0].i = 1;
-		rdcmds[1].s="*rdcmds*";
-		rdcmds[2].f = Xrdcmds;
-		rdcmds[3].f = Xreturn;
-		rdcmds[4].f = 0;
-	}
-
-	if(exitnext()) turfstack(local);
-
-	startexec(rdcmds, 2, local, redir);
-	runq->lex = newlexer(input, file);
-}
-
-void
-execeval(void)
-{
-	char *cmds;
-	int len;
-	io *f;
-//print("Execeval\n");
-	popword();	/* "eval" */
-
-	if(runq->argv->words==0){
-		Xerror1("Usage: eval cmd ...");
-		return;
-	}
-	Xqw();		/* make into single word */
-	cmds = Popword();
-	len = strlen(cmds);
-	cmds[len++] = '\n';
-	poplist();
-
-	f = openiostr();
-	pfln(f, srcfile(runq), runq->line);
-	pstr(f, " *eval*");
-
-	execcmds(openiocore(cmds, len), closeiostr(f), runq->local, runq->redir);
-}
-
-void
-execdot(void)
-{
-	int fd, bflag, iflag, qflag;
-	word *path, *argv;
-	char *file;
-//print("Execdot\n");
-	popword();	/* "." */
-
-	bflag = iflag = qflag = 0;
-	while(runq->argv->words && runq->argv->words->word[0]=='-'){
-		char *f = runq->argv->words->word+1;
-		if(*f == '-'){
-			popword();
-			break;
-		}
-		for(; *f; f++){
-			switch(*f){
-			case 'b':
-				bflag = 1;
-				continue;
-			case 'i':
-				iflag = 1;
-				continue;
-			case 'q':
-				qflag = 1;
-				continue;
-			}
-			goto Usage;
-		}
-		popword();
-	}
-
-	/* get input file */
-	if(runq->argv->words==0){
-Usage:
-		Xerror1("Usage: . [-biq] file [arg ...]");
-		return;
-	}
-	argv = Poplist();
-		
-	file = 0;
-	fd = -1;
-	for(path = searchpath(argv->word, "path"); path; path = path->next){
-		file = makercpath(path->word, argv->word);
-		fd = Open(file, 0);
-		if(fd >= 0)
-			break;
-		free(file);
-	}
-	if(fd<0){
-		if(!qflag)
-			Xerror3(". can't open", argv->word, Errstr());
-		freewords(argv);
-		return;
-	}
-	execcmds(openiofd(fd), file, (var*)0, runq->redir);
-	pushredir(RCLOSE, fd, 0);
-	runq->lex->qflag = qflag;
-	runq->iflag = iflag;
-	if(iflag || (!bflag && flag['b']==0)){
-		runq->lex->peekc=EOF;
-		runq->lex->epilog="";
-	}
-
-	runq->local = newvar("*", runq->local);
-	runq->local->val = argv->next;
-	argv->next=0;
-	runq->local->changed = 1;
-
-	runq->local = newvar("0", runq->local);
-	runq->local->val = argv;
-	runq->local->changed = 1;
-}
-
-void
-execflag(void)
-{
-//	print("Execflag\n");
-	char *letter, *val;
-	switch(count(runq->argv->words)){
-	case 2:
-		setstatus(flag[(unsigned char)runq->argv->words->next->word[0]]?"":"flag not set");
-		break;
-	case 3:
-		letter = runq->argv->words->next->word;
-		val = runq->argv->words->next->next->word;
-		if(strlen(letter)==1){
-			if(strcmp(val, "+")==0){
-				flag[(unsigned char)letter[0]] = flagset;
-				setstatus("");
-				break;
-			}
-			if(strcmp(val, "-")==0){
-				flag[(unsigned char)letter[0]] = 0;
-				setstatus("");
-				break;
-			}
-		}
-	default:
-		Xerror1("Usage: flag [letter] [+-]");
-		return;
-	}
-	poplist();
-}
-
-void
-execwhatis(void){	/* mildly wrong -- should fork before writing */
-	word *a, *b, *path;
-	var *v;
-	char *file;
-	io *out;
-	int found, sep;
-	a = runq->argv->words->next;
-//	print("Execwhatis\n");
-	if(a==0){
-		Xerror1("Usage: whatis name ...");
-		return;
-	}
-	setstatus("");
-	out = openiofd(mapfd(1));
-	for(;a;a = a->next){
-		v = vlook(a->word);
-		if(v->val){
-			pfmt(out, "%s=", a->word);
-			if(v->val->next==0)
-				pfmt(out, "%q\n", v->val->word);
-			else{
-				sep='(';
-				for(b = v->val;b && b->word;b = b->next){
-					pfmt(out, "%c%q", sep, b->word);
-					sep=' ';
-				}
-				pstr(out, ")\n");
-			}
-			found = 1;
-		}
-		else
-			found = 0;
-		v = gvlook(a->word);
-		if(v->fn)
-			pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
-		else{
-			if(builtinfunc(a->word))
-				pfmt(out, "builtin %s\n", a->word);
-			else {
-				for(path = searchpath(a->word, "path"); path; path = path->next){
-					file = makercpath(path->word, a->word);
-					if(Executable(file)){
-						pfmt(out, "%s\n", file);
-						free(file);
-						break;
-					}
-					free(file);
-				}
-				if(!path && !found){
-					pfmt(err, "%s: not found\n", a->word);
-					setstatus("not found");
-				}
-			}
-		}
-		flushio(out);
-	}
-	poplist();
-	free(closeiostr(out));	/* don't close fd */
-}
-
-void
-execwait(void)
-{
-//	print("Execwait\n");
-	switch(count(runq->argv->words)){
-	default:
-		Xerror1("Usage: wait [pid]");
-		return;
-	case 2:
-		Waitfor(atoi(runq->argv->words->next->word));
-		break;
-	case 1:
-		Waitfor(-1);
-		break;
-	}
-	poplist();
-}
-
-
-void
-execmount(void)
-{
-//print("Execmount\n");
-	char *spec = "";
-	int flag = MREPL;
-	int qflag, noauth, fd;
-	qflag = noauth = 0;
-
-	popword(); /* mount */
-	while(runq->argv->words && runq->argv->words->word[0]=='-'){
-		char *f = runq->argv->words->word+1;
-		if(*f == '-'){
-			popword();
-			break;
-		}
-		for(; *f; f++){
-			switch(*f){
-			case 'a':
-				flag |= MAFTER;
-				break;
-			case 'b':
-				flag |= MBEFORE;
-				break;
-			case 'c':
-				flag |= MCREATE;
-				break;
-			case 'C':
-				flag |= MCACHE;
-				break;
-			case 'n':
-				noauth = 1;
-				break;
-			case 'q':
-				qflag = 1;
-				break;
-			default:
-				goto Usage;
-			}
-			popword();
-		}
-	}
-	if(count(runq->argv->words)==3)
-		spec = runq->argv->words->next->next->word;
-	else if(count(runq->argv->words)!=2)
-		goto Usage;
-	if((flag&MAFTER)&&(flag&MBEFORE))
-		goto Usage;
-	fd = Open(runq->argv->words->word, ORDWR);
-	if(fd < 0)
-		goto Error;
-	if(mount(fd, -1, runq->argv->words->next->word, flag, spec) < 0)
-		goto Error;
-	poplist();
-	return;
-Error:
-	setstatus("mount error");
-	poplist();
-	if(qflag)
-		return;
-	pfmt(err, "mount: %s\n", strerror(errno));
-	return;
-Usage:
-	pfmt(err, "usage: mount [-a|-b] [-cCnNq] [-k keypattern] /srv/service dir [spec]\n");
-	setstatus("mount usage");
-	return;
-}
-
-// TODO: Remove
-int
-cat(int f, char *s)
-{
-	char buf[IOUNIT];
-	long n;
-	while((n=Read(f, buf, sizeof buf))>0)
-		if(Write(1, buf, n)!=n)
-			pfmt(err, "write error copying %s: %s\n", s, strerror(errno));
-	if(n < 0)
-		pfmt(err, "error reading %s: %s\n", s, strerror(errno));
-	return n;
-}
-
-void
-execcat(void)
-{
-	int f;
-	popword(); /* cat */
-	word *a;
-
-	f = 0;
-	a = runq->argv->words;
-	if(count(a) == 0){
-		cat(f, "<stdin>");
-		close(f);
-	} else for(;a;a = a->next){
-		f = Open(a->word, OREAD);
-		if(f < 0){
-			pfmt(err, "can't open %s: %s", a->word, strerror(errno));
-			break;
-		}
-		cat(f, a->word);
-		close(f);
-		write(1, "\n", 1);
-	}
-	poplist();
-}
-
-// TODO: Remove
-void
-execls(void)
-{
-	Dir *db;
-	int fd, n, i;
-	char *path;
-
-	/* Read in our dir and just output name in a row */
-	popword(); /* "ls" */
-	switch(count(runq->argv->words)){
-	case 0:
-		path = ".";
-		break;
-	case 1:
-		path = runq->argv->words->word;
-		break;
-	default:
-		pfmt(err, "ls: listing multiple files not supported\n");
-		return;
-	}
-	db = dirstat(path);
-	if(db == nil)
-		goto Error;
-	if((db->qid.type&QTDIR)) {
-		free(db);
-		fd = open(path, OREAD);
-		if(fd == -1)
-			goto Error;
-		n = dirreadall(fd, &db);
-		if(n < 0)
-			goto Error;
-		for(i = 0; i < n; i++){
-			write(1, db->name, strlen(db->name));
-			write(1, "\n", 1);
-			db++;
-		}
-		close(fd);
-	} else {
-		write(1, db->name, strlen(db->name));
-		write(1, "\n", 1);
-	}
-	return;
-Error:
-	pfmt(err, "ls: %sr\n", strerror(errno));
-	setstatus("ls error");
-	poplist();
-	return;
-}
-
-void
-execrfork(void)
-{
-	int arg;
-	char *s;
-
-	switch(count(runq->argv->words)){
-	case 1:
-		arg = RFENVG|RFNAMEG|RFNOTEG;
-		break;
-	case 2:
-		arg = 0;
-		for(s = runq->argv->words->next->word;*s;s++) switch(*s){
-		default:
-			goto Usage;
-		case 'n':
-			arg|=RFNAMEG;  break;
-		case 'N':
-			arg|=RFCNAMEG;
-			break;
-		case 'm':
-			/*arg|=RFNOMNT;*/  break;
-		case 'e':
-			arg|=RFENVG;   break;
-		case 'E':
-			arg|=RFCENVG;  break;
-		case 's':
-			arg|=RFNOTEG;  break;
-		case 'f':
-			arg|=RFFDG;    break;
-		case 'F':
-			arg|=RFCFDG;   break;
-		}
-		break;
-	default:
-	Usage:
-		pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
-		setstatus("rfork usage");
-		poplist();
-		return;
-	}
-	if(rfork(arg)==-1){
-		pfmt(err, "%s: %s failed\n", argv0, runq->argv->words->word);
-		setstatus("rfork failed");
-	} else {
-		if(arg & RFCFDG){
-			redir *rp;
-			for(rp = runq->redir; rp; rp = rp->next)
-				rp->type = 0;
-		}
-		setstatus("");
-	}
-	poplist();
-}
-
-void
-execbind(void)
-{
-//print("Execbind\n");
-	ulong flag = 0;
-	int qflag = 0;
-	popword(); /* "bind" */
-	while(runq->argv->words && runq->argv->words->word[0]=='-'){
-		char *f = runq->argv->words->word+1;
-		if(*f == '-'){
-			popword();
-			break;
-		}
-		for(; *f; f++){
-			switch(*f){
-			case 'a':
-				flag |= MAFTER;
-				break;
-			case 'b':
-				flag |= MBEFORE;
-				break;
-			case 'c':
-				flag |= MCREATE;
-				break;
-			case 'q':
-				qflag = 1;
-				break;
-			default:
-				goto Usage;
-			}
-			popword();
-		}
-	}
-	if(count(runq->argv->words)!=2 || ((flag & MAFTER) && (flag & MBEFORE)))
-		goto Usage;
-	if(bind(runq->argv->words->word, runq->argv->words->next->word, flag) == -1)
-		goto Error;
-	return;
-Error:
-	poplist();
-	if(qflag)
-		return;
-	pfmt(err, "bind: %s\n", strerror(errno));
-	return;
-Usage:
-	pfmt(err, "usage: bind [-b|-a|-c|-bc|-ac] new old\n");
-	setstatus("bind usage");
-	poplist();
-	return;
-}
--- a/librc/subr.c
+++ /dev/null
@@ -1,54 +1,0 @@
-#include "rc.h"
-#include "io.h"
-#include "fns.h"
-
-void *
-emalloc(long n)
-{
-	void *p = malloc(n);
-	if(p==0)
-		panic("Can't malloc %d bytes", n);
-	return p;
-}
-
-void*
-erealloc(void *p, long n)
-{
-	p = realloc(p, n);
-	if(p==0 && n!=0)
-		panic("Can't realloc %d bytes\n", n);
-	return p;
-}
-
-void
-pfln(io *fd, char *file, int line)
-{
-	if(file && line)
-		pfmt(fd, "%s:%d", file, line);
-	else if(file)
-		pstr(fd, file);
-	else
-		pstr(fd, argv0);
-}
-
-static char *bp;
-
-static void
-iacvt(int n)
-{
-	if(n<0){
-		*bp++='-';
-		n=-n;	/* doesn't work for n==-inf */
-	}
-	if(n/10)
-		iacvt(n/10);
-	*bp++=n%10+'0';
-}
-
-void
-inttoascii(char *s, int n)
-{
-	bp = s;
-	iacvt(n);
-	*bp='\0';
-}
\ No newline at end of file
--- a/librc/trap.c
+++ /dev/null
@@ -1,34 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "fns.h"
-#include "io.h"
-
-int ntrap;
-int trap[NSIG];
-
-void
-dotrap(void)
-{
-	int i;
-	var *trapreq;
-	word *starval;
-	starval = vlook("*")->val;
-	while(ntrap) for(i = 0;i<NSIG;i++) while(trap[i]){
-		--trap[i];
-		--ntrap;
-		if(getpid()!=mypid) Exit();
-		trapreq = vlook(Signame[i]);
-		if(trapreq->fn)
-			startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0);
-		else if(i==SIGINT || i==SIGQUIT){
-			/*
-			 * run the stack down until we uncover the
-			 * command reading loop.  Xreturn will exit
-			 * if there is none (i.e. if this is not
-			 * an interactive rc.)
-			 */
-			while(!runq->iflag) Xreturn();
-		}
-		else Exit();
-	}
-}
\ No newline at end of file
--- a/librc/tree.c
+++ /dev/null
@@ -1,190 +1,0 @@
-#include "rc.h"
-#include "io.h"
-#include "fns.h"
-
-/*
- * create and clear a new tree node, and add it
- * to the node list.
- */
-static tree *treefree, *treenodes;
-
-tree*
-newtree(void)
-{
-	tree *t;
-
-	t = treefree;
-	if(t==0)
-		t = new(tree);
-	else
-		treefree = t->next;
-	t->quoted = 0;
-	t->glob = 0;
-	t->iskw = 0;
-	t->str = 0;
-	t->child[0] = t->child[1] = t->child[2] = 0;
-	t->line = lex->line;
-	t->next = treenodes;
-	treenodes = t;
-	return t;
-}
-
-void
-freenodes(void)
-{
-	tree *t;
-
-	t = treenodes;
-	while(t){
-		if(t->str){
-			free(t->str);
-			t->str = 0;
-		}
-		t->child[0] = t->child[1] = t->child[2] = 0;
-		if(t->next==0){
-			t->next = treefree;
-			treefree = treenodes;
-			break;
-		}
-		t = t->next;
-	}
-	treenodes = 0;
-}
-
-tree*
-tree1(int type, tree *c0)
-{
-	return tree3(type, c0, (tree *)0, (tree *)0);
-}
-
-tree*
-tree2(int type, tree *c0, tree *c1)
-{
-	return tree3(type, c0, c1, (tree *)0);
-}
-
-tree*
-tree3(int type, tree *c0, tree *c1, tree *c2)
-{
-	tree *t;
-	if(type==';'){
-		if(c0==0)
-			return c1;
-		if(c1==0)
-			return c0;
-	}
-	t = newtree();
-	t->type = type;
-	t->child[0] = c0;
-	t->child[1] = c1;
-	t->child[2] = c2;
-
-	if(c0)
-		t->line = c0->line;
-	else if(c1)
-		t->line = c1->line;
-	else if(c2)
-		t->line = c2->line;
-	return t;
-}
-
-tree*
-mung1(tree *t, tree *c0)
-{
-	t->child[0] = c0;
-	return t;
-}
-
-tree*
-mung2(tree *t, tree *c0, tree *c1)
-{
-	t->child[0] = c0;
-	t->child[1] = c1;
-	return t;
-}
-
-tree*
-mung3(tree *t, tree *c0, tree *c1, tree *c2)
-{
-	t->child[0] = c0;
-	t->child[1] = c1;
-	t->child[2] = c2;
-	return t;
-}
-
-tree*
-epimung(tree *comp, tree *epi)
-{
-	tree *p;
-	if(epi==0)
-		return comp;
-	for(p = epi;p->child[1];p = p->child[1]);
-	p->child[1] = comp;
-	return epi;
-}
-
-/*
- * Add a SIMPLE node at the root of t and percolate all the redirections
- * up to the root.
- */
-tree*
-simplemung(tree *t)
-{
-	tree *u;
-
-	t = tree1(SIMPLE, t);
-	t->str = fnstr(t);
-	for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
-		if(u->child[1]->type==DUP
-		|| u->child[1]->type==REDIR){
-			u->child[1]->child[1] = t;
-			t = u->child[1];
-			u->child[1] = 0;
-		}
-	}
-	return t;
-}
-
-char*
-fnstr(tree *t)
-{
-	io *f = openiostr();
-	pfmt(f, "%t", t);
-	return closeiostr(f);
-}
-
-tree*
-globprop(tree *t)
-{
-	tree *c0 = t->child[0];
-	tree *c1 = t->child[1];
-	if(c1==0){
-		while(c0 && c0->type==WORDS){
-			c1 = c0->child[1];
-			if(c1 && c1->glob){
-				c1->glob=2;
-				t->glob=1;
-			}
-			c0 = c0->child[0];
-		}
-	} else {
-		if(c0->glob){
-			c0->glob=2;
-			t->glob=1;
-		}
-		if(c1->glob){
-			c1->glob=2;
-			t->glob=1;
-		}
-	}
-	return t;
-}
-
-tree*
-token(char *str, int type)
-{
-	tree *t = newtree();
-	t->str = estrdup(str);
-	t->type = type;
-	return t;
-}
\ No newline at end of file
--- a/librc/var.c
+++ /dev/null
@@ -1,109 +1,0 @@
-#include "rc.h"
-#include "exec.h"
-#include "fns.h"
-
-var *gvar[NVAR];
-
-int
-hash(char *s, int n)
-{
-	int h = 0, i = 1;
-	while(*s) h+=*s++*i++;
-	h%=n;
-	return h<0?h+n:h;
-}
-#define	NKW	30
-struct kw{
-	char *name;
-	int type;
-	struct kw *next;
-}*kw[NKW];
-
-void
-kenter(int type, char *name)
-{
-	int h = hash(name, NKW);
-	struct kw *p = new(struct kw);
-	p->type = type;
-	p->name = name;
-	p->next = kw[h];
-	kw[h] = p;
-}
-
-void
-kinit(void)
-{
-	kenter(FOR, "for");
-	kenter(IN, "in");
-	kenter(WHILE, "while");
-	kenter(IF, "if");
-	kenter(NOT, "not");
-	kenter(TWIDDLE, "~");
-	kenter(BANG, "!");
-	kenter(SUBSHELL, "@");
-	kenter(SWITCH, "switch");
-	kenter(FN, "fn");
-}
-
-tree*
-klook(char *name)
-{
-	struct kw *p;
-	tree *t = token(name, WORD);
-	for(p = kw[hash(name, NKW)];p;p = p->next)
-		if(strcmp(p->name, name)==0){
-			t->type = p->type;
-			t->iskw = 1;
-			break;
-		}
-	return t;
-}
-
-var*
-newvar(char *name, var *next)
-{
-	int n = strlen(name)+1;
-	var *v = emalloc(sizeof(var)+n);
-	memmove(v->name, name, n);
-	v->next = next;
-	v->val = 0;
-	v->fn = 0;
-	v->changed = 0;
-	v->fnchanged = 0;
-	return v;
-}
-
-var*
-gvlook(char *name)
-{
-	int h = hash(name, NVAR);
-	var *v;
-	for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
-	return gvar[h] = newvar(name, gvar[h]);
-}
-
-var*
-vlook(char *name)
-{
-	var *v;
-	if(runq)
-		for(v = runq->local;v;v = v->next)
-			if(strcmp(v->name, name)==0) return v;
-	return gvlook(name);
-}
-
-void
-setvar(char *name, word *val)
-{
-	var *v = vlook(name);
-	freewords(v->val);
-	v->val = val;
-	v->changed = 1;
-}
-
-void
-freevar(var *v)
-{
-	freewords(v->val);
-	free(v);
-}
\ No newline at end of file
--- a/librc/y.tab.c
+++ /dev/null
@@ -1,1977 +1,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     FOR = 258,
-     IN = 259,
-     WHILE = 260,
-     IF = 261,
-     NOT = 262,
-     TWIDDLE = 263,
-     BANG = 264,
-     SUBSHELL = 265,
-     SWITCH = 266,
-     FN = 267,
-     WORD = 268,
-     REDIR = 269,
-     DUP = 270,
-     PIPE = 271,
-     SUB = 272,
-     SIMPLE = 273,
-     ARGLIST = 274,
-     WORDS = 275,
-     BRACE = 276,
-     PAREN = 277,
-     PCMD = 278,
-     PIPEFD = 279,
-     OROR = 280,
-     ANDAND = 281,
-     COUNT = 282
-   };
-#endif
-/* Tokens.  */
-#define FOR 258
-#define IN 259
-#define WHILE 260
-#define IF 261
-#define NOT 262
-#define TWIDDLE 263
-#define BANG 264
-#define SUBSHELL 265
-#define SWITCH 266
-#define FN 267
-#define WORD 268
-#define REDIR 269
-#define DUP 270
-#define PIPE 271
-#define SUB 272
-#define SIMPLE 273
-#define ARGLIST 274
-#define WORDS 275
-#define BRACE 276
-#define PAREN 277
-#define PCMD 278
-#define PIPEFD 279
-#define OROR 280
-#define ANDAND 281
-#define COUNT 282
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 12 "syn.y"
-
-#include "rc.h"
-#include "fns.h"
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 16 "syn.y"
-{
-	struct tree *tree;
-}
-/* Line 193 of yacc.c.  */
-#line 159 "y.tab.c"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 172 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-/* Hand changed */
-#include <stddef.h>
-#define YYSIZE_T size_t
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)					\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack, Stack, yysize);				\
-	Stack = &yyptr->Stack;						\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  63
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   347
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  40
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  24
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  72
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  118
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   282
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      32,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    30,     2,    29,     2,    34,     2,
-      37,    25,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,    33,
-       2,    38,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    28,     2,    39,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    35,     2,    36,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      26,    27,    31
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint8 yyprhs[] =
-{
-       0,     0,     3,     4,     7,     9,    12,    14,    17,    20,
-      23,    25,    28,    32,    36,    40,    41,    44,    47,    49,
-      50,    53,    54,    59,    60,    65,    66,    75,    76,    83,
-      84,    89,    90,    95,    97,   101,   105,   109,   113,   116,
-     119,   122,   125,   129,   132,   134,   137,   140,   142,   146,
-     148,   150,   154,   157,   163,   166,   169,   171,   174,   178,
-     182,   185,   187,   189,   191,   193,   195,   197,   199,   201,
-     203,   205,   206
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      41,     0,    -1,    -1,    42,    32,    -1,    51,    -1,    44,
-      42,    -1,    51,    -1,    45,    43,    -1,    51,    33,    -1,
-      51,    34,    -1,    44,    -1,    51,    32,    -1,    35,    43,
-      36,    -1,    37,    43,    25,    -1,    59,    38,    60,    -1,
-      -1,    50,    49,    -1,    14,    60,    -1,    15,    -1,    -1,
-      46,    49,    -1,    -1,     6,    47,    52,    51,    -1,    -1,
-       6,     7,    53,    51,    -1,    -1,     3,    37,    60,     4,
-      63,    25,    54,    51,    -1,    -1,     3,    37,    60,    25,
-      55,    51,    -1,    -1,     5,    47,    56,    51,    -1,    -1,
-      11,    60,    57,    46,    -1,    58,    -1,     8,    60,    63,
-      -1,    51,    27,    51,    -1,    51,    26,    51,    -1,    51,
-      16,    51,    -1,    50,    51,    -1,    48,    51,    -1,     9,
-      51,    -1,    10,    51,    -1,    12,    63,    46,    -1,    12,
-      63,    -1,    59,    -1,    58,    60,    -1,    58,    50,    -1,
-      61,    -1,    59,    28,    60,    -1,    62,    -1,    61,    -1,
-      60,    28,    60,    -1,    29,    60,    -1,    29,    60,    17,
-      63,    25,    -1,    30,    60,    -1,    31,    60,    -1,    13,
-      -1,    39,    46,    -1,    39,    60,    46,    -1,    37,    63,
-      25,    -1,    14,    46,    -1,     3,    -1,     4,    -1,     5,
-      -1,     6,    -1,     7,    -1,     8,    -1,     9,    -1,    10,
-      -1,    11,    -1,    12,    -1,    -1,    63,    60,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint8 yyrline[] =
-{
-       0,    24,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,    33,    34,    35,    36,    37,    38,    39,    40,    41,
-      42,    43,    43,    45,    45,    46,    46,    56,    56,    58,
-      58,    60,    60,    62,    63,    64,    65,    66,    67,    68,
-      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
-      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
-      89,    90,    90,    90,    90,    90,    90,    90,    90,    90,
-      90,    91,    92
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "FOR", "IN", "WHILE", "IF", "NOT",
-  "TWIDDLE", "BANG", "SUBSHELL", "SWITCH", "FN", "WORD", "REDIR", "DUP",
-  "PIPE", "SUB", "SIMPLE", "ARGLIST", "WORDS", "BRACE", "PAREN", "PCMD",
-  "PIPEFD", "')'", "OROR", "ANDAND", "'^'", "'$'", "'\"'", "COUNT",
-  "'\\n'", "';'", "'&'", "'{'", "'}'", "'('", "'='", "'`'", "$accept",
-  "rc", "line", "body", "cmdsa", "cmdsan", "brace", "paren", "assign",
-  "epilog", "redir", "cmd", "@1", "@2", "@3", "@4", "@5", "@6", "simple",
-  "first", "word", "comword", "keyword", "words", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,    41,   280,   281,    94,    36,
-      34,   282,    10,    59,    38,   123,   125,    40,    61,    96
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    40,    41,    41,    42,    42,    43,    43,    44,    44,
-      45,    45,    46,    47,    48,    49,    49,    50,    50,    51,
-      51,    52,    51,    53,    51,    54,    51,    55,    51,    56,
-      51,    57,    51,    51,    51,    51,    51,    51,    51,    51,
-      51,    51,    51,    51,    58,    58,    58,    59,    59,    60,
-      60,    60,    61,    61,    61,    61,    61,    61,    61,    61,
-      61,    62,    62,    62,    62,    62,    62,    62,    62,    62,
-      62,    63,    63
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     2,     1,     2,     1,     2,     2,     2,
-       1,     2,     3,     3,     3,     0,     2,     2,     1,     0,
-       2,     0,     4,     0,     4,     0,     8,     0,     6,     0,
-       4,     0,     4,     1,     3,     3,     3,     3,     2,     2,
-       2,     2,     3,     2,     1,     2,     2,     1,     3,     1,
-       1,     3,     2,     5,     2,     2,     1,     2,     3,     3,
-       2,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     0,     2
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-      19,     0,     0,     0,     0,    19,    19,     0,    71,    56,
-       0,    18,     0,     0,     0,    19,    71,     0,     0,     0,
-      19,    15,    19,    19,     4,    33,    44,    47,     0,    19,
-      29,    23,    21,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,     0,    71,    50,    49,    40,    41,    31,
-      43,    60,    17,    52,    54,    55,     0,    10,    19,     6,
-       0,    57,     0,     1,     3,     5,     0,    20,    15,    39,
-      38,    19,    19,    19,     8,     9,    46,    45,     0,     0,
-       0,     0,    19,    19,    19,     0,    34,     0,    42,    72,
-      71,    12,     7,    11,    59,    58,    16,    37,    36,    35,
-      48,    14,    71,    27,    13,    30,    24,    22,    51,    32,
-       0,     0,    19,    53,    25,    28,    19,    26
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int8 yydefgoto[] =
-{
-      -1,    18,    19,    56,    57,    58,    21,    30,    22,    67,
-      23,    59,    84,    83,   116,   112,    82,    87,    25,    26,
-      89,    45,    46,    50
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -28
-static const yytype_int16 yypact[] =
-{
-     122,   -27,   -13,    -3,   296,   308,   308,   296,   -28,   -28,
-     135,   -28,   296,   296,   296,   308,   -28,   135,    25,     5,
-     308,     4,   308,   308,    84,   172,   -26,   -28,   296,   308,
-     -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
-     -28,   -28,   -28,     9,    15,   -28,   -28,    20,    20,    15,
-     135,   -28,    15,    30,   -28,   -28,    13,   -28,   308,    36,
-     185,   -28,   -19,   -28,   -28,   -28,   296,   -28,     4,    20,
-      20,   308,   308,   308,   -28,   -28,   -28,    15,   296,   296,
-      23,    32,   308,   308,   308,   296,   296,     9,   -28,    15,
-     -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,    20,    20,
-     -28,    15,   -28,   -28,   -28,    38,    38,    38,   -28,   -28,
-     222,   259,   308,   -28,   -28,    38,   308,    38
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-     -28,   -28,    35,   -12,     1,   -28,    16,    57,   -28,    -7,
-     -18,     8,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
-      28,     0,   -28,    -5
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -3
-static const yytype_int8 yytable[] =
-{
-      27,    20,    78,    68,    31,    27,    27,    76,    24,    85,
-      28,    60,    79,    47,    48,    27,    15,    81,    66,    11,
-      27,    20,    27,    27,    29,    63,    51,   102,    24,    27,
-      69,    70,    44,    61,    29,    49,    71,    64,    52,    86,
-      53,    54,    55,    85,    15,    62,    92,    90,   103,    91,
-      68,    85,    71,    77,    71,    65,    80,   104,    27,    51,
-      32,    96,    72,    73,    72,    73,    88,     0,    93,    74,
-      75,    27,    27,    27,     0,     0,     0,     0,    95,    97,
-      98,    99,    27,    27,    27,   110,     0,     0,     0,     0,
-     105,   106,   107,     0,    52,     0,     0,   111,     0,     0,
-      71,     0,     0,   109,     0,     0,   100,   101,     0,     0,
-      72,    73,    27,   108,     0,     0,    27,    74,    75,     0,
-     115,     0,    -2,     0,   117,     1,     0,     2,     3,     0,
-       4,     5,     6,     7,     8,     9,    10,    11,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,     9,    43,
-       0,    12,    13,    14,     0,     0,     0,    15,     0,    16,
-       0,    17,     0,     0,    12,    13,    14,     0,     0,     0,
-      15,     0,    16,     0,    17,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,    42,     9,    10,    11,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,     9,    43,
-       0,    12,    13,    14,     0,     0,     0,     0,     0,    16,
-      94,    17,     0,     0,    12,    13,    14,     0,     0,     0,
-       0,     0,    16,     0,    17,    33,    34,    35,    36,    37,
-      38,    39,    40,    41,    42,     9,    43,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   113,     0,     0,
-       0,    12,    13,    14,     0,     0,     0,     0,     0,    16,
-       0,    17,    33,    34,    35,    36,    37,    38,    39,    40,
-      41,    42,     9,    43,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   114,     0,     0,     0,    12,    13,
-      14,     0,     0,     0,     0,     0,    16,     0,    17,    33,
-      34,    35,    36,    37,    38,    39,    40,    41,    42,     9,
-      43,     1,     0,     2,     3,     0,     4,     5,     6,     7,
-       8,     9,    10,    11,     0,    12,    13,    14,     0,     0,
-       0,     0,     0,    16,     0,    17,     0,    12,    13,    14,
-       0,     0,     0,    15,     0,    16,     0,    17
-};
-
-static const yytype_int8 yycheck[] =
-{
-       0,     0,    28,    21,     7,     5,     6,    25,     0,    28,
-      37,    16,    38,     5,     6,    15,    35,    29,    14,    15,
-      20,    20,    22,    23,    37,     0,    10,     4,    20,    29,
-      22,    23,     4,    17,    37,     7,    16,    32,    10,    44,
-      12,    13,    14,    28,    35,    17,    58,    17,    25,    36,
-      68,    28,    16,    25,    16,    20,    28,    25,    58,    43,
-       3,    68,    26,    27,    26,    27,    50,    -1,    32,    33,
-      34,    71,    72,    73,    -1,    -1,    -1,    -1,    62,    71,
-      72,    73,    82,    83,    84,    90,    -1,    -1,    -1,    -1,
-      82,    83,    84,    -1,    66,    -1,    -1,   102,    -1,    -1,
-      16,    -1,    -1,    87,    -1,    -1,    78,    79,    -1,    -1,
-      26,    27,   112,    85,    -1,    -1,   116,    33,    34,    -1,
-     112,    -1,     0,    -1,   116,     3,    -1,     5,     6,    -1,
-       8,     9,    10,    11,    12,    13,    14,    15,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      -1,    29,    30,    31,    -1,    -1,    -1,    35,    -1,    37,
-      -1,    39,    -1,    -1,    29,    30,    31,    -1,    -1,    -1,
-      35,    -1,    37,    -1,    39,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      -1,    29,    30,    31,    -1,    -1,    -1,    -1,    -1,    37,
-      25,    39,    -1,    -1,    29,    30,    31,    -1,    -1,    -1,
-      -1,    -1,    37,    -1,    39,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    25,    -1,    -1,
-      -1,    29,    30,    31,    -1,    -1,    -1,    -1,    -1,    37,
-      -1,    39,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,    13,    14,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    25,    -1,    -1,    -1,    29,    30,
-      31,    -1,    -1,    -1,    -1,    -1,    37,    -1,    39,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
-      14,     3,    -1,     5,     6,    -1,     8,     9,    10,    11,
-      12,    13,    14,    15,    -1,    29,    30,    31,    -1,    -1,
-      -1,    -1,    -1,    37,    -1,    39,    -1,    29,    30,    31,
-      -1,    -1,    -1,    35,    -1,    37,    -1,    39
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,     3,     5,     6,     8,     9,    10,    11,    12,    13,
-      14,    15,    29,    30,    31,    35,    37,    39,    41,    42,
-      44,    46,    48,    50,    51,    58,    59,    61,    37,    37,
-      47,     7,    47,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    14,    60,    61,    62,    51,    51,    60,
-      63,    46,    60,    60,    60,    60,    43,    44,    45,    51,
-      63,    46,    60,     0,    32,    42,    14,    49,    50,    51,
-      51,    16,    26,    27,    33,    34,    50,    60,    28,    38,
-      60,    43,    56,    53,    52,    28,    63,    57,    46,    60,
-      17,    36,    43,    32,    25,    46,    49,    51,    51,    51,
-      60,    60,     4,    25,    25,    51,    51,    51,    60,    46,
-      63,    63,    55,    25,    25,    51,    54,    51
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL		goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-	break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-	 constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-		    + sizeof yyexpecting - 1
-		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-		       * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-	 YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	  {
-	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-	      {
-		yycount = 1;
-		yysize = yysize0;
-		yyformat[sizeof yyunexpected - 1] = '\0';
-		break;
-	      }
-	    yyarg[yycount++] = yytname[yyx];
-	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-	    yysize_overflow |= (yysize1 < yysize);
-	    yysize = yysize1;
-	    yyfmt = yystpcpy (yyfmt, yyprefix);
-	    yyprefix = yyor;
-	  }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-	{
-	  /* Avoid sprintf, as that infringes on the user's name space.
-	     Don't have undefined behavior even if the translation
-	     produced a string with the wrong number of "%s"s.  */
-	  char *yyp = yyresult;
-	  int yyi = 0;
-	  while ((*yyp = *yyf) != '\0')
-	    {
-	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-		{
-		  yyp += yytnamerr (yyp, yyarg[yyi++]);
-		  yyf += 2;
-		}
-	      else
-		{
-		  yyp++;
-		  yyf++;
-		}
-	    }
-	}
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-	break;
-    }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol.  */
-int yychar;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;		/* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss);
-	YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 2:
-#line 24 "syn.y"
-    { return 1;}
-    break;
-
-  case 3:
-#line 25 "syn.y"
-    {readhere(lex->input); return !compile((yyvsp[(1) - (2)].tree));}
-    break;
-
-  case 5:
-#line 27 "syn.y"
-    {(yyval.tree)=tree2(';', (yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 7:
-#line 29 "syn.y"
-    {(yyval.tree)=tree2(';', (yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 9:
-#line 31 "syn.y"
-    {(yyval.tree)=tree1('&', (yyvsp[(1) - (2)].tree));}
-    break;
-
-  case 11:
-#line 33 "syn.y"
-    {readhere(lex->input);}
-    break;
-
-  case 12:
-#line 34 "syn.y"
-    {(yyval.tree)=tree1(BRACE, (yyvsp[(2) - (3)].tree));}
-    break;
-
-  case 13:
-#line 35 "syn.y"
-    {(yyval.tree)=tree1(PCMD, (yyvsp[(2) - (3)].tree));}
-    break;
-
-  case 14:
-#line 36 "syn.y"
-    {(yyval.tree)=tree2('=', (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 15:
-#line 37 "syn.y"
-    {(yyval.tree)=0;}
-    break;
-
-  case 16:
-#line 38 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(1) - (2)].tree), (yyvsp[(1) - (2)].tree)->child[0], (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 17:
-#line 39 "syn.y"
-    {(yyval.tree)=mung1((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)); if((yyval.tree)->rtype==HERE) heredoc((yyval.tree));}
-    break;
-
-  case 19:
-#line 41 "syn.y"
-    {(yyval.tree)=0;}
-    break;
-
-  case 20:
-#line 42 "syn.y"
-    {(yyval.tree)=epimung((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 21:
-#line 43 "syn.y"
-    {skipnl();}
-    break;
-
-  case 22:
-#line 44 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(1) - (4)].tree), (yyvsp[(2) - (4)].tree), (yyvsp[(4) - (4)].tree));}
-    break;
-
-  case 23:
-#line 45 "syn.y"
-    {skipnl();}
-    break;
-
-  case 24:
-#line 45 "syn.y"
-    {(yyval.tree)=mung1((yyvsp[(2) - (4)].tree), (yyvsp[(4) - (4)].tree));}
-    break;
-
-  case 25:
-#line 46 "syn.y"
-    {skipnl();}
-    break;
-
-  case 26:
-#line 55 "syn.y"
-    {(yyval.tree)=mung3((yyvsp[(1) - (8)].tree), (yyvsp[(3) - (8)].tree), (yyvsp[(5) - (8)].tree) ? (yyvsp[(5) - (8)].tree) : tree1(PAREN, (yyvsp[(5) - (8)].tree)), (yyvsp[(8) - (8)].tree));}
-    break;
-
-  case 27:
-#line 56 "syn.y"
-    {skipnl();}
-    break;
-
-  case 28:
-#line 57 "syn.y"
-    {(yyval.tree)=mung3((yyvsp[(1) - (6)].tree), (yyvsp[(3) - (6)].tree), (tree*)0, (yyvsp[(6) - (6)].tree));}
-    break;
-
-  case 29:
-#line 58 "syn.y"
-    {skipnl();}
-    break;
-
-  case 30:
-#line 59 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(1) - (4)].tree), (yyvsp[(2) - (4)].tree), (yyvsp[(4) - (4)].tree));}
-    break;
-
-  case 31:
-#line 60 "syn.y"
-    {skipnl();}
-    break;
-
-  case 32:
-#line 61 "syn.y"
-    {(yyval.tree)=tree2(SWITCH, (yyvsp[(2) - (4)].tree), (yyvsp[(4) - (4)].tree));}
-    break;
-
-  case 33:
-#line 62 "syn.y"
-    {(yyval.tree)=simplemung((yyvsp[(1) - (1)].tree));}
-    break;
-
-  case 34:
-#line 63 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(1) - (3)].tree), (yyvsp[(2) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 35:
-#line 64 "syn.y"
-    {(yyval.tree)=tree2(ANDAND, (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 36:
-#line 65 "syn.y"
-    {(yyval.tree)=tree2(OROR, (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 37:
-#line 66 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(2) - (3)].tree), (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 38:
-#line 67 "syn.y"
-    {(yyval.tree)=mung2((yyvsp[(1) - (2)].tree), (yyvsp[(1) - (2)].tree)->child[0], (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 39:
-#line 68 "syn.y"
-    {(yyval.tree)=mung3((yyvsp[(1) - (2)].tree), (yyvsp[(1) - (2)].tree)->child[0], (yyvsp[(1) - (2)].tree)->child[1], (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 40:
-#line 69 "syn.y"
-    {(yyval.tree)=mung1((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 41:
-#line 70 "syn.y"
-    {(yyval.tree)=mung1((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 42:
-#line 71 "syn.y"
-    {(yyval.tree)=tree2(FN, (yyvsp[(2) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 43:
-#line 72 "syn.y"
-    {(yyval.tree)=tree1(FN, (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 45:
-#line 74 "syn.y"
-    {(yyval.tree)=globprop(tree2(ARGLIST, (yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)));}
-    break;
-
-  case 46:
-#line 75 "syn.y"
-    {(yyval.tree)=globprop(tree2(ARGLIST, (yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)));}
-    break;
-
-  case 48:
-#line 77 "syn.y"
-    {(yyval.tree)=globprop(tree2('^', (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree)));}
-    break;
-
-  case 49:
-#line 78 "syn.y"
-    {lex->lastword=1; (yyvsp[(1) - (1)].tree)->type=WORD;}
-    break;
-
-  case 51:
-#line 80 "syn.y"
-    {(yyval.tree)=globprop(tree2('^', (yyvsp[(1) - (3)].tree), (yyvsp[(3) - (3)].tree)));}
-    break;
-
-  case 52:
-#line 81 "syn.y"
-    {(yyval.tree)=tree1('$', (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 53:
-#line 82 "syn.y"
-    {(yyval.tree)=tree2(SUB, (yyvsp[(2) - (5)].tree), (yyvsp[(4) - (5)].tree));}
-    break;
-
-  case 54:
-#line 83 "syn.y"
-    {(yyval.tree)=tree1('"', (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 55:
-#line 84 "syn.y"
-    {(yyval.tree)=tree1(COUNT, (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 57:
-#line 86 "syn.y"
-    {(yyval.tree)=tree2('`', (tree*)0, (yyvsp[(2) - (2)].tree));}
-    break;
-
-  case 58:
-#line 87 "syn.y"
-    {(yyval.tree)=tree2('`', (yyvsp[(2) - (3)].tree), (yyvsp[(3) - (3)].tree));}
-    break;
-
-  case 59:
-#line 88 "syn.y"
-    {(yyval.tree)=globprop(tree1(PAREN, (yyvsp[(2) - (3)].tree)));}
-    break;
-
-  case 60:
-#line 89 "syn.y"
-    {(yyval.tree)=mung1((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)); (yyval.tree)->type=PIPEFD;}
-    break;
-
-  case 71:
-#line 91 "syn.y"
-    {(yyval.tree)=(tree*)0;}
-    break;
-
-  case 72:
-#line 92 "syn.y"
-    {(yyval.tree)=tree2(WORDS, (yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree));}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 1776 "y.tab.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-      {
-	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-	  {
-	    YYSIZE_T yyalloc = 2 * yysize;
-	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
-	    if (yymsg != yymsgbuf)
-	      YYSTACK_FREE (yymsg);
-	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-	    if (yymsg)
-	      yymsg_alloc = yyalloc;
-	    else
-	      {
-		yymsg = yymsgbuf;
-		yymsg_alloc = sizeof yymsgbuf;
-	      }
-	  }
-
-	if (0 < yysize && yysize <= yymsg_alloc)
-	  {
-	    (void) yysyntax_error (yymsg, yystate, yychar);
-	    yyerror (yymsg);
-	  }
-	else
-	  {
-	    yyerror (YY_("syntax error"));
-	    if (yysize != 0)
-	      goto yyexhaustedlab;
-	  }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
--- a/librc/y.tab.h
+++ /dev/null
@@ -1,113 +1,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     FOR = 258,
-     IN = 259,
-     WHILE = 260,
-     IF = 261,
-     NOT = 262,
-     TWIDDLE = 263,
-     BANG = 264,
-     SUBSHELL = 265,
-     SWITCH = 266,
-     FN = 267,
-     WORD = 268,
-     REDIR = 269,
-     DUP = 270,
-     PIPE = 271,
-     SUB = 272,
-     SIMPLE = 273,
-     ARGLIST = 274,
-     WORDS = 275,
-     BRACE = 276,
-     PAREN = 277,
-     PCMD = 278,
-     PIPEFD = 279,
-     OROR = 280,
-     ANDAND = 281,
-     COUNT = 282
-   };
-#endif
-/* Tokens.  */
-#define FOR 258
-#define IN 259
-#define WHILE 260
-#define IF 261
-#define NOT 262
-#define TWIDDLE 263
-#define BANG 264
-#define SUBSHELL 265
-#define SWITCH 266
-#define FN 267
-#define WORD 268
-#define REDIR 269
-#define DUP 270
-#define PIPE 271
-#define SUB 272
-#define SIMPLE 273
-#define ARGLIST 274
-#define WORDS 275
-#define BRACE 276
-#define PAREN 277
-#define PCMD 278
-#define PIPEFD 279
-#define OROR 280
-#define ANDAND 281
-#define COUNT 282
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 16 "syn.y"
-{
-	struct tree *tree;
-}
-/* Line 1529 of yacc.c.  */
-#line 107 "y.tab.h"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
--- a/main.c
+++ b/main.c
@@ -44,7 +44,7 @@
 static void
 usage(void)
 {
-	fprintf(stderr, "usage: drawcpu [-D] [-p 9bin]\n");
+	fprintf(stderr, "usage: drawcpu [-p 9bin]\n");
 	exit(1);
 }
 
@@ -53,10 +53,8 @@
 main(int argc, char **argv)
 {
 	extern ulong kerndate;
-	int ifd, ofd,efd, dfd;
 	char *path;
 
-	debug = 0;
 	path = nil;
 	kerndate = seconds();
 	eve = getuser();
@@ -64,9 +62,6 @@
 		eve = "drawcpu";
 
 	ARGBEGIN {
-	case 'D':
-		debug++;
-		break;
 	case 'p':
 		path = EARGF(usage());
 		break;
@@ -92,34 +87,22 @@
 	if(bind("#U", "/root", MREPL|MCREATE) < 0)
 		panic("bind #U: %r");
 	bind("#C", "/", MAFTER);
-	//bind("#F", "/fd", MBEFORE);
 	//bind("#P", "/proc", MBEFORE);
 
-	/* We have to be a bit pedantic about the fds, leave 0, 1, 2 alone */
-	ifd = open("/dev/null", OREAD);
-	ofd = open("/dev/null", OWRITE);
-	efd = open("/dev/null", OWRITE);
-	if(debug)
-		dfd = create("./error.log", OWRITE, 0644);
-	else
-		dfd = open("/dev/null", OWRITE);
-
-	close(ifd);
-	close(ofd);
-	close(efd);
-
 	if(bind("/root", "/", MAFTER) < 0)
 		panic("bind /root: %r");
 
+	//if(bind("/dev/fd", "/fd", MAFTER) < 0)
+	//	panic("bind /fd: %r");
+
 	if(path != nil)
 		bind(path, "/bin", MAFTER);
 
 	char *cmd[] = {
-		"drawcpu",
-		"-c",
-		". <{n=`{read} && ! ~ $#n 0 && read -c $n} >[2=1]"	
+		"./Users/halfwit/Downloads/drawcpu/bin/echo",
+		"hi"
 	};
 
-	rc(3, cmd, dfd);
+	exec(2, cmd);
 	_exit(0);
 }
--- a/posix-arm64/Makefile
+++ b/posix-arm64/Makefile
@@ -1,9 +1,8 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
-# Cannot use PIE because of trampoline
 CFLAGS+=-arch arm64
-#LDFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\