shithub: drawcpu

Download patch

ref: e4df0925260ce4f14ba6db4025d1ed4913b0f9ec
parent: 106305c733d2f7b20e3cf8093ba5dc3a1407df5d
parent: 6d3e368f2d0796e366d2df8ed56e3b6fe0c42182
author: halfwit <michaelmisch1985@gmail.com>
date: Thu Aug 22 15:56:01 EDT 2024

Merge pull request #1 from halfwit/execvm

Execvm

--- a/Make.dragonfly
+++ b/Make.dragonfly
@@ -13,6 +13,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 AUDIO=none
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/')
 
 all: default
 
--- a/Make.fbdev
+++ b/Make.fbdev
@@ -14,6 +14,7 @@
 TARG=drawcpu
 # AUDIO=none
 AUDIO=alsa
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/')
 
 all: default
 
--- a/Make.freebsd
+++ b/Make.freebsd
@@ -13,6 +13,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 AUDIO=unix
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/')
 
 all: default
 
--- a/Make.irix
+++ b/Make.irix
@@ -17,6 +17,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 MAKE=gmake
+ARCH=mips
 
 all: default
 
--- a/Make.linux
+++ b/Make.linux
@@ -13,6 +13,7 @@
 TARG=drawcpu
 # AUDIO=none
 AUDIO=pipewire
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/')
 
 all: default
 
--- a/Make.linux386
+++ b/Make.linux386
@@ -14,6 +14,7 @@
 TARG=drawcpu
 # AUDIO=none
 AUDIO=unix
+ARCH=386
 
 all: default
 
--- a/Make.netbsd
+++ b/Make.netbsd
@@ -13,6 +13,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 AUDIO=unix
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/')
 
 all: default
 
--- a/Make.openbsd
+++ b/Make.openbsd
@@ -12,6 +12,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 AUDIO=sndio
+ARCH=$(shell uname -m|sed 's/i.86/386/; s/macppc/power/; s/socppc/power/; s/x86_64/amd64/; s/sparc64/sun4u/')
 
 all: default
 
--- a/Make.osx-cocoa
+++ b/Make.osx-cocoa
@@ -12,6 +12,7 @@
 LDFLAGS=$(PTHREAD)
 TARG=drawcpu
 AUDIO=none
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/x86_64/amd64/')
 
 all: default
 
--- a/Make.pthread
+++ b/Make.pthread
@@ -15,6 +15,7 @@
 TARG=drawcpu
 # AUDIO=none
 AUDIO=unix
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/')
 
 all: default
 
--- a/Make.unix
+++ b/Make.unix
@@ -15,6 +15,7 @@
 TARG=drawcpu
 # AUDIO=none
 AUDIO=unix
+ARCH=$(shell uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/')
 
 all: default
 
--- a/Make.win32
+++ b/Make.win32
@@ -30,6 +30,7 @@
 #IP=win32
 #OS=win32
 #GUI=win32
+ARCH=386
 
 all: default
 
--- a/Make.win64
+++ b/Make.win64
@@ -20,6 +20,7 @@
 LDADD=-lgdi32 -lws2_32 -lwinmm -mwindows
 TARG=drawcpu.exe
 XOFILES=glenda-t.$O
+ARCH=386
 
 all: default
 
--- a/Makefile
+++ b/Makefile
@@ -11,8 +11,8 @@
 
 LIBS1=\
 	kern/libkern.a\
-	rc/librc.a\
 	libip/libip.a\
+	librc/librc.a\
 	libmemdraw/libmemdraw.a\
 	libmemlayer/libmemlayer.a\
 	libdraw/libdraw.a\
@@ -50,8 +50,8 @@
 libc/libc.a:
 	(cd libc; $(MAKE))
 
-rc/librc.a:
-	(cd rc; $(MAKE))
-
 gui-$(GUI)/libgui.a:
 	(cd gui-$(GUI); $(MAKE))
+
+librc/librc.a:
+	(cd librc; $(MAKE))
--- a/TODO
+++ b/TODO
@@ -1,47 +1,28 @@
-BUILTINS:
- - [x]' read'
- - [ ] 'write' ?
- - [x] 'ls'
- - [x] 'cat'
- - [ ] 'srv' ?
- - [~] 'mount' - currently not working
- - [x] 'bind'
- - [ ] 'mkdir'
- - [x] 'rm'
- - [ ] 'unmount'
- - [ ] 'ns'
- - [~] 'test' - only -d and maybe -f for now
- - [x] 'echo'
- - [ ] 'cp'
-
 TODO:
- - [ ] rc builtins (see above)
- - [x] Install rcmain properly on system, refer to it as needed
- - [ ] have it export a var service=unix
+ - [x] /env/fn# to init functions?
+ - [-] set up initial connection before handing over to an rc session, to set up binds and mounts?
+ - [ ] Set up $path with \#9/$objtype/bin and \#9/rc/bin
+ - [x] remove rc builtins aside from mount/bind
+ - [x] start.s in libmachdep for each posix-target, just do like tas.c
+       - investigate if we want to run this another way instead!
+ - [x] have it export a var service=unix
  - [ ] Some people probably want aan?
- - [x] Move rc code to use our libc.h, u.h everywhere so our defs of open + such are correct
  - [ ] gui-cocoa try to capture the windows we create so we can send mouse/keyboard to it, plist for launchd
  - [ ] gui-wl cannibalize the wayland shims
+ - [ ] Use ScreenCaptureKit to get at the video/audio. Handle resizes the other direction
  - [ ] define the gui interface
  - [x] Makefile librc --> librc.a
- - [x] libc.h getwd plan9port/src/lib9/getwd.c 
- - [x] libc.h dirread /sys/src/libc/9sys/dirread.c
- - [x] libc.h notify plan9port/src/lib9/notify.c
- - [x] libc.h postnote plan9port/src/lib9/postnote.c
- - [x] libc.h await plan9port/src/lib9/await.c
- - [x] libc.h rfork plan9port/src/lib9/rfork.c 
- - [x] libc.h wait plan9port/src/lib9/wait.c
- - [x] libc.h time plan9port/src/lib9/time.c
  - [ ] RFREND + RFNOMEM could probably be handled in rfork
 
+Remove our rc, just add in all of our syscall intercepts properly.
 Kernel space needs:
  - devdraw  - #i: !needed, We use the client exported /dev/draw instead
  - devkbd   - #b: !needed, We use the client exported /dev/kbd instead
  - devmouse - #m: !needed, We use the client exported /dev/mouse instead
  - devaudio - #A: !needed, We use the client exported /dev/audio instead
- - devcmd   - #C: !needed OS(1) commands, we already run on host
+ - devcmd   - #C: needed OS(1) commands, we already run on host
  - devcons  - #c: needed, /dev/cons
- - devenv   - #e: needed, /dev/env
+ - devenv   - #e: needed, /env
  - devfs    - #U: needed, local files
  - devip    - #I: needed, networking
  - devlfd   - #L: needed, local fd
@@ -48,8 +29,9 @@
  - devmnt   - #M: needed, client shares
  - devpipe  - #|: needed for pipes
  - devroot  - #/: needed, base of stack
- - devssl   - #D: !needed, ssl
- - devtls   - #a: !needed, tls
+ - devssl   - #D: !needed, ssl - eventually add
+ - devtls   - #a: !needed, tls - eventually add
  - devproc  - #p: needed, /dev/proc, overlay any existing 
- - devsrv   - #s: ~needed, if there's a compelling use case and interest
+ - devsrv   - #s: !needed, eventually add
+ - devbin   - #9: needed, just a path that can use PLAN9 
  - devtab   - meta, needed - add/remove any devices that we add/remove, from here as well
--- /dev/null
+++ b/arg.h
@@ -1,0 +1,20 @@
+/* SPDX-License-Identifier: Unlicense */
+#define ARGBEGIN \
+	for (;;) { \
+		if (argc > 0) \
+			++argv, --argc; \
+		if (argc == 0 || (*argv)[0] != '-') \
+			break; \
+		if ((*argv)[1] == '-' && !(*argv)[2]) { \
+			++argv, --argc; \
+			break; \
+		} \
+		for (char *opt_ = &(*argv)[1], done_ = 0; !done_ && *opt_; ++opt_) { \
+			switch (*opt_)
+
+#define ARGEND \
+		} \
+	}
+
+#define EARGF(x) \
+	(done_ = 1, opt_[1] ? ++opt_ : argv[1] ? --argc, *++argv : ((x), abort(), (char *)0))
\ No newline at end of file
--- a/drawcpu.h
+++ b/drawcpu.h
@@ -1,5 +1,4 @@
-extern void runcommand(int, char**);
 extern char *getuser(void);
-extern int session(void);
+extern void rc(int, char**, int);
 extern int aanclient(char*, int);
 extern int dbg;
\ No newline at end of file
--- /dev/null
+++ b/include/a.out.h
@@ -1,0 +1,48 @@
+typedef	struct	Exec	Exec;
+struct Exec
+{
+	long	magic;		/* magic number */
+	long	text;	 	/* size of text segment */
+	long	data;	 	/* size of initialized data */
+	long	bss;	  	/* size of uninitialized data */
+	long	syms;	 	/* size of symbol table */
+	long	entry;	 	/* entry point */
+	long	spsz;		/* size of pc/sp offset table */
+	long	pcsz;		/* size of pc/line number table */
+};
+
+#define HDR_MAGIC	0x00008000		/* header expansion */
+
+#define	_MAGIC(f, b)	((f)|((((4*(b))+0)*(b))+7))
+#define	A_MAGIC		_MAGIC(0, 8)		/* 68020 */
+#define	I_MAGIC		_MAGIC(0, 11)		/* intel 386 */
+#define	J_MAGIC		_MAGIC(0, 12)		/* intel 960 (retired) */
+#define	K_MAGIC		_MAGIC(0, 13)		/* sparc */
+#define	V_MAGIC		_MAGIC(0, 16)		/* mips 3000 BE */
+#define	X_MAGIC		_MAGIC(0, 17)		/* att dsp 3210 (retired) */
+#define	M_MAGIC		_MAGIC(0, 18)		/* mips 4000 BE */
+#define	D_MAGIC		_MAGIC(0, 19)		/* amd 29000 (retired) */
+#define	E_MAGIC		_MAGIC(0, 20)		/* arm */
+#define	Q_MAGIC		_MAGIC(0, 21)		/* powerpc */
+#define	N_MAGIC		_MAGIC(0, 22)		/* mips 4000 LE */
+#define	L_MAGIC		_MAGIC(0, 23)		/* dec alpha (retired) */
+#define	P_MAGIC		_MAGIC(0, 24)		/* mips 3000 LE */
+#define	U_MAGIC		_MAGIC(0, 25)		/* sparc64 */
+#define	S_MAGIC		_MAGIC(HDR_MAGIC, 26)	/* amd64 */
+#define	T_MAGIC		_MAGIC(HDR_MAGIC, 27)	/* powerpc64 */
+#define	R_MAGIC		_MAGIC(HDR_MAGIC, 28)	/* arm64 */
+
+#define	MIN_MAGIC	8
+#define	MAX_MAGIC	28			/* <= 90 */
+
+#define	DYN_MAGIC	0x80000000		/* dlm */
+
+typedef	struct	Sym	Sym;
+struct	Sym
+{
+	vlong	value;
+	uint	sig;
+	char	type;
+	char	*name;
+};
+
--- a/include/draw.h
+++ b/include/draw.h
@@ -4,7 +4,7 @@
 typedef struct	Display Display;
 typedef struct	Font Font;
 typedef struct	Fontchar Fontchar;
-typedef struct	Image Image;
+typedef struct	Img Img;
 typedef struct	Mouse Mouse;
 typedef struct	Point Point;
 typedef struct	Rectangle Rectangle;
@@ -155,14 +155,14 @@
 	Point	max;
 };
 
-typedef void	(*Reffn)(Image*, Rectangle, void*);
+typedef void	(*Reffn)(Img*, Rectangle, void*);
 
 struct Screen
 {
 	Display	*display;	/* display holding data */
 	int	id;		/* id of system-held Screen */
-	Image	*image;		/* unused; for reference only */
-	Image	*fill;		/* color to paint behind windows */
+	Img	*image;		/* unused; for reference only */
+	Img	*fill;		/* color to paint behind windows */
 };
 
 struct Display
@@ -180,25 +180,25 @@
 	char		*windir;
 	char		oldlabel[64];
 	ulong		dataqid;
-	Image		*white;
-	Image		*black;
-	Image		*opaque;
-	Image		*transparent;
-	Image		*image;
+	Img		*white;
+	Img		*black;
+	Img		*opaque;
+	Img		*transparent;
+	Img		*image;
 	uchar		*buf;
 	int		bufsize;
 	uchar		*bufp;
 	Font		*defaultfont;
 	Subfont		*defaultsubfont;
-	Image		*windows;
-	Image		*screenimage;
+	Img		*windows;
+	Img		*screenimage;
 	int		_isnewdisplay;
 };
 
