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;
-
--
⑨