-struct Image
+struct Img
 {
 	Display		*display;	/* display holding data */
-	int		id;		/* id of system-held Image */
+	int		id;		/* id of system-held Img */
 	Rectangle	r;		/* rectangle in data area, local coords */
 	Rectangle 	clipr;		/* clipping region */
 	int		depth;		/* number of bits per pixel */
@@ -205,7 +205,7 @@
 	ulong		chan;
 	int		repl;		/* flag: data replicates to tile clipr */
 	Screen		*screen;	/* 0 if not a window */
-	Image		*next;	/* next in list of windows */
+	Img		*next;	/* next in list of windows */
 };
 
 struct RGB
@@ -224,7 +224,7 @@
  *		p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
  *		color, f->bits, Pt(i->x, i->top));
  *	p.x += i->width;
- * to draw characters in the specified color (itself an Image) in Image b.
+ * to draw characters in the specified color (itself an Img) in Img b.
  */
 
 struct	Fontchar
@@ -243,7 +243,7 @@
 	uchar		height;		/* height of image */
 	char		ascent;		/* top of image to baseline */
 	Fontchar 	*info;		/* n+1 character descriptors */
-	Image		*bits;		/* of font */
+	Img		*bits;		/* of font */
 	int		ref;
 };
 
@@ -304,7 +304,7 @@
 	Cacheinfo	*cache;
 	Cachesubf	*subf;
 	Cachefont	**sub;	/* as read from file */
-	Image		*cacheimage;
+	Img		*cacheimage;
 };
 
 #define	Dx(r)	((r).max.x-(r).min.x)
@@ -311,33 +311,33 @@
 #define	Dy(r)	((r).max.y-(r).min.y)
 
 /*
- * Image management
+ * Img management
  */
-extern Image*	_allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int);
-extern Image*	allocimage(Display*, Rectangle, ulong, int, ulong);
+extern Img*	_allocimage(Img*, Display*, Rectangle, ulong, int, ulong, int, int);
+extern Img*	allocimage(Display*, Rectangle, ulong, int, ulong);
 extern uchar*	bufimage(Display*, int);
 extern int	bytesperline(Rectangle, int);
 extern void	closedisplay(Display*);
 extern void	drawerror(Display*, char*);
 extern int	flushimage(Display*, int);
-extern int	freeimage(Image*);
-extern int	_freeimage1(Image*);
+extern int	freeimage(Img*);
+extern int	_freeimage1(Img*);
 extern int	geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
 extern int	initdraw(void(*)(Display*, char*), char*, char*);
 extern int	newwindow(char*);
 extern Display*	initdisplay(char*, char*, void(*)(Display*, char*));
-extern int	loadimage(Image*, Rectangle, uchar*, int);
-extern int	cloadimage(Image*, Rectangle, uchar*, int);
+extern int	loadimage(Img*, Rectangle, uchar*, int);
+extern int	cloadimage(Img*, Rectangle, uchar*, int);
 extern int	getwindow(Display*, int);
-extern int	gengetwindow(Display*, char*, Image**, Screen**, int);
-extern Image* readimage(Display*, int, int);
-extern Image* creadimage(Display*, int, int);
-extern int	unloadimage(Image*, Rectangle, uchar*, int);
+extern int	gengetwindow(Display*, char*, Img**, Screen**, int);
+extern Img* readimage(Display*, int, int);
+extern Img* creadimage(Display*, int, int);
+extern int	unloadimage(Img*, Rectangle, uchar*, int);
 extern int	wordsperline(Rectangle, int);
-extern int	writeimage(int, Image*, int);
-extern Image*	namedimage(Display*, char*);
-extern int	nameimage(Image*, char*, int);
-extern Image* allocimagemix(Display*, ulong, ulong);
+extern int	writeimage(int, Img*, int);
+extern Img*	namedimage(Display*, char*);
+extern int	nameimage(Img*, char*, int);
+extern Img* allocimagemix(Display*, ulong, ulong);
 
 /*
  * Colors
@@ -349,16 +349,16 @@
 /*
  * Windows
  */
-extern Screen*	allocscreen(Image*, Image*, int);
-extern Image*	_allocwindow(Image*, Screen*, Rectangle, int, ulong);
-extern Image*	allocwindow(Screen*, Rectangle, int, ulong);
-extern void	bottomnwindows(Image**, int);
-extern void	bottomwindow(Image*);
+extern Screen*	allocscreen(Img*, Img*, int);
+extern Img*	_allocwindow(Img*, Screen*, Rectangle, int, ulong);
+extern Img*	allocwindow(Screen*, Rectangle, int, ulong);
+extern void	bottomnwindows(Img**, int);
+extern void	bottomwindow(Img*);
 extern int	freescreen(Screen*);
 extern Screen*	publicscreen(Display*, int, ulong);
-extern void	topnwindows(Image**, int);
-extern void	topwindow(Image*);
-extern int	originwindow(Image*, Point, Point);
+extern void	topnwindows(Img**, int);
+extern void	topwindow(Img*);
+extern int	originwindow(Img*, Point, Point);
 
 /*
  * Geometry
@@ -381,7 +381,7 @@
 extern void		combinerect(Rectangle*, Rectangle);
 extern int		rectclip(Rectangle*, Rectangle);
 extern int		ptinrect(Point, Rectangle);
-extern void		replclipr(Image*, int, Rectangle);
+extern void		replclipr(Img*, int, Rectangle);
 extern int		drawreplxy(int, int, int);	/* used to be drawsetxy */
 extern Point	drawrepl(Rectangle, Point);
 extern int		rgb2cmap(int, int, int);
@@ -394,53 +394,53 @@
 /*
  * Graphics
  */
-extern void	draw(Image*, Rectangle, Image*, Image*, Point);
-extern void	drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
-extern void	gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
-extern void	gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
-extern void	line(Image*, Point, Point, int, int, int, Image*, Point);
-extern void	lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
-extern void	poly(Image*, Point*, int, int, int, int, Image*, Point);
-extern void	polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
-extern void	fillpoly(Image*, Point*, int, int, Image*, Point);
-extern void	fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
-extern Point	string(Image*, Point, Image*, Point, Font*, char*);
-extern Point	stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
-extern Point	stringn(Image*, Point, Image*, Point, Font*, char*, int);
-extern Point	stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
-extern Point	runestring(Image*, Point, Image*, Point, Font*, Rune*);
-extern Point	runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
-extern Point	runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
-extern Point	runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
-extern Point	stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
-extern Point	stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
-extern Point	stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
-extern Point	stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
-extern Point	runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
-extern Point	runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
-extern Point	runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
-extern Point	runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
-extern Point	_string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
-extern Point	stringsubfont(Image*, Point, Image*, Subfont*, char*);
-extern int		bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
-extern int		bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
-extern int		bezspline(Image*, Point*, int, int, int, int, Image*, Point);
-extern int		bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
-extern int		bezsplinepts(Point*, int, Point**);
-extern int		fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
-extern int		fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
-extern int		fillbezspline(Image*, Point*, int, int, Image*, Point);
-extern int		fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
-extern void	ellipse(Image*, Point, int, int, int, Image*, Point);
-extern void	ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
-extern void	fillellipse(Image*, Point, int, int, Image*, Point);
-extern void	fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
-extern void	arc(Image*, Point, int, int, int, Image*, Point, int, int);
-extern void	arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
-extern void	fillarc(Image*, Point, int, int, Image*, Point, int, int);
-extern void	fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
-extern void	border(Image*, Rectangle, int, Image*, Point);
-extern void	borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+extern void	draw(Img*, Rectangle, Img*, Img*, Point);
+extern void	drawop(Img*, Rectangle, Img*, Img*, Point, Drawop);
+extern void	gendraw(Img*, Rectangle, Img*, Point, Img*, Point);
+extern void	gendrawop(Img*, Rectangle, Img*, Point, Img*, Point, Drawop);
+extern void	line(Img*, Point, Point, int, int, int, Img*, Point);
+extern void	lineop(Img*, Point, Point, int, int, int, Img*, Point, Drawop);
+extern void	poly(Img*, Point*, int, int, int, int, Img*, Point);
+extern void	polyop(Img*, Point*, int, int, int, int, Img*, Point, Drawop);
+extern void	fillpoly(Img*, Point*, int, int, Img*, Point);
+extern void	fillpolyop(Img*, Point*, int, int, Img*, Point, Drawop);
+extern Point	string(Img*, Point, Img*, Point, Font*, char*);
+extern Point	stringop(Img*, Point, Img*, Point, Font*, char*, Drawop);
+extern Point	stringn(Img*, Point, Img*, Point, Font*, char*, int);
+extern Point	stringnop(Img*, Point, Img*, Point, Font*, char*, int, Drawop);
+extern Point	runestring(Img*, Point, Img*, Point, Font*, Rune*);
+extern Point	runestringop(Img*, Point, Img*, Point, Font*, Rune*, Drawop);
+extern Point	runestringn(Img*, Point, Img*, Point, Font*, Rune*, int);
+extern Point	runestringnop(Img*, Point, Img*, Point, Font*, Rune*, int, Drawop);
+extern Point	stringbg(Img*, Point, Img*, Point, Font*, char*, Img*, Point);
+extern Point	stringbgop(Img*, Point, Img*, Point, Font*, char*, Img*, Point, Drawop);
+extern Point	stringnbg(Img*, Point, Img*, Point, Font*, char*, int, Img*, Point);
+extern Point	stringnbgop(Img*, Point, Img*, Point, Font*, char*, int, Img*, Point, Drawop);
+extern Point	runestringbg(Img*, Point, Img*, Point, Font*, Rune*, Img*, Point);
+extern Point	runestringbgop(Img*, Point, Img*, Point, Font*, Rune*, Img*, Point, Drawop);
+extern Point	runestringnbg(Img*, Point, Img*, Point, Font*, Rune*, int, Img*, Point);
+extern Point	runestringnbgop(Img*, Point, Img*, Point, Font*, Rune*, int, Img*, Point, Drawop);
+extern Point	_string(Img*, Point, Img*, Point, Font*, char*, Rune*, int, Rectangle, Img*, Point, Drawop);
+extern Point	stringsubfont(Img*, Point, Img*, Subfont*, char*);
+extern int		bezier(Img*, Point, Point, Point, Point, int, int, int, Img*, Point);
+extern int		bezierop(Img*, Point, Point, Point, Point, int, int, int, Img*, Point, Drawop);
+extern int		bezspline(Img*, Point*, int, int, int, int, Img*, Point);
+extern int		bezsplineop(Img*, Point*, int, int, int, int, Img*, Point, Drawop);
+extern int		bezsplinepts(Point*, int, Point**);
+extern int		fillbezier(Img*, Point, Point, Point, Point, int, Img*, Point);
+extern int		fillbezierop(Img*, Point, Point, Point, Point, int, Img*, Point, Drawop);
+extern int		fillbezspline(Img*, Point*, int, int, Img*, Point);
+extern int		fillbezsplineop(Img*, Point*, int, int, Img*, Point, Drawop);
+extern void	ellipse(Img*, Point, int, int, int, Img*, Point);
+extern void	ellipseop(Img*, Point, int, int, int, Img*, Point, Drawop);
+extern void	fillellipse(Img*, Point, int, int, Img*, Point);
+extern void	fillellipseop(Img*, Point, int, int, Img*, Point, Drawop);
+extern void	arc(Img*, Point, int, int, int, Img*, Point, int, int);
+extern void	arcop(Img*, Point, int, int, int, Img*, Point, int, int, Drawop);
+extern void	fillarc(Img*, Point, int, int, Img*, Point, int, int);
+extern void	fillarcop(Img*, Point, int, int, Img*, Point, int, int, Drawop);
+extern void	border(Img*, Rectangle, int, Img*, Point);
+extern void	borderop(Img*, Rectangle, int, Img*, Point, Drawop);
 
 /*
  * Font management
@@ -451,13 +451,13 @@
 extern Font*	mkfont(Subfont*, Rune);
 extern int	cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
 extern void	agefont(Font*);
-extern Subfont*	allocsubfont(char*, int, int, int, Fontchar*, Image*);
+extern Subfont*	allocsubfont(char*, int, int, int, Fontchar*, Img*);
 extern Subfont*	lookupsubfont(Display*, char*);
 extern void	installsubfont(char*, Subfont*);
 extern void	uninstallsubfont(Subfont*);
 extern void	freesubfont(Subfont*);
 extern Subfont*	readsubfont(Display*, char*, int, int);
-extern Subfont*	readsubfonti(Display*, char*, int, Image*, int);
+extern Subfont*	readsubfonti(Display*, char*, int, Img*, int);
 extern int	writesubfont(int, Subfont*);
 extern void	_unpackinfo(Fontchar*, uchar*, int);
 extern Point	stringsize(Font*, char*);
@@ -487,7 +487,7 @@
  */
 extern	Display	*display;
 extern	Font		*font;
-// extern	Image	*screen;
+// extern	Img	*screen;
 extern	Screen	*_screen;
 extern	int	_cursorfd;
 extern	void	_setdrawop(Display*, Drawop);
--- a/include/lib.h
+++ b/include/lib.h
@@ -227,6 +227,29 @@
 	ulong	flags;
 };
 
+typedef struct Tos Tos;
+typedef struct Plink Plink;
+
+struct Tos {
+	struct				/* Per process profiling */
+	{
+		Plink		*pp;	/* known to be 0(ptr) */
+		Plink		*next;	/* known to be 4(ptr) */
+		Plink		*last;
+		Plink		*first;
+		u32int	pid;
+		u32int	what;
+	} prof;
+	u64int	cyclefreq;	/* cycle clock frequency if there is one, 0 otherwise */
+	ulong	kcycles;	/* cycles spent in kernel */
+	ulong	pcycles;	/* cycles spent in process (kernel + user) */
+	u32int	pid;		/* might as well put the pid here */
+	u32int	clock;
+	/* top of stack is here */
+};
+
+extern Tos *_tos;
+
 enum{
 	FmtWidth	= 1,
 	FmtLeft		= FmtWidth << 1,
@@ -291,6 +314,10 @@
 extern	int	getfields(char*, char**, int, int, char*);
 extern	char*	utfecpy(char*, char*, char*);
 extern	int	tas(int*);
+extern  int trampoline(void*);
+extern  void run(uintptr_t, Tos *, int, char **);
+extern  long sysintercept(void*, void*, void*, void*, void*, void*, void*);
+extern  int patch(void*, int);
 extern	void	quotefmtinstall(void);
 extern	int	dec64(uchar*, int, char*, int);
 extern	int	enc64(char*, int, uchar*, int);
@@ -316,7 +343,6 @@
 extern	int	__isInf(double, int);
 
 extern int (*fmtdoquote)(int);
-
 
 /*
  * Time-of-day
--- a/include/u.h
+++ b/include/u.h
@@ -10,9 +10,11 @@
 #undef close
 #undef create
 #undef dup
+#undef exec
 #undef export
 #undef fstat
 #undef fwstat
+#undef memchr
 #undef mount
 #undef open
 #undef start
--- a/include/user.h
+++ b/include/user.h
@@ -1,4 +1,4 @@
-/* sys calls */
+/* sys calls */ 
 #define	bind	sysbind
 #define	chdir	syschdir
 #define	close	sysclose
@@ -5,11 +5,13 @@
 #define create	syscreate
 #define dup	    sysdup
 #define export	sysexport
+#define exec    sysexec
 #define getwd   sysgetwd
 #define fd2path sysfd2path
 #define fstat	sysfstat
 #define fwstat	sysfwstat
 #define mount	sysmount
+#define memchr  sysmemchr
 #define	open	sysopen
 #define read	sysread
 #define remove	sysremove
@@ -38,10 +40,12 @@
 extern	int	create(char*, int, ulong);
 extern	int	dup(int, int);
 extern  int	export(int);
+extern  int exec(int, char**);
 extern  int fd2path(int, char*, int);
 extern	int	fstat(int, uchar*, int);
 extern	int	fwstat(int, uchar*, int);
 extern  char* getwd(char *, int);
+extern  void* memchr(void *, int, ulong);
 extern	int	mount(int, int, char*, int, char*);
 extern	int	unmount(char*, char*);
 extern	int	open(char*, int);
@@ -64,7 +68,6 @@
 extern	long	dirread(int, Dir**);
 extern  long    dirreadall(int, Dir**);
 extern	ulong	iounit(int);
-
 extern	int	lfdfd(int);
 
 /*
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -23,16 +23,18 @@
 	dirread.$O\
 	error.$O\
 	getwd.$O\
+	memchr.$O\
 	parse.$O\
 	pgrp.$O\
 	postnote.$O\
 	procinit.$O\
 	notify.$O\
-	rfork.$O\
 	rwlock.$O\
 	sleep.$O\
 	stub.$O\
+	syscall.$O\
 	sysfile.$O\
+	sysproc.$O\
 	time.$O\
 	qio.$O\
 	qlock.$O\
@@ -46,5 +48,5 @@
 	$(RANLIB) $(LIB)
 
 %.$O: %.c
-	$(CC) $(CFLAGS) $*.c
+	$(CC) $(CFLAGS) -I../$(OS)-$(ARCH) $*.c
 
--- a/kern/allocb.c
+++ b/kern/allocb.c
@@ -3,6 +3,7 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"error.h"
+#include	"mem.h"
 
 enum
 {
--- a/kern/chan.c
+++ b/kern/chan.c
@@ -1158,8 +1158,8 @@
 {
 	int len, n, t, nomount;
 	Chan *c;
-	Chan *volatile cnew;
-	Path *volatile path;
+	Chan */*volatile*/ cnew;
+	Path */*volatile*/ path;
 	Elemlist e;
 	Rune r;
 	Mhead *m;
@@ -1520,8 +1520,8 @@
 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
-	['/']	1,
-	[0x7f]	1,
+	['/']=	1,
+	[0x7f]=	1,
 };
 
 /*
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -1,7 +1,7 @@
 #define	KNAMELEN		28	/* max length of name held in kernel */
 
-#define	BLOCKALIGN		8
-
+//#define	BLOCKALIGN		8
+typedef struct Binary	Binary;
 typedef struct Block	Block;
 typedef struct Chan	Chan;
 typedef struct Cmdbuf	Cmdbuf;
@@ -30,6 +30,7 @@
 typedef struct Rendez	Rendez;
 typedef struct Rgrp	Rgrp;
 typedef struct RWlock	RWlock;
+typedef struct Segment  Segment;
 typedef struct Waitq	Waitq;
 typedef struct Walkqid	Walkqid;
 typedef struct Kmesg	Kmesg;
@@ -119,6 +120,18 @@
 	Bpktck	=	(1<<5),		/* packet checksum */
 };
 
+/* Not using segments, so this is our holder */
+struct Binary
+{
+	uintptr entry;
+	uintptr text;
+	uintptr data;
+	uintptr bssz;
+	uintptr ts;
+	uintptr ds;
+	uintptr bss;
+};
+
 struct Block
 {
 	Block*	next;
@@ -224,6 +237,7 @@
 	NSMAX	=	1000,
 	NSLOG	=	7,
 	NSCACHE	=	(1<<NSLOG),
+	NNOTE   =   5,
 };
 
 struct Mntwalk				/* state for /proc/#/ns */
@@ -340,6 +354,15 @@
 
 typedef uvlong	Ticks;
 
+enum {
+	SEGTEXT,
+	SEGDATA,
+	SEGBSS,
+	SEGSTACK,
+	SEGNUM = 8,
+};
+
+
 enum
 {
 	Running,
@@ -367,7 +390,7 @@
 	void*	rendtag;	/* Tag for rendezvous */
 	void*	rendval;	/* Value for rendezvous */
 	Proc	*rendhash;	/* Hash list for tag values */
-
+	
 	int	nerrlab;
 	Label	errlab[NERR];
 	char	user[KNAMELEN];
@@ -378,16 +401,40 @@
 	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
 	char	text[KNAMELEN];
 
+	u32int lladdr;		/* LL/SC emulation */
+	u32int llval;
+
+
+	/* Notes */
+	u32int notehandler;
+	int innote;
+	jmp_buf notejmp;
+	char notes[ERRMAX][NNOTE];
+	long notein, noteout;
 	Chan	*slash;
 	Chan	*dot;
 
 	Proc	*qnext;
+	Binary  *bin;
 
 	void	(*fn)(void*);
 	void	*arg;
 
 	char oproc[1024];	/* reserved for os */
+	u32int CPSR;		/* status register for step */
+	/* TODO: Multiarch */
+	u32int R[16];		/* general purpose registers / PC (R15) */
+	Segment *S[SEGNUM];
+};
 
+
+struct Segment {
+	Ref ref;
+	int flags;
+	RWlock rw; /* lock for SEGFLLOCK segments */
+	u32int start, size;
+	void *data;
+	Ref *dref;
 };
 
 enum
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -1,4 +1,4 @@
-#define	ROUND(s, sz)	(((s)+((sz)-1))&~((sz)-1))
+//#define	ROUND(s, sz)	(((s)+((sz)-1))&~((sz)-1))
 
 Block*		adjustblock(Block*, int);
 Block*		allocb(int);
@@ -60,6 +60,7 @@
 void		error(char*);
 void		exhausted(char*);
 void		exit(int);
+void        fdclose(int, int);
 Chan*		fdtochan(int, int, int, int);
 void		free(void*);
 void		freeb(Block*);
@@ -206,11 +207,11 @@
 Block*		trimblock(Block*, int, int);
 long		unionread(Chan*, void*, long);
 void		unlock(Lock*);
-#define	validaddr(a, b, c)
+#define	    validaddr(one, two, three);
 void		validname(char*, int);
 char*		validnamedup(char*, int);
 void		validstat(uchar*, int);
-void*		vmemchr(void*, int, int);
+void*		vmemchr(void*, int, ulong);
 Proc*		wakeup(Rendez*);
 int		walk(Chan**, char**, int, int, int*);
 #define	waserror()	(setjmp(pwaserror()->buf))
@@ -220,7 +221,13 @@
 void		osmsleep(int);
 ulong	ticks(void);
 void	osproc(Proc*);
+void    osexec(Proc*);
+void    osbuildtext(Chan *);
+void    osbuilddata(Chan *);
+void    osbuildbss(Chan *);
+void    ospatchtext(void);
 void	osnewproc(Proc*);
+void    osclrmem(void);
 void	procsleep(void);
 void	procwakeup(Proc*);
 void	osinit(void);
--- /dev/null
+++ b/kern/memchr.c
@@ -1,0 +1,20 @@
+#include	<u.h>
+#include	<libc.h>
+
+void*
+sysmemchr(void *ap, int c, ulong n)
+{
+	uchar *sp;
+	ulong i;
+
+	i = n;
+	
+	sp = (uchar *)ap;
+	c &= 0xFF;
+	while(i > 0) {
+		if(*sp++ == c)
+			return sp-1;
+		i--;
+	}
+	return 0;
+}
\ No newline at end of file
--- a/kern/parse.c
+++ b/kern/parse.c
@@ -35,7 +35,7 @@
 Cmdbuf*
 parsecmd(char *p, int n)
 {
-	Cmdbuf *volatile cb;
+	Cmdbuf */*volatile*/ cb;
 	int nf;
 	char *sp;
 
--- a/kern/posix.c
+++ b/kern/posix.c
@@ -13,6 +13,7 @@
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <sys/select.h>
+#include <sys/mman.h>
 #include <signal.h>
 #include <pwd.h>
 #include <errno.h>
@@ -21,6 +22,8 @@
 #include "lib.h"
 #include "dat.h"
 #include "fns.h"
+#include "mem.h"
+#include <a.out.h>
 
 typedef struct Oproc Oproc;
 struct Oproc
@@ -112,7 +115,6 @@
 tramp(void *vp)
 {
 	Proc *p;
-
 	p = vp;
 	if(pthread_setspecific(prdakey, p))
 		panic("cannot setspecific");
@@ -131,6 +133,111 @@
 		panic("osproc: %r");
 	}
 	sched_yield();
+}
+
+static void*
+trex(void *vp)
+{
+	Proc *p;
+	Tos tos;
+	int argc;
+
+	p = vp;
+	tos.pid = p->pid;
+	argc = nelem((char**)p->arg);
+	if(pthread_setspecific(prdakey, p))
+		panic("cannot setspecific");
+	run(up->bin->text, &tos, argc, p->arg);
+	pexit("", 0);
+	return 0;
+}
+
+void
+osexec(Proc *p)
+{
+	pthread_t pid;
+	if(pthread_create(&pid, nil, trex, p)){
+		oserrstr();
+		panic("osexec: %r");
+	}
+	pthread_join(pid, nil);
+}
+
+void
+osclrmem(void)
+{
+	/* Clean up text, data, bss */
+	if(up->bin->text)
+		munmap((void*)up->bin->text, up->bin->ts);
+	if(up->bin->data)
+		munmap((void*)up->bin->data, up->bin->ds);
+	if(up->bin->bss)
+		munmap((void*)up->bin->bss, up->bin->bssz);
+}
+
+void
+osbuildtext(Chan *tc)
+{
+	int n;
+	void *text;
+
+	//text = mmap(nil, up->bin->ts, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+	text = mallocz(up->bin->ts, 1);
+	n = devtab[tc->type]->read(tc, text, up->bin->ts, 0);
+	if(!text || n == 0)
+		error("unable to set up text segment");
+	/* Stash this in text for now, we will be moving and rewriting in the patch */
+	up->bin->text = (uintptr)text;
+}
+
+void
+ospatchtext(void)
+{
+	int n;
+	void *text, *final;
+
+	/* Set up trampoline. Mach dependent */
+	text = mallocz(TRAMPSIZE, 1);
+	n = trampoline(text);
+	if(n != TRAMPSIZE)
+		error("building trampoline failed");
+
+	final = mmap(0, (up->bin->ts)+n, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+	memmove(final, text, n);
+	memmove(final+n+1, (void*)up->bin->text, up->bin->ts);
+	if(!final)
+		error("unable to set up text segment with trampoline");
+
+	/* Patch. Mach dependent */
+	if(patch(final+n+1, up->bin->ts) < 0)
+		error("unable to patch syscalls");
+	mprotect(final, n, PROT_EXEC);
+	up->bin->text = (uintptr)final+n+1;
+	poperror();
+}
+
+void
+osbuilddata(Chan *tc)
+{
+	int n;
+	void *data;
+
+	data = mmap((void*)up->bin->data, up->bin->ds, PROT_READ| PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+	n = devtab[tc->type]->read(tc, data, up->bin->ds, up->bin->ts);
+	if(!data || n == 0)
+		error("unable to set up data segment");
+	//up->bin->data = (uintptr)data;
+}
+
+void
+osbuildbss(Chan *tc)
+{
+	void *bss;
+	// BSS - set it up in READ/WRITE
+	bss = mmap((void*)up->bin->bss, up->bin->bssz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+	if(!bss)
+		error("unable to set up bss segment");
+	//up->bin->bss = (uintptr)bss;
 }
 
 void
--- a/kern/procinit.c
+++ b/kern/procinit.c
@@ -3,6 +3,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "error.h"
+#include "mem.h"
 
 void
 procinit0(void)
--- a/kern/rfork.c
+++ /dev/null
@@ -1,127 +1,0 @@
-#include <u.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <libc.h>
-#undef rfork
-
-static void
-nop(int x)
-{
-	USED(x);
-}
-
-int
-sysrfork(int flags)
-{
-	int pid, status;
-	int p[2];
-	int n;
-	char buf[128], *q;
-	extern char **environ;
-	struct sigaction oldchld;
-
-	memset(&oldchld, 0, sizeof oldchld);
-
-	if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
-		/* check other flags before we commit */
-		flags &= ~(RFPROC|RFFDG|RFENVG);
-		n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
-		if(n){
-			werrstr("unknown flags %08ux in rfork", n);
-			return -1;
-		}
-		if(flags&RFNOWAIT){
-			sigaction(SIGCHLD, nil, &oldchld);
-			signal(SIGCHLD, nop);
-			if(pipe(p) < 0)
-				return -1;
-		}
-		pid = fork();
-		if(pid == -1)
-			return -1;
-		if(flags&RFNOWAIT){
-			flags &= ~RFNOWAIT;
-			if(pid){
-				/*
-				 * Parent - wait for child to fork wait-free child.
-				 * Then read pid from pipe.  Assume pipe buffer can absorb the write.
-				 */
-				close(p[1]);
-				status = 0;
-				if(wait4(pid, &status, 0, 0) < 0){
-					werrstr("pipe dance - wait4 - %r");
-					close(p[0]);
-					return -1;
-				}
-				n = readn(p[0], buf, sizeof buf-1);
-				close(p[0]);
-				if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
-					if(!WIFEXITED(status))
-						werrstr("pipe dance - !exited 0x%ux", status);
-					else if(WEXITSTATUS(status) != 0)
-						werrstr("pipe dance - non-zero status 0x%ux", status);
-					else if(n < 0)
-						werrstr("pipe dance - pipe read error - %r");
-					else if(n == 0)
-						werrstr("pipe dance - pipe read eof");
-					else
-						werrstr("pipe dance - unknown failure");
-					return -1;
-				}
-				buf[n] = 0;
-				if(buf[0] == 'x'){
-					werrstr("%s", buf+2);
-					return -1;
-				}
-				pid = strtol(buf, &q, 0);
-			}else{
-				/*
-				 * Child - fork a new child whose wait message can't
-				 * get back to the parent because we're going to exit!
-				 */
-				signal(SIGCHLD, SIG_IGN);
-				close(p[0]);
-				pid = fork();
-				if(pid){
-					/* Child parent - send status over pipe and exit. */
-					if(pid > 0)
-						fprint(p[1], "%d", pid);
-					else
-						fprint(p[1], "x %r");
-					close(p[1]);
-					_exit(0);
-				}else{
-					/* Child child - close pipe. */
-					close(p[1]);
-				}
-			}
-			sigaction(SIGCHLD, &oldchld, nil);
-		}
-		if(pid != 0)
-			return pid;
-		if(flags&RFCENVG)
-			if(environ)
-				*environ = nil;
-	}
-	if(flags&RFPROC){
-		werrstr("cannot use rfork for shared memory -- use libthread");
-		return -1;
-	}
-	if(flags&RFNAMEG){
-		/* XXX set $NAMESPACE to a new directory */
-		flags &= ~RFNAMEG;
-	}
-	if(flags&RFNOTEG){
-		setpgid(0, getpid());
-		flags &= ~RFNOTEG;
-	}
-	if(flags&RFNOWAIT){
-		werrstr("cannot use RFNOWAIT without RFPROC");
-		return -1;
-	}
-	if(flags){
-		werrstr("unknown flags %08ux in rfork", flags);
-		return -1;
-	}
-	return 0;
-}
--- a/kern/stub.c
+++ b/kern/stub.c
@@ -60,6 +60,7 @@
 	USED(tag);
 }
 
+/* TODO: We may want notes */
 int
 postnote(Proc *p, int x, char *msg, int flag)
 {
--- /dev/null
+++ b/kern/syscall.c
@@ -1,0 +1,95 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "user.h"
+
+long
+sysintercept(void* r0, void* r1, void* r2, void* r3, void* r4, void* r5, void* r6)
+{
+    print("Interception %d\n", r0);
+    long ret = -1;
+    switch((int)r0){
+        case 0: /* SYSR1 */
+            ret = 0;
+            break;
+        case 1: /* _ERRSTR */
+            ret = errstr((char*)r1, 64);
+            break;
+        case 2: /* BIND */
+            ret = bind((char*) r1, (char*)r2, (int) r3);
+            break;
+        case 3: /* CHDIR */
+            ret = chdir((char *)r1);
+            break;
+        case 4: /* CLOSE */
+            ret = close((int)r1);
+            break;
+        case 5: /* DUP */
+            ret = dup((int)r1, (int)r2);
+            break;
+    	case 6: /* ALARM */
+            ret = alarm((int) r1);
+            break;
+        case 7: /* EXEC */
+            ret = exec((int) r1, (char**)r2);
+            break;
+        case 8: /* EXITS */
+            exits((char*)r1);
+            ret = 0;
+            break;
+        case 9: /* _FSESSION */
+            //ret = fsession();
+            break;
+        case 10: /* FAUTH */
+            // ret = fauth();
+            break;
+        case 11: /* _FSTAT */
+            ret = fstat((int) r1, (char*) r2, (int)r3);
+            break;  
+        case 12: /* SEGBRK */
+        case 13: /* _MOUNT */
+        case 14: /* OPEN */
+        case 15: /* _READ */
+        case 16: /* OSEEK */
+        case 17: /* SLEEP */
+        case 18: /* _STAT */
+        case 19: /* RFORK */
+        case 20: /* _WRITE */
+        case 21: /* PIPE */
+        case 22: /* CREATE */
+        case 23: /* FD2PATH */
+        case 24: /* BRK_ */
+        case 25: /* REMOVE */
+        case 26: /* _WSTAT */
+        case 27: /* _FWSAT */
+        case 28: /* NOTIFY */
+        case 29: /* NOTED */
+        case 30: /* SEGATTACH */
+        case 31: /* SEGDETACH */
+        case 32: /* SEGFREE */
+        case 33: /* SEGFLUSH */
+        case 34: /* RENDEZVOUS */
+        case 35: /* UNMOUNT */
+        case 36: /* _WAIT */
+        case 37: /* SEMACQUIRE */
+        case 38: /* SEMRELEASE */
+        case 39: /* SEEK */
+        case 40: /* FVERSION */
+        case 41: /* ERRSTR */
+        case 42: /* STAT */
+        case 43: /* FSTAT */
+        case 44: /* WSTAT */
+        case 45: /* FWSTAT */
+        case 46: /* MOUNT */
+        case 47: /* AWAIT */
+        case 50: /* PREAD */
+        case 51: /* PWRITE */
+        case 52: /* TSEMACQUIRE */
+        case 53: /* _NSEC */
+            break;
+    }
+
+    return ret;
+}
--- a/kern/sysfile.c
+++ b/kern/sysfile.c
@@ -18,6 +18,8 @@
 #undef fstat
 #undef fwstat
 #undef iounit
+#undef validaddr
+#define validaddr(a, b, c)
 
 /*
  * The sys*() routines needn't poperror() as they return directly to syscall().
@@ -293,8 +295,8 @@
 	return fd;
 }
 
-static void
-_fdclose(int fd, int flag)
+void
+fdclose(int fd, int flag)
 {
 	int i;
 	Chan *c;
@@ -326,7 +328,7 @@
 _sysclose(int fd)
 {
 	fdtochan(fd, -1, 0, 0);
-	_fdclose(fd, 0);
+	fdclose(fd, 0);
 
 	return 0;
 }
@@ -589,7 +591,7 @@
 	uint l;
 
 	l = n;
-	validaddr(buf, l, 1);
+	validaddr((uintptr)buf, l, 1);
 	c = fdtochan(fd, -1, 0, 1);
 	if(waserror()) {
 		cclose(c);
@@ -608,8 +610,8 @@
 	uint l;
 
 	l = n;
-	validaddr(buf, l, 1);
-	validaddr(name, 1, 0);
+	validaddr((uintptr)buf, l, 1);
+	validaddr((uintptr)name, 1, 0);
 	c = namec(name, Aaccess, 0, 0);
 	if(waserror()){
 		cclose(c);
@@ -626,7 +628,7 @@
 {
 	Chan *c;
 
-	validaddr(name, 1, 0);
+	validaddr((uintptr)name, 1, 0);
 
 	c = namec(name, Atodir, 0, 0);
 	cclose(up->dot);
@@ -696,7 +698,7 @@
 	poperror();
 	cclose(c0);
 	if(ismount){
-		_fdclose(fd, 0);
+		fdclose(fd, 0);
 		poperror();
 		free(spec);
 	}
@@ -729,7 +731,7 @@
 			cclose(cmount);
 			nexterror();
 		}
-		validaddr(old, 1, 0);
+		validaddr((uintptr)old, 1, 0);
 		/*
 		 * This has to be namec(..., Aopen, ...) because
 		 * if arg[0] is something like /srv/cs or /fd/0,
@@ -767,7 +769,7 @@
 			cclose(c);
 		nexterror();
 	}
-	validaddr(name, 1, 0);
+	validaddr((uintptr)name, 1, 0);
 	c = namec(name, Acreate, mode, perm);
 	fd = newfd(c);
 	if(fd < 0)
@@ -806,7 +808,7 @@
 
 	l = n;
 	validstat(buf, l);
-	validaddr(name, 1, 0);
+	validaddr((uintptr)name, 1, 0);
 	c = namec(name, Aaccess, 0, 0);
 	if(waserror()){
 		cclose(c);
@@ -825,7 +827,7 @@
 	uint l;
 
 	l = n;
-	validaddr(buf, l, 0);
+	validaddr((uintptr)buf, l, 0);
 	validstat(buf, l);
 	c = fdtochan(fd, -1, 1, 1);
 	if(waserror()) {
--- /dev/null
+++ b/kern/sysproc.c
@@ -1,0 +1,353 @@
+#include    "u.h"
+#include    "lib.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+#include    "user.h"
+#include	"mem.h"
+#include    <a.out.h>
+#include 	<signal.h>
+#include    <sys/mman.h>
+
+#undef rfork
+
+static void
+nop(int x)
+{
+	USED(x);
+}
+
+int
+sysrfork(int flags)
+{
+	int pid, status;
+	int p[2];
+	int n;
+	char buf[128], *q;
+	extern char **environ;
+	struct sigaction oldchld;
+
+	memset(&oldchld, 0, sizeof oldchld);
+
+	if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
+		/* check other flags before we commit */
+		flags &= ~(RFPROC|RFFDG|RFENVG);
+		n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
+		if(n){
+			werrstr("unknown flags %08ux in rfork", n);
+			return -1;
+		}
+		if(flags&RFNOWAIT){
+			sigaction(SIGCHLD, nil, &oldchld);
+			signal(SIGCHLD, nop);
+			if(pipe(p) < 0)
+				return -1;
+		}
+		pid = fork();
+		if(pid == -1)
+			return -1;
+		if(flags&RFNOWAIT){
+			flags &= ~RFNOWAIT;
+			if(pid){
+				/*
+				 * Parent - wait for child to fork wait-free child.
+				 * Then read pid from pipe.  Assume pipe buffer can absorb the write.
+				 */
+				close(p[1]);
+				status = 0;
+				if(wait4(pid, &status, 0, 0) < 0){
+					werrstr("pipe dance - wait4 - %r");
+					close(p[0]);
+					return -1;
+				}
+				n = readn(p[0], buf, sizeof buf-1);
+				close(p[0]);
+				if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+					if(!WIFEXITED(status))
+						werrstr("pipe dance - !exited 0x%ux", status);
+					else if(WEXITSTATUS(status) != 0)
+						werrstr("pipe dance - non-zero status 0x%ux", status);
+					else if(n < 0)
+						werrstr("pipe dance - pipe read error - %r");
+					else if(n == 0)
+						werrstr("pipe dance - pipe read eof");
+					else
+						werrstr("pipe dance - unknown failure");
+					return -1;
+				}
+				buf[n] = 0;
+				if(buf[0] == 'x'){
+					werrstr("%s", buf+2);
+					return -1;
+				}
+				pid = strtol(buf, &q, 0);
+			}else{
+				/*
+				 * Child - fork a new child whose wait message can't
+				 * get back to the parent because we're going to exit!
+				 */
+				signal(SIGCHLD, SIG_IGN);
+				close(p[0]);
+				pid = fork();
+				if(pid){
+					/* Child parent - send status over pipe and exit. */
+					if(pid > 0)
+						fprint(p[1], "%d", pid);
+					else
+						fprint(p[1], "x %r");
+					close(p[1]);
+					_exit(0);
+				}else{
+					/* Child child - close pipe. */
+					close(p[1]);
+				}
+			}
+			sigaction(SIGCHLD, &oldchld, nil);
+		}
+		if(pid != 0)
+			return pid;
+		if(flags&RFCENVG)
+			if(environ)
+				*environ = nil;
+	}
+	if(flags&RFPROC){
+		werrstr("cannot use rfork for shared memory -- use libthread");
+		return -1;
+	}
+	if(flags&RFNAMEG){
+		/* XXX set $NAMESPACE to a new directory */
+		flags &= ~RFNAMEG;
+	}
+	if(flags&RFNOTEG){
+		setpgid(0, getpid());
+		flags &= ~RFNOTEG;
+	}
+	if(flags&RFNOWAIT){
+		werrstr("cannot use RFNOWAIT without RFPROC");
+		return -1;
+	}
+	if(flags){
+		werrstr("unknown flags %08ux in rfork", flags);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+shargs(char *s, int n, char **ap, int nap)
+{
+	char *p;
+	int i;
+
+	if(n <= 2 || s[0] != '#' || s[1] != '!')
+		return -1;
+	s += 2;
+	n -= 2;		/* skip #! */
+	if((p = memchr(s, '\n', n)) == nil)
+		return 0;
+	*p = 0;
+	i = tokenize(s, ap, nap-1);
+	ap[i] = nil;
+	return i;
+}
+
+ulong
+beswal(ulong l)
+{
+	uchar *p;
+
+	p = (uchar*)&l;
+	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+uvlong
+beswav(uvlong v)
+{
+	uchar *p;
+
+	p = (uchar*)&v;
+	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
+				  | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
+				  | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
+				  | (uvlong)p[7];
+}
+
+void
+evenaddr(uintptr addr)
+{
+	if(addr & 3){
+		postnote(up, 1, "sys: odd address", NDebug);
+		error(Ebadarg);
+	}
+}
+
+/*
+ * &s[0] is known to be a valid address.
+ */
+void*
+vmemchr(void *s, int c, ulong n)
+{
+	uintptr a;
+	ulong m, i;
+	void *t;
+
+	i = n;
+	a = (uintptr)s;
+	for(;;){
+		m = BY2PG - (a & (BY2PG-1));
+		if(i <= m)
+			break;
+		/* spans pages; handle this page */
+		t = memchr((void*)a, c, m);
+		if(t != nil)
+			return t;
+		a += m;
+		i -= m;
+		if(a < KZERO)
+			validaddr(a, 1, 0);
+	}
+	/* fits in one page */
+	return memchr((void*)a, c, i);
+}
+
+#undef read
+int
+sysexec(int argc, char **argv)
+{
+	union {
+		struct {
+			Exec ex;
+			uvlong	hdr[1];
+		} ehdr;
+		char buf[256];
+	} u;
+
+	char line[256];
+	char *progarg[32+1];
+	char *file, *elem;
+	Chan *tc;
+	ulong magic;
+	uintptr align, bssend;
+	int n, indir;
+
+	elem = nil;
+	align = BY2PG-1;
+	indir = 0;
+	file = argv[0];
+	up->bin = mallocz(sizeof(Binary*), 1);
+
+	for(;;){
+		tc = namec(file, Aopen, OEXEC, 0);
+		if(waserror()){
+			cclose(tc);
+			nexterror();
+		}
+		if(!indir)
+			kstrdup(&elem, up->genbuf);
+		n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
+		if (n >= sizeof(Exec)){
+			magic = beswal(u.ehdr.ex.magic);
+			if(magic & AOUT_MAGIC) {
+				if(magic & HDR_MAGIC){
+					if(n < sizeof(u.ehdr))
+						error(Ebadexec);
+					up->bin->entry = beswav(u.ehdr.hdr[0]);
+					up->bin->text = UTZERO+sizeof(u.ehdr);
+				} else {
+					up->bin->entry = beswal(u.ehdr.ex.entry);
+					up->bin->text = UTZERO+sizeof(Exec);
+				}
+				if(up->bin->entry < up->bin->text)
+					error(Ebadexec);
+				up->bin->text += beswal(u.ehdr.ex.text);
+				// BUG: This errors, errors seem broken currently
+//				if(text <= entry || text >= (uintptr)(USTKTOP-USTKSIZE))
+//					error(Ebadexec);
+				switch(magic){
+				case S_MAGIC:	/* 2MB segment alignment for amd64 */
+					align = 0x1fffff;
+					break;
+				case P_MAGIC:	/* 16K segment alignment for spim */
+				case V_MAGIC:	/* 16K segment alignment for mips */
+					align = 0x3fff;
+					break;
+				case R_MAGIC:	/* 64K segment alignment for arm64 */
+					align = 0xffff;
+					break;
+				}
+				up->arg = argv;
+				break; /* for binary */
+			}
+		}
+		if(indir++)
+			error(Ebadexec);
+
+		/* Process #!/bin/sh args */
+		memmove(line, u.buf, n);
+		n = shargs(line, n, progarg, nelem(progarg));
+		if(n < 1)
+			error(Ebadexec);
+
+		progarg[n++] = file;
+		progarg[n] = nil;
+		argv++;
+		file = progarg[0];
+		progarg[0] = elem;
+		strcpy(up->text, elem);
+		poperror();
+		cclose(tc);
+		// Check the actual sysproc, there's some missing bits here still
+		up->arg = progarg;
+	}
+
+	up->bin->ts = ((up->bin->text+align) & ~align) / BY2WD;
+	up->bin->text -= UTZERO;
+	up->bin->data = beswal(u.ehdr.ex.data);
+	up->bin->bss = beswal(u.ehdr.ex.bss);
+	align = BY2PG-1;
+	up->bin->ds = ((up->bin->ts + up->bin->data + align) & ~align) / BY2WD;
+	bssend = up->bin->ts + up->bin->data + up->bin->bss;
+	up->bin->bssz = ((bssend + align) & ~align) / BY2WD;
+
+	if(up->bin->ts >= (ulong)(USTKTOP-USTKSIZE) || up->bin->ds >= (ulong)(USTKTOP-USTKSIZE) || up->bin->bss >= (ulong)(USTKTOP-USTKSIZE))
+		error(Ebadexec);
+
+	/* Set up text, data, and bss. Patch syscalls. OS dependent. */
+	osbuildtext(tc);
+	if(waserror()){
+		osclrmem();
+		nexterror();
+	}
+	ospatchtext();
+	if(waserror()){
+		osclrmem();
+		nexterror();
+	}
+	osbuilddata(tc);
+	if(waserror()){
+		osclrmem();
+		nexterror();
+	}
+	osbuildbss(tc);
+	if(waserror()){
+		osclrmem();
+		nexterror();
+	}
+
+	/* Run binary. OS dependent. */
+	osexec(up);
+
+	print("Exiting sysproc\n");
+	/* Clean up */
+	osclrmem();
+	up->arg = nil;
+	free(up->bin);
+
+	poperror(); /* osbuildtext */
+	poperror(); /* ospatchtext */
+	poperror(); /* osbuilddata */
+	poperror(); /* osbuildbss */
+	cclose(tc);
+	
+	return 0;
+}
\ No newline at end of file
--- a/libdraw/alloc.c
+++ b/libdraw/alloc.c
@@ -2,10 +2,10 @@
 #include <libc.h>
 #include <draw.h>
 
-Image*
+Img*
 allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col)
 {
-	Image *i;
+	Img *i;
 
 	i = _allocimage(nil, d, r, chan, repl, col, 0, 0);
 	if(i != nil)
@@ -13,12 +13,12 @@
 	return i;
 }
 
-Image*
-_allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong col, int screenid, int refresh)
+Img*
+_allocimage(Img *ai, Display *d, Rectangle r, ulong chan, int repl, ulong col, int screenid, int refresh)
 {
 	uchar *a;
 	char *err;
-	Image *i;
+	Img *i;
 	Rectangle clipr;
 	int id;
 	int depth;
@@ -80,7 +80,7 @@
 	if(ai != nil)
 		i = ai;
 	else{
-		i = malloc(sizeof(Image));
+		i = malloc(sizeof(Img));
 		if(i == nil){
 			a = bufimage(d, 1+4);
 			if(a != nil){
@@ -103,12 +103,12 @@
 	return i;
 }
 
-Image*
+Img*
 namedimage(Display *d, char *name)
 {
 	uchar *a;
 	char *err, buf[12*12+1];
-	Image *i;
+	Img *i;
 	int id, n;
 	ulong chan;
 
@@ -144,7 +144,7 @@
 		goto Error;
 	buf[12*12] = '\0';
 
-	i = malloc(sizeof(Image));
+	i = malloc(sizeof(Img));
 	if(i == nil){
 	Error1:
 		a = bufimage(d, 1+4);
@@ -178,7 +178,7 @@
 }
 
 int
-nameimage(Image *i, char *name, int in)
+nameimage(Img *i, char *name, int in)
 {
 	uchar *a;
 	int n;
@@ -198,11 +198,11 @@
 }
 
 int
-_freeimage1(Image *i)
+_freeimage1(Img *i)
 {
 	uchar *a;
 	Display *d;
-	Image *w;
+	Img *w;
 
 	if(i == nil || i->display == nil)
 		return 0;
@@ -233,7 +233,7 @@
 }
 
 int
-freeimage(Image *i)
+freeimage(Img *i)
 {
 	int ret;
 
--- a/libip/eipfmt.c
+++ b/libip/eipfmt.c
@@ -9,15 +9,15 @@
 
 uchar prefixvals[256] =
 {
-[0x00] 0 | Isprefix,
-[0x80] 1 | Isprefix,
-[0xC0] 2 | Isprefix,
-[0xE0] 3 | Isprefix,
-[0xF0] 4 | Isprefix,
-[0xF8] 5 | Isprefix,
-[0xFC] 6 | Isprefix,
-[0xFE] 7 | Isprefix,
-[0xFF] 8 | Isprefix,
+[0x00] = 0 | Isprefix,
+[0x80] = 1 | Isprefix,
+[0xC0] = 2 | Isprefix,
+[0xE0] = 3 | Isprefix,
+[0xF0] = 4 | Isprefix,
+[0xF8] = 5 | Isprefix,
+[0xFC] = 6 | Isprefix,
+[0xFE] = 7 | Isprefix,
+[0xFF] = 8 | Isprefix,
 };
 
 int
--- /dev/null
+++ b/librc/Makefile
@@ -1,0 +1,30 @@
+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
--- /dev/null
+++ b/librc/code.c
@@ -1,0 +1,547 @@
+#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
--- /dev/null
+++ b/librc/drawcpu.c
@@ -1,0 +1,445 @@
+/*
+ * 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
+};
+
+/* TODO: Set rcmain in .make  */
+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
--- /dev/null
+++ b/librc/exec.c
@@ -1,0 +1,1170 @@
+#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
+start(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)
+{
+	start(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));
+	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;
+	start(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 */
+		start(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
--- /dev/null
+++ b/librc/exec.h
@@ -1,0 +1,88 @@
+/*
+ * 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
--- /dev/null
+++ b/librc/fns.h
@@ -1,0 +1,69 @@
+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	start(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
--- /dev/null
+++ b/librc/getflags.c
@@ -1,0 +1,234 @@
+#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
--- /dev/null
+++ b/librc/getflags.h
@@ -1,0 +1,7 @@
+#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
--- /dev/null
+++ b/librc/glob.c
@@ -1,0 +1,259 @@
+#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
--- /dev/null
+++ b/librc/havefork.c
@@ -1,0 +1,240 @@
+#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();
+		start(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]);
+		start(p->code, pc+2, runq->local, runq->redir);
+		runq->ret = 0;
+		pushredir(ROPEN, pfd[PWR], lfd);
+		break;
+	default:
+		addwaitpid(pid);
+		Close(pfd[PWR]);
+		start(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]);
+		start(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);
+		start(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();
+		start(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
--- /dev/null
+++ b/librc/here.c
@@ -1,0 +1,137 @@
+#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
--- /dev/null
+++ b/librc/io.c
@@ -1,0 +1,302 @@
+#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
--- /dev/null
+++ b/librc/io.h
@@ -1,0 +1,28 @@
+#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
--- /dev/null
+++ b/librc/lex.c
@@ -1,0 +1,435 @@
+#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
--- /dev/null
+++ b/librc/pcmd.c
@@ -1,0 +1,169 @@
+#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
--- /dev/null
+++ b/librc/pfnc.c
@@ -1,0 +1,78 @@
+#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
--- /dev/null
+++ b/librc/rc.h
@@ -1,0 +1,146 @@
+
+#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
--- /dev/null
+++ b/librc/rcmain
@@ -1,0 +1,39 @@
+# 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
--- /dev/null
+++ b/librc/simple.c
@@ -1,0 +1,804 @@
+/*
+ * 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);
+
+	start(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;
+}
--- /dev/null
+++ b/librc/subr.c
@@ -1,0 +1,54 @@
+#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
--- /dev/null
+++ b/librc/trap.c
@@ -1,0 +1,34 @@
+#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
--- /dev/null
+++ b/librc/tree.c
@@ -1,0 +1,190 @@
+#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
--- /dev/null
+++ b/librc/var.c
@@ -1,0 +1,109 @@
+#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
--- /dev/null
+++ b/librc/y.tab.c
@@ -1,0 +1,1977 @@
+/* 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);
+}
+
+
--- /dev/null
+++ b/librc/y.tab.h
@@ -1,0 +1,113 @@
+/* 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
@@ -4,9 +4,11 @@
 #include "kern/fns.h"
 #include "user.h"
 #include "drawcpu.h"
+#include "arg.h"
 
 char *argv0;
 char *dbgfile = "./debug.log";
+int debug;
 
 void
 sizebug(void)
@@ -38,15 +40,35 @@
     return s;
 }
 
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: drawcpu [-D]\n");
+	exit(1);
+}
+
+
 int
 main(int argc, char **argv)
 {
 	extern ulong kerndate;
+	int ifd, ofd,efd, dfd;
+
+	debug = 0;
 	kerndate = seconds();
 	eve = getuser();
 	if(eve == nil)
 		eve = "drawcpu";
 
+	ARGBEGIN {
+	case 'D':
+		debug++;
+		break;
+	default:
+		usage();
+	} ARGEND;
+
 	sizebug();
 	osinit();
 	procinit0();
@@ -62,17 +84,34 @@
 		panic("bind #e: %r");
 	if(bind("#I", "/net", MBEFORE) < 0)
 		panic("bind #I: %r");
-	if(bind("#U", "/root", MREPL) < 0)
+	if(bind("#U", "/root", MREPL|MCREATE) < 0)
 		panic("bind #U: %r");
-    if(bind("/root", "/", MAFTER) < 0)
+	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");
 
 	char *cmd[] = {
 		"drawcpu",
-		"-c"
+		"-c",
 		". <{n=`{read} && ! ~ $#n 0 && read -c $n} >[2=1]"	
 	};
 
-	runcommand(3, cmd);
+	rc(3, cmd, dfd);
 	_exit(0);
 }
--- a/posix-386/Makefile
+++ b/posix-386/Makefile
@@ -1,10 +1,13 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	start.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-386/start.c
@@ -1,0 +1,38 @@
+#include "u.h"
+#include "libc.h"
+
+void start(uintptr_t entry, Tos *_tos, int argc, char *argv[]) {
+    // entry point
+    register uintptr_t ebx asm("ebx") = entry;
+    register Tos *ecx asm("ecx") = _tos;
+    register int edx asm("edx") = argc;
+    register char **esi asm("esi") = argv;
+
+    __asm__ (
+        // Load values into registers
+        "mov ebx, %0\n\t"
+        "mov ecx, %1\n\t"
+        "mov edx, %2\n\t"
+        "mov esi, %3\n\t"
+
+        // push argv onto stack
+        "mov edi, edx\n\t"
+        "inc edi\n\t"
+        "shl edi, 2\n\t"
+        "sub esp, edi\n\t"
+        "mov edi, esp\n\t"
+        "rep movsb\n\t"
+
+        // push argc onto stack
+        "mov [esp], edx\n\t"
+        "sub esp, 4\n\t"
+
+        // jump to entry point
+        "jmp ebx\n\t"
+        "nop\n\t"
+
+        :
+        : "r" (ebx), "r" (ecx), "r" (edx), "r" (esi)
+        : "edi"
+    );
+}
--- a/posix-amd64/Makefile
+++ b/posix-amd64/Makefile
@@ -1,10 +1,14 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	run.$O\
+	trampoline.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-amd64/run.c
@@ -1,0 +1,38 @@
+#include "u.h"
+#include "libc.h"
+
+void run(uintptr_t entry, Tos *_tos, int argc, char *argv[]) {
+    // entry point
+    register uintptr_t rdi asm("rdi") = entry;
+    register Tos *rsi asm("rsi") = _tos;
+    register int edx asm("edx") = argc;
+    register char **rcx asm("rcx") = argv;
+
+    __asm__ __volatile__ (
+        // Load values into registers
+        "mov rdi, %0\n\t"
+        "mov rsi, %1\n\t"
+        "mov edx, %2\n\t"
+        "mov rcx, %3\n\t"
+
+        // push argv onto stack
+        "mov r8, rdx\n\t"
+        "add r8, r8, 1\n\t"
+        "shl r8, r8, 3\n\t"
+        "sub rsp, r8\n\t"
+        "mov r9, rsp\n\t"
+        "rep movsb\n\t"
+
+        // push argc onto stack
+        "mov [rsp], edx\n\t"
+        "sub rsp, 8\n\t"
+
+        // jump to entry point
+        "jmp rdi\n\t"
+        "nop\n\t"
+
+        :
+        : "r" (rdi), "r" (rsi), "r" (edx), "r" (rcx)
+        : "r8", "r9"
+    );
+}
\ No newline at end of file
--- /dev/null
+++ b/posix-amd64/trampoline.c
@@ -1,0 +1,80 @@
+#include <u.h>
+#include <libc.h>
+#include "../kern/fns.h"
+
+#define _NSYS		53
+
+/* TODO: This is not arm64 code, this is amd64 code */
+extern void asm_syscall_hook(void);
+void ____asm_syscall_hook(void)
+{
+	/*
+	 * asm_syscall_hook is the address where the
+	 * trampoline code first jumps to.
+	 *
+	 * the procedure below calls the C function
+	 * namded syscall_hook.
+	 *
+	 * at the entry point of this,
+	 * the register values follow the calling convention
+	 * of the system calls. the following transforms
+	 * to the calling convention of the C functions.
+	 *
+	 * we do this just for writing the hook in C.
+	 * so, this part would not be performance optimal.
+	 */
+	asm volatile (
+	".globl asm_syscall_hook \n\t"
+	"asm_syscall_hook: \n\t"
+	"movq (%rsp), %rcx \n\t"
+	"pushq %rbp \n\t"
+	"movq %rsp, %rbp \n\t"
+	"subq $16,%rsp \n\t"
+	"movq %rcx,8(%rsp) \n\t"
+	"movq %r9,(%rsp) \n\t"
+	"movq %r8, %r9 \n\t"
+	"movq %r10, %r8 \n\t"
+	"movq %rdx, %rcx \n\t"
+	"movq %rsi, %rdx \n\t"
+	"movq %rdi, %rsi \n\t"
+	"movq %rax, %rdi \n\t"
+	"call syscall \n\t"
+	"leaveq \n\t"
+	"retq \n\t"
+	);
+}
+
+int
+trampoline(void *text)
+{
+    int i;
+    for(i = 0; i < _NSYS; i++)
+        ((uint8_t *)text)[i] = 0x90;
+
+    /* Preserve redzone */
+    ((uint8_t*)text)[_NSYS + 0x00] = 0x48;
+    ((uint8_t *) text)[_NSYS + 0x01] = 0x81;
+	((uint8_t *) text)[_NSYS + 0x02] = 0xec;
+	((uint8_t *) text)[_NSYS + 0x03] = 0x80;
+	((uint8_t *) text)[_NSYS + 0x04] = 0x00;
+	((uint8_t *) text)[_NSYS + 0x05] = 0x00;
+	((uint8_t *) text)[_NSYS + 0x06] = 0x00;
+
+    /* 49 bb [64-bit addr (8-byte)] movabs [64-bit addr (8-byte)],%r11 */
+	((uint8_t *) text)[_NSYS + 0x07] = 0x49;
+	((uint8_t *) text)[_NSYS + 0x08] = 0xbb;
+	((uint8_t *) text)[_NSYS + 0x09] = ((uint64_t) asm_syscall_hook >> (8 * 0)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0a] = ((uint64_t) asm_syscall_hook >> (8 * 1)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0b] = ((uint64_t) asm_syscall_hook >> (8 * 2)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0c] = ((uint64_t) asm_syscall_hook >> (8 * 3)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0d] = ((uint64_t) asm_syscall_hook >> (8 * 4)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0e] = ((uint64_t) asm_syscall_hook >> (8 * 5)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0f] = ((uint64_t) asm_syscall_hook >> (8 * 6)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x10] = ((uint64_t) asm_syscall_hook >> (8 * 7)) & 0xff;
+
+	// 41 ff e3                jmp    *%r11
+	((uint8_t *) text)[_NSYS + 0x11] = 0x41;
+	((uint8_t *) text)[_NSYS + 0x12] = 0xff;
+	((uint8_t *) text)[_NSYS + 0x13] = 0xe3;
+	return i + 0x13;
+}
--- a/posix-arm/Makefile
+++ b/posix-arm/Makefile
@@ -1,10 +1,13 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	start.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-arm/start.c
@@ -1,0 +1,70 @@
+#include "u.h"
+#include "libc.h"
+
+void start(uintptr_t entry, Tos *_tos, int argc, char *argv[]) {
+    // entry point
+    register uintptr_t r0 asm("r0") = entry;
+    register Tos *r1 asm("r1") = _tos;
+    register int r2 asm("r2") = argc;
+    register char **r3 asm("r3") = argv;
+
+    __asm__ __volatile__ (
+        // Load values into registers
+        "mov r0, %0\n\t"
+        "mov r1, %1\n\t"
+        "mov r2, %2\n\t"
+        "mov r3, %3\n\t"
+
+    #ifdef ARMV5
+        // ARMv5 specific code
+        // push argv onto stack
+        "mov r4, r2\n\t"
+        "add r4, r4, #1\n\t"
+        "lsl r4, r4, #2\n\t"
+        "sub sp, sp, r4\n\t"
+        "mov r5, sp\n\t"
+        "cpy r6, r3\n\t"
+
+
+    "copy_argv_loop:\n\t"
+        "ldr r7, [r6], #4\n\t"
+        "str r7, [r5], #4\n\t"
+        "subs r4, r4, #1\n\t"
+        "bne copy_argv_loop\n\t"
+
+        // push argc onto stack
+        "sub sp, sp, #4\n\t"
+        "str r2, [sp]\n\t"
+
+    #else
+        // Generic ARM code
+        // push argv onto stack
+        "ldr r4, [r3]\n\t"
+        "add r4, r4, #1\n\t"
+        "lsl r4, r4, #2\n\t"
+        "sub sp, sp, r4\n\t"
+        "mov r5, sp\n\t"
+        "cpy r6, r3\n\t"
+
+    "copy_argv_loop:\n\t"
+        "ldr r7, [r6], #4\n\t"
+        "str r7, [r5], #4\n\t"
+        "subs r4, r4, #1\n\t"
+        "bne copy_argv_loop\n\t"
+
+        // push argc onto stack
+        "sub sp, sp, #4\n\t"
+        "str r2, [sp]\n\t"
+
+    #endif
+
+        // jump to entry point
+        "mov lr, r0\n\t"
+        "bx lr\n\t"
+        "nop\n\t"
+
+        :
+        : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
+        : "r4", "r5", "r6", "r7"
+    );
+}
\ No newline at end of file
--- a/posix-arm64/Makefile
+++ b/posix-arm64/Makefile
@@ -1,10 +1,15 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	run.$O\
+	trampoline.$O\
+	patch.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-arm64/mem.h
@@ -1,0 +1,152 @@
+#define AOUT_MAGIC  (R_MAGIC)
+/*
+ * Memory and machine-specific definitions.  Used in C and assembler.
+ */
+#define KiB		1024u			/* Kibi 0x0000000000000400 */
+#define MiB		1048576u		/* Mebi 0x0000000000100000 */
+#define GiB		1073741824u		/* Gibi 000000000040000000 */
+
+/*
+ * Sizes:
+ * 	L0	L1	L2	L3
+ *	4K	2M	1G	512G
+ *	16K	32M	64G	128T
+ *	64K	512M	4T	-
+ */
+#define	PGSHIFT		12		/* log(BY2PG) */
+#define	BY2PG		(1ULL<<PGSHIFT)	/* bytes per page */
+#define	ROUND(s, sz)	(((s)+(sz-1))&~(sz-1))
+#define	PGROUND(s)	ROUND(s, BY2PG)
+
+/* effective virtual address space */
+#define EVASHIFT	36
+#define EVAMASK		((1ULL<<EVASHIFT)-1)
+
+#define PTSHIFT		(PGSHIFT-3)
+#define PTLEVELS	(((EVASHIFT-PGSHIFT)+PTSHIFT-1)/PTSHIFT)	
+#define PTLX(v, l)	((((v) & EVAMASK) >> (PGSHIFT + (l)*PTSHIFT)) & ((1 << PTSHIFT)-1))
+#define PGLSZ(l)	(1ULL << (PGSHIFT + (l)*PTSHIFT))
+
+#define PTL1X(v, l)	(L1TABLEX(v, l) | PTLX(v, l))
+#define L1TABLEX(v, l)	(L1TABLE(v, l) << PTSHIFT)
+#define L1TABLES	((-KSEG0+PGLSZ(2)-1)/PGLSZ(2))
+#define L1TABLE(v, l)	(L1TABLES - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
+#define L1TOPSIZE	(1ULL << (EVASHIFT - PTLEVELS*PTSHIFT))
+
+#define	MAXMACH		16			/* max # cpus system can run */
+#define	MACHSIZE	(8*KiB)
+
+#define KSTACK		(8*KiB)
+#define STACKALIGN(sp)	((sp) & ~7)		/* bug: assure with alloc */
+#define TRAPFRAMESIZE	(38*8)
+
+#define DTBADDR		0x40000000
+
+#define VDRAM		(0xFFFFFFFFC0000000ULL)	/* 0x40000000 - 0x80000000 */
+#define	KTZERO		(VDRAM + 0x100000)	/* 0x40100000 - kernel text start */
+
+#define PHYSIO		0x8000000
+#define PHYSIOEND	0x10000000
+
+#define	VIRTIO		(0xFFFFFFFFB0000000ULL)
+
+#define	KZERO		(0xFFFFFFFF80000000ULL)	/* 0x00000000 - kernel address space */
+
+#define VMAP		(0xFFFFFFFF00000000ULL)	/* 0x00000000 - 0x40000000 */
+
+#define KMAPEND		(0xFFFFFFFF00000000ULL)	/* 0x140000000 */
+#define KMAP		(0xFFFFFFFE00000000ULL)	/*  0x40000000 */
+
+#define KLIMIT		(VDRAM - KZERO + KMAPEND - KMAP)	/* 0x140000000 */
+
+#define KSEG0		(0xFFFFFFFE00000000ULL)
+
+/* temporary identity map for TTBR0 (using only top-level) */
+#define L1BOT		((L1-L1TOPSIZE)&-BY2PG)
+
+/* shared kernel page table for TTBR1 */
+#define L1		(L1TOP-L1SIZE)
+#define L1SIZE		((L1TABLES+PTLEVELS-2)*BY2PG)
+#define L1TOP		((MACHADDR(MAXMACH-1)-L1TOPSIZE)&-BY2PG)
+
+#define MACHADDR(n)	(KTZERO-((n)+1)*MACHSIZE)
+
+#define CONFADDR	(VDRAM + 0x10000)	/* 0x40010000 */
+
+#define BOOTARGS	((char*)CONFADDR)
+#define BOOTARGSLEN	0x10000
+
+#define	REBOOTADDR	(VDRAM-KZERO + 0x20000)	/* 0x40020000 */
+
+#define	UZERO		0ULL			/* user segment */
+#define	UTZERO		(UZERO+0x10000)		/* user text start */
+#define	USTKTOP		((EVAMASK>>1)-0xFFFF)	/* user segment end +1 */
+#define	USTKSIZE	(16*1024*1024)		/* user stack size */
+
+#define BLOCKALIGN	64			/* only used in allocb.c */
+#define TRAMPSIZE   72          /* Size of the trampoline */
+/*
+ * Sizes
+ */
+#define BI2BY		8			/* bits per byte */
+#define BY2SE		4
+#define BY2WD		8
+#define BY2V		8			/* only used in xalloc.c */
+
+#define	PTEMAPMEM	(1024*1024)
+#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
+#define	SEGMAPSIZE	8192
+#define	SSEGMAPSIZE	16
+#define	PPN(x)		((x)&~(BY2PG-1))
+
+#define SHARE_NONE	0
+#define SHARE_OUTER	2
+#define SHARE_INNER	3
+
+#define CACHE_UC	0
+#define CACHE_WB	1
+#define CACHE_WT	2
+#define CACHE_WB_NA	3
+
+#define MA_MEM_WB	0
+#define MA_MEM_WT	1
+#define MA_MEM_UC	2
+#define MA_DEV_nGnRnE	3
+#define MA_DEV_nGnRE	4
+#define MA_DEV_nGRE	5
+#define MA_DEV_GRE	6
+
+#define	PTEVALID	1
+#define PTEBLOCK	0
+#define PTETABLE	2
+#define PTEPAGE		2
+
+#define PTEMA(x)	((x)<<2)
+#define PTEAP(x)	((x)<<6)
+#define PTESH(x)	((x)<<8)
+
+#define PTEAF		(1<<10)
+#define PTENG		(1<<11)
+#define PTEPXN		(1ULL<<53)
+#define PTEUXN		(1ULL<<54)
+
+#define PTEKERNEL	PTEAP(0)
+#define PTEUSER		PTEAP(1)
+#define PTEWRITE	PTEAP(0)
+#define PTERONLY	PTEAP(2)
+#define PTENOEXEC	(PTEPXN|PTEUXN)
+
+#define PTECACHED	PTEMA(MA_MEM_WB)
+#define PTEWT		PTEMA(MA_MEM_WT)
+#define PTEUNCACHED	PTEMA(MA_MEM_UC)
+#define PTEDEVICE	PTEMA(MA_DEV_nGnRE)
+
+/*
+ * Physical machine information from here on.
+ *	PHYS addresses as seen from the arm cpu.
+ *	BUS  addresses as seen from peripherals
+ */
+#define	PHYSDRAM	0
+
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#define MAX(a, b)	((a) > (b)? (a): (b))
\ No newline at end of file
--- /dev/null
+++ b/posix-arm64/patch.c
@@ -1,0 +1,22 @@
+#include <u.h>
+#include <libc.h>
+#include "mem.h"
+
+int
+patch(void* text, int size)
+{
+    ulong i;
+    int ret = -1;
+    for(i = 0; i < size - BY2WD; i++){
+        // MOV X0, #immediate (could be D2800000 | syscall_number)
+        // BL X0 (could be D4000000 | offset)
+        // 0xD63F0000 is our BLR X0
+        if ((*(ulong*)&text[i] & 0xFFFF0000) == 0xD2800000 && (*(ulong*)&text[i+BY2SE] & 0xFFFF0000) == 0xD4000000) {
+            long *ptr = (ulong*)&text[i];
+            ptr[1] = 0xD6;
+            ptr[0] = 0x3F;
+            ret++;
+        }
+    }
+    return ret;
+}
--- /dev/null
+++ b/posix-arm64/run.s
@@ -1,0 +1,24 @@
+/* SPDX-License-Identifier: Unlicense */
+.text
+.global _run
+_run:
+    mov x29, x0         // entry (x0 is the first argument, equivalent to rdi)
+    mov x9, x1          // _tos (x1 is the second argument, equivalent to rsi)
+    mov x19, x2         // argc (x2 is the third argument, equivalent to rdx)
+    mov x20, x3         // argv (x3 is the fourth argument, equivalent to rcx)
+
+    // Push argv onto stack
+    mov x10, x19        // x10 = argc
+    add x10, x10, #1    // x10 = argc + 1
+    lsl x10, x10, #3    // x10 = (argc + 1) * 8 (shifting left by 3 is multiplying by 8)
+    sub sp, sp, x10     // Allocate space on stack
+    mov x0, sp          // x0 = new stack pointer (destination for memcpy)
+    mov x1, x20         // x1 = argv (source for memcpy)
+    mov x2, x10         // x2 = number of bytes to copy
+    bl _memcpy           // Call memcpy to copy argv to stack
+
+    // Push argc onto stack
+    str x19, [sp, #-16]!  // Push argc onto stack and update stack pointer
+
+    // Jump to entry point
+    br x29
\ No newline at end of file
--- /dev/null
+++ b/posix-arm64/trampoline.c
@@ -1,0 +1,66 @@
+#include <u.h>
+#include <libc.h>
+
+#define _NSYS		53
+
+void asm_syscall_hook(void)
+{
+	__asm__ __volatile__ (
+    	".global asm_syscall_hook \n\t"
+    	"asm_syscall_hook: \n\t"
+    	"stp x29, x30, [sp, #-16]! \n\t"  // Save frame pointer and link register
+    	"mov x29, sp \n\t"                // Set up frame pointer
+    	"sub sp, sp, #32 \n\t"            // Allocate 32 bytes on stack
+    	"str x8, [sp, #24] \n\t"          // Save x8 (syscall number)
+    	"stp x0, x1, [sp, #8] \n\t"       // Save x0 and x1
+    	"str x2, [sp] \n\t"               // Save x2
+    	"mov x0, x8 \n\t"                 // Move syscall number to x0
+    	"mov x1, x0 \n\t"                 // Shift arguments: x0 -> x1
+    	"mov x2, x1 \n\t"                 // x1 -> x2
+    	"mov x3, x2 \n\t"                 // x2 -> x3
+    	"mov x4, x3 \n\t"                 // x3 -> x4
+    	"mov x5, x4 \n\t"                 // x4 -> x5
+    	"mov x6, x5 \n\t"                 // x5 -> x6
+    	"ldr x7, [sp, #24] \n\t"          // Load original x8 into x7
+    	"bl _sysintercept \n\t"            // Call syscall function
+    	"mov sp, x29 \n\t"                // Restore stack pointer
+    	"ldp x29, x30, [sp], #16 \n\t"    // Restore frame pointer and link register
+    	"ret \n\t"                        // Return
+	);
+}
+
+int
+trampoline(void *text)
+{
+    int i;
+
+    for(i = 0; i < _NSYS; i++)
+        ((uint8_t *)text)[i] = 0x90;
+
+    /* Preserve redzone */
+    ((uint8_t*)text)[_NSYS + 0x00] = 0x48;
+    ((uint8_t *) text)[_NSYS + 0x01] = 0x81;
+	((uint8_t *) text)[_NSYS + 0x02] = 0xec;
+	((uint8_t *) text)[_NSYS + 0x03] = 0x80;
+	((uint8_t *) text)[_NSYS + 0x04] = 0x00;
+	((uint8_t *) text)[_NSYS + 0x05] = 0x00;
+	((uint8_t *) text)[_NSYS + 0x06] = 0x00;
+
+    /* 49 bb [64-bit addr (8-byte)] movabs [64-bit addr (8-byte)],%r11 */
+	((uint8_t *) text)[_NSYS + 0x07] = 0x49;
+	((uint8_t *) text)[_NSYS + 0x08] = 0xbb;
+	((uint8_t *) text)[_NSYS + 0x09] = ((uint64_t) asm_syscall_hook >> (8 * 0)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0a] = ((uint64_t) asm_syscall_hook >> (8 * 1)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0b] = ((uint64_t) asm_syscall_hook >> (8 * 2)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0c] = ((uint64_t) asm_syscall_hook >> (8 * 3)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0d] = ((uint64_t) asm_syscall_hook >> (8 * 4)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0e] = ((uint64_t) asm_syscall_hook >> (8 * 5)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x0f] = ((uint64_t) asm_syscall_hook >> (8 * 6)) & 0xff;
+	((uint8_t *) text)[_NSYS + 0x10] = ((uint64_t) asm_syscall_hook >> (8 * 7)) & 0xff;
+
+	// 41 ff e3                jmp    *%r11
+	((uint8_t *) text)[_NSYS + 0x11] = 0x41;
+	((uint8_t *) text)[_NSYS + 0x12] = 0xff;
+	((uint8_t *) text)[_NSYS + 0x13] = 0xe3;
+	return i + 0x13;
+}
--- a/posix-mips/Makefile
+++ b/posix-mips/Makefile
@@ -1,11 +1,14 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
-
+	tas.$O\
+	start.$O\
+	
 default: $(LIB)
 $(LIB): $(OFILES)
 	$(AR) r $(LIB) $(OFILES)
--- /dev/null
+++ b/posix-mips/start.s
@@ -1,0 +1,41 @@
+.data
+argc:   .word 0
+_tos:   .word 0
+argv:   .word 0
+sp:     .word 0
+
+.text
+.globl start
+start:
+    # entry point
+    lw $t0, argc       # $t0 = argc
+    lw $t1, _tos       # $t1 = _tos
+    lw $t2, argv       # $t2 = argv
+    lw $t3, sp         # $t3 = stack pointer
+
+    # push argv onto stack
+    move $t4, $t0      # $t4 = argc
+    addi $t4, $t4, 1   # $t4 = argc + 1
+    sll $t4, $t4, 2    # $t4 = (argc + 1) * 4
+    subu $sp, $sp, $t4 # $sp = $sp - ((argc + 1) * 4)
+    move $t4, $sp      # $t4 = stack pointer
+    move $t5, $t2      # $t5 = argv
+    move $t6, $t4      # $t6 = destination pointer
+
+copy_argv_loop:
+    lw $t7, 0($t5)     # Load argv[i] to $t7
+    sw $t7, 0($t6)     # Store argv[i] to stack
+    addiu $t5, $t5, 4  # Increment argv
+    addiu $t6, $t6, 4  # Increment destination pointer
+    addi $t0, $t0, -1  # Decrement argc
+    bne $t0, $zero, copy_argv_loop # Loop if argc != 0
+
+    # push argc onto stack
+    subu $sp, $sp, 4   # $sp = $sp - 4
+    sw $t3, ($sp)      # Push stack pointer
+
+    # jump to entry point
+    j $t0
+    nop
+
+.section .note.GNU-stack,"",@progbits
\ No newline at end of file
--- a/posix-power/Makefile
+++ b/posix-power/Makefile
@@ -1,12 +1,15 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+LAGS+= -Wa,-mregnames,-fpie
+LDFLAGS+=-fpie
 
 CFLAGS+= -Wa,-mregnames
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	start.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-power/start.c
@@ -1,0 +1,49 @@
+#include "u.h"
+#include "libc.h"
+
+void start() {
+    // entry point
+    register int argc asm("r3");
+    register int _tos asm("r4");
+    register int argv asm("r5");
+    register int sp asm("r6");
+
+    __asm__ (
+        // Load values into registers
+        "lwz %0, argc\n\t"
+        "lwz %1, _tos\n\t"
+        "lwz %2, argv\n\t"
+        "lwz %3, sp\n\t"
+
+        // push argv onto stack
+        "mr r4, r3\n\t"
+        "addi r4, r4, 1\n\t"
+        "slwi r4, r4, 2\n\t"
+        "subi sp, sp, r4\n\t"
+        "mr r4, sp\n\t"
+        "mr r5, r5\n\t"
+        "mr r6, r4\n\t"
+
+    "copy_argv_loop:\n\t"
+        "lwz r7, 0(r5)\n\t"
+        "stw r7, 0(r6)\n\t"
+        "addi r5, r5, 4\n\t"
+        "addi r6, r6, 4\n\t"
+        "addi r3, r3, -1\n\t"
+        "cmpwi r3, 0\n\t"
+        "bne copy_argv_loop\n\t"
+
+        // push argc onto stack
+        "subi sp, sp, 4\n\t"
+        "stw r4, 0(sp)\n\t"
+
+        // jump to entry point
+        "mtctr r3\n\t"
+        "bctr\n\t"
+        "nop\n\t"
+
+        :
+        : "r" (argc), "r" (_tos), "r" (argv), "r" (sp)
+        : "r4", "r5", "r6", "r7"
+    );
+}
\ No newline at end of file
--- a/posix-riscv64/Makefile
+++ b/posix-riscv64/Makefile
@@ -1,10 +1,13 @@
 ROOT=..
 include ../Make.config
 LIB=../libmachdep.a
+CFLAGS+=-fpie
+LDFLAGS+=-fpie
 
 OFILES=\
 	getcallerpc.$O\
-	tas.$O
+	tas.$O\
+	start.$O\
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/posix-riscv64/start.c
@@ -1,0 +1,47 @@
+#include "u.h"
+#include "libc.h"
+
+void start() {
+    // entry point
+    register int argc asm("t0");
+    register int _tos asm("t1");
+    register int argv asm("t2");
+    register int sp asm("t3");
+
+    __asm__ (
+        // Load values into registers
+        "lw %0, argc\n\t"
+        "lw %1, _tos\n\t"
+        "lw %2, argv\n\t"
+        "lw %3, sp\n\t"
+
+        // push argv onto stack
+        "mv t4, t0\n\t"
+        "addi t4, t4, 1\n\t"
+        "slli t4, t4, 2\n\t"
+        "sub sp, sp, t4\n\t"
+        "mv t4, sp\n\t"
+        "mv t5, t2\n\t"
+        "mv t6, t4\n\t"
+
+    "copy_argv_loop:\n\t"
+        "lw t7, 0(t5)\n\t"
+        "sw t7, 0(t6)\n\t"
+        "addi t5, t5, 4\n\t"
+        "addi t6, t6, 4\n\t"
+        "addi t0, t0, -1\n\t"
+        "bnez t0, copy_argv_loop\n\t"
+
+        // push argc onto stack
+        "addi sp, sp, -4\n\t"
+        "sw t3, 0(sp)\n\t"
+
+        // jump to entry point
+        "jr t0\n\t"
+        "nop\n\t"
+
+        :
+        : "r" (argc), "r" (_tos), "r" (argv), "r" (sp)
+        : "t4", "t5", "t6", "t7"
+    );
+}
\ No newline at end of file
--- a/rc/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
--- a/rc/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);
-}
--- a/rc/drawcpu.c
+++ /dev/null
@@ -1,504 +1,0 @@
-/*
- * Plan 9 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 execrfork(void);
-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,
-	"read",     execread,
-	"ns",       execns,
-	"bind",		execbind,
-	"mount",	execmount,
-	"unmount",	execunmount,
-	"ls", 		execls,
-	"cat",		execcat,
-	"rm",       execrm,
-	"mkdir",    execmkdir,
-	"test",     exectest,
-	"echo",     exececho,
-	0
-};
-
-/* TODO: Set rcmain in .make  */
-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;
-}
-
-static 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();
-}
-
-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)
-{
-	execvp(argv[0], argv+1);
-}
-
-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* u, char *s)
-{
-	int i;
-
-	USED(u);
-	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]);
-	if(fd < 0 && strcmp(file, "/fd/0") == 0)
-		fd = lfdfd(0);
-	if(fd < 0 && 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;
-		if((fd=Creat("/dev/wdir"))>=0){
-			getwd(dir, sizeof(dir));
-			Write(fd, dir, strlen(dir));
-			Close(fd);
-		}
-		newwdir = 0;
-	}
-}
--- a/rc/exec.c
+++ /dev/null
@@ -1,1174 +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
-start(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)
-{
-	start(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
-runcommand(int argc, char **argv)
-{
-	code bootstrap[20];
-	char num[12];
-	char *rcmain=Rcmain;
-
-	int i, fd;
-	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];
-
-	/* Open stdout so next desc is stderr */
-	fd = open("/dev/cons", ORDWR);
-	err = openiofd(open("/dev/cons", OWRITE));
-	close(fd);
-
-	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));
-	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;
-	start(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 */
-		start(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;
-}
--- a/rc/exec.h
+++ /dev/null
@@ -1,89 +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 execread(void), execns(void), execls(void), execcat(void);
-void execrm(void), execmkdir(void), exectest(void), exececho(void);
-void execbind(void), execmount(void), execunmount(void);
-void execcd(void), execwhatis(void), execeval(void), execexec(void);
-int execforkexec(void);
-void execexit(void), execshift(void);
-void execwait(void), execumask(void), execdot(void), execflag(void);
-void execfunc(var*), execcmds(io*, char*, var*, redir*);
-
-void startfunc(var*, word*, var*, redir*);
-
-char *srcfile(thread*);
-char *getstatus(void);
--- a/rc/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	start(code*, int, var*, redir*);
-int	truestatus(void);
-void	usage(char*);
-int	wordchr(int);
-void	yyerror(char*);
-int	yylex(void);
-int	yyparse(void);
--- a/rc/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;
-	}
-}
--- a/rc/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);
--- a/rc/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';
-}
--- a/rc/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();
-		start(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]);
-		start(p->code, pc+2, runq->local, runq->redir);
-		runq->ret = 0;
-		pushredir(ROPEN, pfd[PWR], lfd);
-		break;
-	default:
-		addwaitpid(pid);
-		Close(pfd[PWR]);
-		start(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]);
-		start(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);
-		start(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();
-		start(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;
-}
--- a/rc/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);
-	}
-}
--- a/rc/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++;
-}
--- a/rc/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);
--- a/rc/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);
-}
--- a/rc/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;
-	}
-}
--- a/rc/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);
-}
--- a/rc/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[];
--- a/rc/rcmain
+++ /dev/null
@@ -1,38 +1,0 @@
-# rcmain: unix version
-if(~ $#home 0) home=$HOME
-if(~ $#ifs 0) ifs=' 	
-'
-profile=$home/.rcrc
-switch($#prompt){
-case 0
-	prompt=('% ' '	')
-case 1
-	prompt=($prompt '	')
-}
-if(~ $rcname ?.out) 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=''
-	. $*
-}
--- a/rc/simple.c
+++ /dev/null
@@ -1,1004 +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;
-}
-
-int
-chars(int fd, int multi, vlong count, char *file)
-{
-	char buf[8*1024];
-	vlong m;
-	int n;
-
-	for(m = 0; m < count; m += n){
-		n = sizeof(buf);
-		if(n > (count - m))
-			n = count - m;
-		if((n = read(fd, buf, n)) < 0){
-			return -1;
-		}
-		if(n == 0){
-			if(m == 0)
-				setstatus("eof");
-			break;
-		}
-		write(1, buf, n);
-	}
-	return 0;
-}
-
-int
-line(int fd, char *file)
-{
-	char c;
-	int m, n, nalloc;
-	char *buf;
-
-	nalloc = 0;
-	buf = nil;
-	for(m=0; ; ){
-		n = read(fd, &c, 1);
-		if(n < 0){
-			return -1;
-		}
-		if(n == 0){
-			if(m == 0)
-				setstatus("eof");
-			break;
-		}
-		if(m == nalloc){
-			nalloc += 1024;
-			buf = realloc(buf, nalloc);
-			if(buf == nil){
-				return -1;
-			}
-		}
-		buf[m++] = c;
-		if(c == '\n')
-			break;
-	}
-	if(m > 0)
-		write(1, buf, m);
-	free(buf);
-	return m;
-}
-
-int
-lines(int fd, int multi, vlong count, char *file)
-{
-	int n;
-	do{
-		if((n = line(fd, file)) <= 0)
-			break;
-	}while(multi || --count > 0);
-	return n;
-}
-
-void
-execread(void)
-{
-//	print("Execread\n");
-	int (*proc)(int, int, vlong, char*);
-	word *a;
-	int fd, multi = 0;
-	vlong num = 0;
-	popword(); /* "read" */
-	proc = lines;
-	while(runq->argv->words && runq->argv->words->word[0]=='-'){
-		char *f = runq->argv->words->word+1;
-		if(*f == '-'){
-			popword();
-			break;
-		}
-		proc = lines;
-		for(; *f; f++){
-			switch(*f){
-			case 'c':
-				num = atoll(runq->argv->words->next->word);
-				proc = chars;
-				break;
-			case 'n':
-				num = atoi(runq->argv->words->next->word);
-				break;
-			case 'm':
-				multi = 1;
-				break;
-			default:
-				goto Usage;
-			}
-			popword();
-		}
-	}
-	if(count(runq->argv->words)==0){
-		(*proc)(0, multi, num, "<stdin>");
-	} else {
-		a = runq->argv->words->next;
-		for(;a;a = a->next){
-			fd = open(a->word, OREAD);
-			if(fd < 0){
-				goto Error;
-			}
-			if((*proc)(fd, multi, num, a->word) < 0)
-				goto Error;
-			close(fd);
-		}
-	}
-	return;
-Error:
-	pfmt(err, "read: %s\n", strerror(errno));
-	setstatus("read error");
-	poplist();
-	return;
-Usage:
-	pfmt(err, "Usage: read [ -m | -n nlines | -c nbytes | -r nrunes ] [ file ... ]\n");
-	setstatus("read usage");
-	poplist();
-}
-
-void
-execrm(void)
-{
-	int i, recurse, force;
-	char *fd;
-	Dir *db;
-	word *a;
-
-	force = recurse = 0;
-	popword(); /* rm */
-	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 'r':
-				recurse = 1;
-				break;
-			case 'f':
-				force = 1;
-				break;
-			default:
-				goto Usage;
-			}
-			popword();
-		}
-	}
-	a = runq->argv->words;
-	for(;a;a = a->next){
-		if(remove(a->word) != -1)
-			continue;
-		db = nil;
-		if(recurse && (db=dirstat(a->word))!=nil && (db->qid.type&QTDIR))
-			rmdir(a->word);
-		else
-			goto Error;
-		free(db);
-	}
-	return;
-Error:
-	pfmt(err, "rm: %r\n", strerror(errno));
-	poplist();
-	return;
-Usage:
-	pfmt(err, "usage: rm [-fr] file ...\n");
-	setstatus("rm usage");
-	poplist();
-	return;
-}
-
-void
-execns(void)
-{
-//print("Execns\n");
-}
-
-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;
-}
-
-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(sysmount(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;
-}
-
-void
-execunmount(void)
-{
-	//unmount
-}
-
-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", s, strerror(errno));
-	if(n < 0)
-		pfmt(err, "error reading %s: %s", s, strerror(errno));
-}
-
-void
-execcat(void)
-{
-	int f;
-	popword(); /* cat */
-	word *a;
-
-	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();
-}
-
-int
-hasmode(char *f, ulong m)
-{
-	int r;
-	Dir *dir;
-	dir = dirstat(f);
-	if (dir == nil)
-		return 0;
-	r = (dir->mode & m) != 0;
-	free(dir);
-	return r;
-}
-
-void
-exectest(void)
-{
-	/* TODO(halfwit): Only care about -d for my needs, but test has a ton of things */
-	setstatus("no such file");
-	if(strcmp(runq->argv->words->next->word, "-d")==0)
-		if(hasmode(runq->argv->words->next->next->word, DMDIR))
-			setstatus("");
-	poplist();
-}
-
-void
-execmkdir(void)
-{
-
-}
-
-void
-exececho(void)
-{
-	int nflag;
-	int i, len;
-	char *buf, *p;
-	word *a, *c;
-
-	nflag = 0;
-	popword(); /* echo */
-	a = runq->argv->words;
-	if(count(a) > 0 && strcmp(a->word, "-n") == 0){
-		a = a->next; // move up our counter as well
-		nflag = 1;
-	}
-	len = 1;
-	for(c = a; c; c = c->next)
-		len += strlen(c->word)+1;
-	buf = malloc(len);
-	if(buf == 0)
-		panic("no memory");
-	p = buf;
-	for(c = a; c; c = c->next){
-		strcpy(p, c->word);
-		p += strlen(p);
-		if(c->next)
-			*p++ = ' ';
-	}
-	if(!nflag)
-		*p++ = '\n';
-	write(1, buf, p-buf);
-}
-
-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
-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);
-
-	start(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();
-}
--- a/rc/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';
-}
--- a/rc/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();
-	}
-}
--- a/rc/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;
-}
--- a/rc/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);
-}
--- a/rc/y.tab.c
+++ /dev/null
@@ -1,1978 +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/rc/y.tab.h
+++ /dev/null
@@ -1,114 +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;
-
--