Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/dist/9legacy/applied/rc-badrunes.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


diff -Nru /n/sources/plan9/sys/src/cmd/rc/code.c /sys/src/cmd/rc/code.c
--- /n/sources/plan9/sys/src/cmd/rc/code.c	Thu Aug 14 18:37:56 2008
+++ /sys/src/cmd/rc/code.c	Wed Aug 17 00:00:00 2016
@@ -2,7 +2,7 @@
 #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]
diff -Nru /n/sources/plan9/sys/src/cmd/rc/exec.c /sys/src/cmd/rc/exec.c
--- /n/sources/plan9/sys/src/cmd/rc/exec.c	Thu Jun 13 23:21:27 2013
+++ /sys/src/cmd/rc/exec.c	Wed Aug 17 00:00:00 2016
@@ -1,12 +1,15 @@
 #include "rc.h"
-#include "getflags.h"
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
+
+char flagset[] = "<flag>";	/* anything non-nil will do */
+char *flag[NFLAG];
+
 /*
  * Start executing the given code at the given pc with the given redirection
  */
-char *argv0="rc";
+char *argv0;
 
 void
 start(code *c, int pc, var *local)
@@ -113,6 +116,8 @@
 newvar(char *name, var *next)
 {
 	var *v = new(var);
+
+	assert(name != nil);
 	v->name = name;
 	v->val = 0;
 	v->fn = 0;
@@ -121,62 +126,99 @@
 	v->next = next;
 	return v;
 }
+
+/* fabricate bootstrap code (*=(argv);. /rc/lib/rcmain $*; exit) */
+static void
+loadboot(code *base, int nel, char *rcmain)
+{
+	code *bs;
+
+	bs = base;
+	bs++->i = 1;			/* reference count */
+	bs++->f = Xmark;		/* "* = $*" */
+	bs++->f = Xword;
+	bs++->s="*";
+	bs++->f = Xassign;
+	bs++->f = Xmark;
+	bs++->f = Xmark;
+	bs++->f = Xword;
+	bs++->s="*";
+	bs++->f = Xdol;
+	bs++->f = Xword;
+	bs++->s = rcmain;		/* ". /rc/lib/rcmain $*" */
+	bs++->f = Xword;
+	bs++->s=".";
+	bs++->f = Xsimple;
+	bs++->f = Xexit;		/* exit */
+	bs++->i = 0;			/* not reached */
+	if (bs > base + nel)
+		panic("bootstrap array too small", 0);
+}
+
+void
+usage(void)
+{
+	pfmt(err, "Usage: rc [-srdiIlxepvV] [-c arg] [-m command] "
+		"[file [arg ...]]\n");
+	Exit("bad flags");
+}
+
 /*
  * get command line flags, initialize keywords & traps.
  * get values from environment.
  * set $pid, $cflag, $*
- * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
+ * fabricate bootstrap code and start it
  * start interpreting code
  */
-
 void
 main(int argc, char *argv[])
 {
 	code bootstrap[17];
-	char num[12], *rcmain;
+	char num[12];
 	int i;
-	argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
-	if(argc==-1)
-		usage("[file [arg ...]]");
-	if(argv[0][0]=='-')
+
+	err = openfd(2);
+	ARGBEGIN {
+	case 'd': case 'e': case 'i': case 'l':
+	case 'p': case 'r': case 's': case 'v':
+	case 'x': case 'I': case 'V':
+		flag[ARGC()] = flagset;
+		break;
+	case 'c':
+	case 'm':
+		if (flag[ARGC()])
+			usage();
+		flag[ARGC()] = EARGF(usage());
+		break;
+	default:
+		usage();
+		break;
+	} ARGEND
+	if(argc < 0)
+		usage();
+	if(argv0 == nil)
+		argv0 = "rc";
+	if(argv0[0]=='-')			/* login shell? */
 		flag['l'] = flagset;
 	if(flag['I'])
 		flag['i'] = 0;
-	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
-	rcmain = flag['m']?flag['m'][0]:Rcmain; 
-	err = openfd(2);
+	else if(flag['i']==0 && argc==0 && Isatty(0))
+		flag['i'] = flagset;		/* force interactive */
+
 	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));
-	i = 0;
-	memset(bootstrap, 0, sizeof bootstrap);
-	bootstrap[i++].i = 1;
-	bootstrap[i++].f = Xmark;
-	bootstrap[i++].f = Xword;
-	bootstrap[i++].s="*";
-	bootstrap[i++].f = Xassign;
-	bootstrap[i++].f = Xmark;
-	bootstrap[i++].f = Xmark;
-	bootstrap[i++].f = Xword;
-	bootstrap[i++].s="*";
-	bootstrap[i++].f = Xdol;
-	bootstrap[i++].f = Xword;
-	bootstrap[i++].s = rcmain;
-	bootstrap[i++].f = Xword;
-	bootstrap[i++].s=".";
-	bootstrap[i++].f = Xsimple;
-	bootstrap[i++].f = Xexit;
-	bootstrap[i].i = 0;
+	setvar("cflag", flag['c']? newword(flag['c'], (word *)0): (word *)0);
+	setvar("rcname", newword(argv0, (word *)0));
+
+	loadboot(bootstrap, nelem(bootstrap), (flag['m']? flag['m']: Rcmain));
 	start(bootstrap, 1, (var *)0);
 	/* prime bootstrap argv */
 	pushlist();
-	argv0 = strdup(argv[0]);
-	for(i = argc-1;i!=0;--i) pushword(argv[i]);
+	for(i = argc-1; i >= 0; --i)
+		pushword(argv[i]);
 	for(;;){
 		if(flag['r'])
 			pfnc(err, runq);
@@ -186,6 +228,7 @@
 			dotrap();
 	}
 }
+
 /*
  * Opcode routines
  * Arguments on stack (...)
@@ -226,13 +269,14 @@
  * Xpipewait
  * Xpopm(value)				pop value from stack
  * Xpopredir
+ * Xqdol(name)				concatenate variable components
  * Xrdcmds
  * Xrdfn
  * Xrdwr(file)[fd]			open file for reading and writing
  * Xread(file)[fd]			open file to read
- * Xqdol(name)				concatenate variable components
  * Xreturn				kill thread
  * Xsimple(args)			run command and wait
+ * Xsettrue
  * Xsub
  * Xsubshell{... Xexit}			execute {} in a subshell and wait
  * Xtrue{...}				execute {} if true
@@ -263,7 +307,7 @@
 		Xerror("can't open");
 		return;
 	}
-	Seek(f, 0L, 2);
+	seek(f, 0, 2);
 	pushredir(ROPEN, f, runq->code[runq->pc].i);
 	runq->pc++;
 	poplist();
@@ -692,7 +736,7 @@
 copynwords(word *a, word *tail, int n)
 {
 	word *v, **end;
-	
+
 	v = 0;
 	end = &v;
 	while(n-- > 0){
@@ -930,24 +974,45 @@
 }
 
 void
-Xerror(char *s)
+pargv0(io *f)
 {
 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
-		pfmt(err, "rc: %s: %r\n", s);
+		pfmt(f, "rc: ");
 	else
-		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
+		pfmt(f, "rc (%s): ", argv0);
+}
+
+void
+hisfault(io *f)
+{
+	thread *t;
+
+	for(t = runq; !t->cmdfile && t->ret != 0; t = t->ret)
+		;
+	if(t->cmdfile && !t->iflag)
+		pfmt(f, "%s:%d ", t->cmdfile, t->lineno);
+}
+
+void
+Xerror(char *s)
+{
+	io *msg = openstr();
+
+	pargv0(msg);
+	hisfault(msg);		/* capture errstr before another sys call */
+	pfmt(err, "%s%s: %r\n", (char *)msg->strp, s);
+	closeio(msg);
 	flush(err);
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
 }
 
 void
-Xerror1(char *s)
+Xerror1(char *s)			/* omit errstr */
 {
-	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
-		pfmt(err, "rc: %s\n", s);
-	else
-		pfmt(err, "rc (%s): %s\n", argv0, s);
+	pargv0(err);
+	hisfault(err);
+	pfmt(err, "%s\n", s);
 	flush(err);
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
diff -Nru /n/sources/plan9/sys/src/cmd/rc/fns.h /sys/src/cmd/rc/fns.h
--- /n/sources/plan9/sys/src/cmd/rc/fns.h	Tue Jun 26 23:18:59 2007
+++ /sys/src/cmd/rc/fns.h	Wed Aug 17 00:00:00 2016
@@ -15,7 +15,6 @@
 int	Opendir(char*);
 long	Read(int, void*, long);
 int	Readdir(int, void*, int);
-long	Seek(int, long, long);
 void	Trapinit(void);
 void	Unlink(char*);
 void	Updenv(void);
@@ -23,7 +22,7 @@
 int	Waitfor(int, int);
 long	Write(int, void*, long);
 void	addwaitpid(int);
-int	advance(void);
+Rune	advance(void);
 int	back(int);
 void	cleanhere(char*);
 void	codefree(code*);
@@ -37,7 +36,7 @@
 void	freewords(word*);
 void	globlist(void);
 int	havewaitpid(int);
-int	idchr(int);
+int	idchr(Rune);
 void	inttoascii(char*, long);
 void	kinit(void);
 int	mapfd(int);
@@ -60,8 +59,8 @@
 void	skipnl(void);
 void	start(code*, int, var*);
 int	truestatus(void);
-void	usage(char*);
-int	wordchr(int);
+void	usage(void);
+int	wordchr(Rune);
 void	yyerror(char*);
 int	yylex(void);
 int	yyparse(void);
diff -Nru /n/sources/plan9/sys/src/cmd/rc/getflags.c /sys/src/cmd/rc/getflags.c
--- /n/sources/plan9/sys/src/cmd/rc/getflags.c	Wed Jun 27 04:19:59 2007
+++ /sys/src/cmd/rc/getflags.c	Thu Jan  1 00:00:00 1970
@@ -1,233 +0,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");
-	Exit("bad flags");
-}
-
-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;
-	}
-}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/getflags.h /sys/src/cmd/rc/getflags.h
--- /n/sources/plan9/sys/src/cmd/rc/getflags.h	Tue Jun 26 19:41:42 2007
+++ /sys/src/cmd/rc/getflags.h	Thu Jan  1 00:00:00 1970
@@ -1,7 +0,0 @@
-#define	NFLAG	128
-
-extern char **flag[NFLAG];
-extern char *cmdname;
-extern char *flagset[];
-
-int getflags(int, char*[], char*, int);
diff -Nru /n/sources/plan9/sys/src/cmd/rc/glob.c /sys/src/cmd/rc/glob.c
--- /n/sources/plan9/sys/src/cmd/rc/glob.c	Tue Apr 23 23:15:45 2013
+++ /sys/src/cmd/rc/glob.c	Wed Aug 17 00:00:00 2016
@@ -111,47 +111,21 @@
 	else
 		globsort(globv, svglobv);
 }
-
 /*
  * Do p and q point at equal utf codes
  */
+
 int
-equtf(uchar *p, uchar *q)
+equtf(char *p, char *q)
 {
 	Rune pr, qr;
+
 	if(*p!=*q)
 		return 0;
-	
-	chartorune(&pr, (char*)p);
-	chartorune(&qr, (char*)q);
+	chartorune(&pr, p);
+	chartorune(&qr, q);
 	return pr == qr;
 }
-
-/*
- * Return a pointer to the next utf code in the string,
- * not jumping past nuls in broken utf codes!
- */
-
-uchar*
-nextutf(uchar *p)
-{
-	Rune dummy;
-	return p + chartorune(&dummy, (char*)p);
-}
-
-/*
- * Convert the utf code at *p to a unicode value
- */
-
-int
-unicode(uchar *p)
-{
-	Rune r;
-
-	chartorune(&r, (char*)p);
-	return r;
-}
-
 /*
  * Does the string s match the pattern p
  * . and .. are only matched by patterns starting with .
@@ -173,10 +147,11 @@
 int
 match(void *as, void *ap, int stop)
 {
-	int compl, hit, lo, hi, t, c;
-	uchar *s = as, *p = ap;
+	int compl, hit;
+	Rune c, lo, hi, t;
+	char *s = as, *p = ap, *q;
 
-	for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){
+	for(; *p!=stop && *p!='\0'; s += chartorune(&t, s), p += chartorune(&t, p)){
 		if(*p!=GLOB){
 			if(!equtf(p, s)) return 0;
 		}
@@ -186,12 +161,12 @@
 				return 0;
 			break;
 		case '*':
-			for(;;){
-				if(match(s, nextutf(p), stop)) return 1;
-				if(!*s)
+			/* set q to next utf seq after p */
+			for(q = p + chartorune(&t, p); ; s += chartorune(&t, s))
+				if(match(s, q, stop))
+					return 1;
+				else if(*s == '\0')
 					break;
-				s = nextutf(s);
-			}
 			return 0;
 		case '?':
 			if(*s=='\0')
@@ -200,7 +175,7 @@
 		case '[':
 			if(*s=='\0')
 				return 0;
-			c = unicode(s);
+			chartorune(&c, s);
 			p++;
 			compl=*p=='~';
 			if(compl)
@@ -209,16 +184,14 @@
 			while(*p!=']'){
 				if(*p=='\0')
 					return 0;		/* syntax error */
-				lo = unicode(p);
-				p = nextutf(p);
+				p += chartorune(&lo, p);
 				if(*p!='-')
 					hi = lo;
 				else{
 					p++;
 					if(*p=='\0')
 						return 0;	/* syntax error */
-					hi = unicode(p);
-					p = nextutf(p);
+					p += chartorune(&hi, p);
 					if(hi<lo){ t = lo; lo = hi; hi = t; }
 				}
 				if(lo<=c && c<=hi)
diff -Nru /n/sources/plan9/sys/src/cmd/rc/havefork.c /sys/src/cmd/rc/havefork.c
--- /n/sources/plan9/sys/src/cmd/rc/havefork.c	Wed May 15 18:53:33 2013
+++ /sys/src/cmd/rc/havefork.c	Wed Aug 17 00:00:00 2016
@@ -1,9 +1,7 @@
 #include "rc.h"
-#include "getflags.h"
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-#include <String.h>
 
 int havefork = 1;
 
@@ -83,11 +81,10 @@
 	int pfd[2];
 	char *stop;
 	char utf[UTFmax+1];
-	struct io *f;
+	io *f, *wd;
 	var *ifs = vlook("ifs");
 	word *v, *nextv;
 	Rune r;
-	String *word;
 
 	stop = ifs->val? ifs->val->word: "";
 	if(pipe(pfd)<0){
@@ -110,26 +107,26 @@
 		addwaitpid(pid);
 		close(pfd[PWR]);
 		f = openfd(pfd[PRD]);
-		word = s_new();
+		wd = openstr();
 		v = nil;
 		/* rutf requires at least UTFmax+1 bytes in utf */
 		while((n = rutf(f, utf, &r)) != EOF){
 			utf[n] = '\0';
 			if(utfutf(stop, utf) == nil)
-				s_nappend(word, utf, n);
+				pstr(wd, utf);	/* append utf to word */
 			else
 				/*
 				 * utf/r is an ifs rune (e.g., \t, \n), thus
 				 * ends the current word, if any.
 				 */
-				if(s_len(word) > 0){
-					v = newword(s_to_c(word), v);
-					s_reset(word);
+				if(*(char *)wd->strp != '\0'){
+					v = newword((char *)wd->strp, v);
+					rewind(wd);
 				}
 		}
-		if(s_len(word) > 0)
-			v = newword(s_to_c(word), v);
-		s_free(word);
+		if(*(char *)wd->strp != '\0')
+			v = newword((char *)wd->strp, v);
+		closeio(wd);
 		closeio(f);
 		Waitfor(pid, 0);
 		/* v points to reversed arglist -- reverse it onto argv */
@@ -229,4 +226,4 @@
 	}
 	addwaitpid(pid);
 	return pid;
-}
+}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/haventfork.c /sys/src/cmd/rc/haventfork.c
--- /n/sources/plan9/sys/src/cmd/rc/haventfork.c	Tue May 14 22:06:03 2013
+++ /sys/src/cmd/rc/haventfork.c	Wed Aug 17 00:00:00 2016
@@ -1,5 +1,4 @@
 #include "rc.h"
-#include "getflags.h"
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
@@ -47,7 +46,7 @@
 	}
 
 	runq->pc++;
-	sprint(buf, "%d", pid);
+	snprint(buf, sizeof buf, "%d", pid);
 	setvar("apid", newword(buf, (word *)0));
 }
 
diff -Nru /n/sources/plan9/sys/src/cmd/rc/io.c /sys/src/cmd/rc/io.c
--- /n/sources/plan9/sys/src/cmd/rc/io.c	Tue May 14 22:30:51 2013
+++ /sys/src/cmd/rc/io.c	Wed Aug 17 00:00:00 2016
@@ -23,7 +23,7 @@
 		if(*++fmt == '\0')		/* "blah%"? */
 			break;
 		switch(*fmt){
-		case 'c':
+		case 'c':			/* char, not Rune */
 			pchr(f, va_arg(ap, int));
 			break;
 		case 'd':
@@ -64,7 +64,7 @@
 }
 
 void
-pchr(io *b, int c)
+pchr(io *b, int c)			/* print a char, not a Rune */
 {
 	if(b->bufp==b->ebuf)
 		fullbuf(b, c);
@@ -79,31 +79,39 @@
 	return *b->bufp++;
 }
 
+/*
+ * read next utf sequence from b into buf, and convert it to Rune *r.
+ * return EOF or number of bytes consumed.
+ */
 int
 rutf(io *b, char *buf, Rune *r)
 {
-	int n, i, c;
+	int i, c;
 
 	c = rchr(b);
-	if(c == EOF)
+	if(c == EOF) {
+		buf[0] = 0;
+		*r = EOF;
 		return EOF;
+	}
 	*buf = c;
-	if(c < Runesync){
+	if(c < Runeself){			/* ascii? */
+		buf[1] = 0;
 		*r = c;
 		return 1;
 	}
-	for(i = 1; (c = rchr(b)) != EOF; ){
+
+	/* multi-byte utf sequence */
+	for(i = 1; i <= UTFmax && (c = rchr(b)) != EOF && c >= Runeself; ){
 		buf[i++] = c;
 		buf[i] = 0;
-		if(fullrune(buf, i)){
-			n = chartorune(r, buf);
-			b->bufp -= i - n;	/* push back unconsumed bytes */
-			assert(b->fd == -1 || b->bufp > b->buf);
-			return n;
-		}
+		if(fullrune(buf, i))
+			return chartorune(r, buf);
 	}
-	/* at eof */
-	b->bufp -= i - 1;			/* consume 1 byte */
+
+	/* bad utf sequence: too long, or unexpected ascii or EOF */
+	if (c != EOF && c < Runeself && b->bufp > b->buf)
+		b->bufp--;			/* push back ascii */
 	*r = Runeerror;
 	return runetochar(buf, r);
 }
@@ -123,10 +131,14 @@
 pwrd(io *f, char *s)
 {
 	char *t;
-	for(t = s;*t;t++) if(*t >= 0 && needsrcquote(*t)) break;
-	if(t==s || *t)
+
+	for (t = s; *t; t++)
+		if (*(uchar *)t < Runeself && needsrcquote(*t))
+			break;
+	if (t == s || *t)
 		pquo(f, s);
-	else pstr(f, s);
+	else
+		pstr(f, s);
 }
 
 void
@@ -134,12 +146,14 @@
 {
 	int n;
 	uintptr p;
+	static char uphex[] = "0123456789ABCDEF";
 
 	p = (uintptr)v;
-	if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
-		for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
-
-	for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+	if (sizeof(uintptr) == sizeof(uvlong) && p >> 32)
+		for (n = 60; n >= 32; n -= 4)
+			pchr(f, uphex[(p>>n)&0xF]);
+	for (n = 28; n >= 0; n -= 4)
+		pchr(f, uphex[(p>>n)&0xF]);
 }
 
 void
@@ -244,6 +258,7 @@
 	f->fd = -1;
 	f->bufp = f->strp = emalloc(Stralloc+1);
 	f->ebuf = f->bufp + Stralloc;
+	f->output = 1;
 	memset(f->bufp, '\0', Stralloc+1);
 	return f;
 }
@@ -261,6 +276,7 @@
 	f->fd = -1 /*open("/dev/null", 0)*/;
 	f->bufp = f->strp = buf;
 	f->ebuf = buf+len;
+	f->output = 0;
 	Memcpy(buf, s, len);
 	return f;
 }
@@ -268,11 +284,13 @@
 void
 rewind(io *io)
 {
-	if(io->fd==-1)
+	if(io->fd==-1) {
 		io->bufp = io->strp;
-	else{
+		if (io->output)
+			memset(io->strp, 0, io->ebuf - io->strp);
+	}else{
 		io->bufp = io->ebuf = io->buf;
-		Seek(io->fd, 0L, 0);
+		seek(io->fd, 0, 0);
 	}
 }
 
@@ -290,7 +308,9 @@
 emptybuf(io *f)
 {
 	int n;
-	if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
+
+	if(f->fd == -1 || (n = Read(f->fd, f->buf, NBUF))<=0)
+		return EOF;
 	f->bufp = f->buf;
 	f->ebuf = f->buf + n;
 	return *f->bufp++;
diff -Nru /n/sources/plan9/sys/src/cmd/rc/io.h /sys/src/cmd/rc/io.h
--- /n/sources/plan9/sys/src/cmd/rc/io.h	Tue May 14 22:30:51 2013
+++ /sys/src/cmd/rc/io.h	Wed Aug 17 00:00:00 2016
@@ -5,6 +5,7 @@
 	int	fd;
 	uchar	*bufp, *ebuf, *strp;
 	uchar	buf[NBUF];
+	uchar	output;		/* flag */
 };
 io *err;
 
@@ -13,6 +14,7 @@
 void pchr(io*, int);
 int rchr(io*);
 int rutf(io*, char*, Rune*);
+void rewind(io*);
 void closeio(io*);
 void flush(io*);
 int fullbuf(io*, int);
diff -Nru /n/sources/plan9/sys/src/cmd/rc/lex.c /sys/src/cmd/rc/lex.c
--- /n/sources/plan9/sys/src/cmd/rc/lex.c	Thu Jun 13 23:22:59 2013
+++ /sys/src/cmd/rc/lex.c	Wed Aug 17 00:00:00 2016
@@ -1,35 +1,43 @@
 #include "rc.h"
 #include "exec.h"
 #include "io.h"
-#include "getflags.h"
 #include "fns.h"
-int getnext(void);
+
+Rune getnext(void);
 
 int
-wordchr(int c)
+wordchr(Rune c)		/* is c in the alphabet of words (non-delimiters)? */
 {
-	return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
+	return c != EOF &&
+		(c >= Runeself || strchr("\n \t#;&|^$=`'{}()<>", c) == nil);
 }
 
+/*
+ * is c in the alphabet of identifiers?  as in the c compiler, treat
+ * non-ascii as alphabetic.
+ */
 int
-idchr(int c)
+idchr(Rune c)
 {
 	/*
 	 * Formerly:
 	 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
 	 *	|| c=='_' || c=='*';
 	 */
-	return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
+	return c != EOF && (c >= Runeself ||
+		c > ' ' &&
+		  strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c) == nil);
 }
-int future = EOF;
+
+Rune future = EOF;
 int doprompt = 1;
-int inquote;
-int incomm;
+int inquote;		/* are we processing a quoted word ('...')? */
+int incomm;		/* are we ignoring input in a comment (#...\n)? */
 /*
  * Look ahead in the input stream
  */
 
-int
+Rune
 nextc(void)
 {
 	if(future==EOF)
@@ -40,23 +48,26 @@
  * Consume the lookahead character.
  */
 
-int
+Rune
 advance(void)
 {
-	int c = nextc();
+	Rune c = nextc();
+
 	lastc = future;
 	future = EOF;
 	return c;
 }
 /*
  * read a character from the input stream
- */	
+ */
 
-int
+Rune
 getnext(void)
 {
-	int c;
-	static int peekc = EOF;
+	Rune c;
+	char buf[UTFmax+1];
+	static Rune peekc = EOF;
+
 	if(peekc!=EOF){
 		c = peekc;
 		peekc = EOF;
@@ -66,9 +77,9 @@
 		return EOF;
 	if(doprompt)
 		pprompt();
-	c = rchr(runq->cmdfd);
+	rutf(runq->cmdfd, buf, &c);
 	if(!inquote && c=='\\'){
-		c = rchr(runq->cmdfd);
+		rutf(runq->cmdfd, buf, &c);
 		if(c=='\n' && !incomm){		/* don't continue a comment */
 			doprompt = 1;
 			c=' ';
@@ -105,7 +116,8 @@
 void
 skipwhite(void)
 {
-	int c;
+	Rune c;
+
 	for(;;){
 		c = nextc();
 		/* Why did this used to be  if(!inquote && c=='#') ?? */
@@ -129,18 +141,22 @@
 void
 skipnl(void)
 {
-	int c;
-	for(;;){
+	Rune c, c0;
+
+	for(c0 = nextc(); ; c0 = c){
 		skipwhite();
 		c = nextc();
+		if(c != c0)
+			lastword = 0; /* change of whitespace or c is not ws */
 		if(c!='\n')
 			return;
+		lastword = 0;			/* new line; continue */
 		advance();
 	}
 }
 
 int
-nextis(int c)
+nextis(Rune c)
 {
 	if(nextc()==c){
 		advance();
@@ -150,38 +166,16 @@
 }
 
 char*
-addtok(char *p, int val)
+addutf(char *p, Rune c)
 {
 	if(p==0)
 		return 0;
-	if(p >= &tok[NTOK]){
+	if(p >= &tok[NTOK-1-UTFmax*2]){
 		*p = 0;
 		yyerror("token buffer too short");
 		return 0;
 	}
-	*p++=val;
-	return p;
-}
-
-char*
-addutf(char *p, int c)
-{
-	uchar b, m;
-	int i;
-
-	p = addtok(p, c);	/* 1-byte UTF runes are special */
-	if(c < Runeself)
-		return p;
-
-	m = 0xc0;
-	b = 0x80;
-	for(i=1; i < UTFmax; i++){
-		if((c&m) == b)
-			break;
-		p = addtok(p, advance());
-		b = m;
-		m = (m >> 1)|0x80;
-	}
+	p += runetochar(p, &c);
 	return p;
 }
 
@@ -191,16 +185,17 @@
 int
 yylex(void)
 {
-	int c, d = nextc();
+	Rune c, d = nextc();
 	char *w = tok;
 	struct 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.
+	 * Embarrassing 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(lastword){
 		lastword = 0;
@@ -214,7 +209,6 @@
 			return '^';
 		}
 	}
-	inquote = 0;
 	skipwhite();
 	switch(c = advance()){
 	case EOF:
@@ -357,23 +351,22 @@
 		t = token(tok, WORD);
 		t->quoted = 1;
 		yylval.tree = t;
+		inquote = 0;
 		return t->type;
 	}
 	if(!wordchr(c)){
 		lastdol = 0;
-		tok[0] = c;
-		tok[1]='\0';
+		addutf(tok, c);
 		return c;
 	}
 	for(;;){
 		if(c=='*' || c=='[' || c=='?' || c==GLOB)
-			w = addtok(w, GLOB);
+			w = addutf(w, GLOB);
 		w = addutf(w, c);
 		c = nextc();
 		if(lastdol?!idchr(c):!wordchr(c)) break;
 		advance();
 	}
-
 	lastword = 1;
 	lastdol = 0;
 	if(w!=0)
diff -Nru /n/sources/plan9/sys/src/cmd/rc/mkfile /sys/src/cmd/rc/mkfile
--- /n/sources/plan9/sys/src/cmd/rc/mkfile	Tue Jun 26 20:46:37 2007
+++ /sys/src/cmd/rc/mkfile	Wed Aug 17 00:00:00 2016
@@ -4,7 +4,6 @@
 COMMONOFILES=\
 	code.$O\
 	exec.$O\
-	getflags.$O\
 	glob.$O\
 	here.$O\
 	io.$O\
@@ -29,7 +28,6 @@
 	io.h\
 	exec.h\
 	fns.h\
-	getflags.h\
 
 YFILES=syn.y
 
diff -Nru /n/sources/plan9/sys/src/cmd/rc/pfnc.c /sys/src/cmd/rc/pfnc.c
--- /n/sources/plan9/sys/src/cmd/rc/pfnc.c	Thu Jun 13 23:22:17 2013
+++ /sys/src/cmd/rc/pfnc.c	Wed Aug 17 00:00:00 2016
@@ -63,14 +63,14 @@
 	list *a;
 
 	pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
-	for (i = 0; fname[i].f; i++) 
+	for (i = 0; fname[i].f; i++)
 		if (fname[i].f == fn) {
 			pstr(fd, fname[i].name);
 			break;
 		}
 	if (!fname[i].f)
 		pfmt(fd, "%p", fn);
-	for (a = t->argv; a; a = a->next) 
+	for (a = t->argv; a; a = a->next)
 		pfmt(fd, " (%v)", a->words);
 	pchr(fd, '\n');
 	flush(fd);
diff -Nru /n/sources/plan9/sys/src/cmd/rc/plan9.c /sys/src/cmd/rc/plan9.c
--- /n/sources/plan9/sys/src/cmd/rc/plan9.c	Thu Jun 13 23:21:10 2013
+++ /sys/src/cmd/rc/plan9.c	Wed Aug 17 00:00:00 2016
@@ -7,11 +7,6 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-#include "getflags.h"
-
-enum {
-	Maxenvname = 256,	/* undocumented limit */
-};
 
 char *Signame[] = {
 	"sigexit",	"sighup",	"sigint",	"sigquit",
@@ -63,27 +58,28 @@
 		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;
-		}
+		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:
@@ -101,12 +97,40 @@
 	poplist();
 }
 
+int
+openenv(char *shortname)
+{
+	int f;
+	io *envname;
+
+	envname = openstr();
+	pfmt(envname, "/env/%s", shortname);
+	f = open((char *)envname->strp, OREAD);
+	closeio(envname);
+	return f;
+}
+
+int
+createenv(char *pfx, char *shortname)
+{
+	int f;
+	io *envname;
+
+	envname = openstr();
+	pfmt(envname, "/env/%s%s", pfx, shortname);
+	f = Creat((char *)envname->strp);
+	if (f < 0)
+		pfmt(err, "rc: can't create %s: %r\n", (char *)envname->strp);
+	closeio(envname);
+	return f;
+}
+
 void
 Vinit(void)
 {
 	int dir, f, len, i, n, nent;
-	char *buf, *s;
-	char envname[Maxenvname];
+	char *buf, *s, *name;
+	var *namevar;
 	word *val;
 	Dir *ent;
 
@@ -116,52 +140,52 @@
 		return;
 	}
 	ent = nil;
-	for(;;){
-		nent = dirread(dir, &ent);
-		if(nent <= 0)
-			break;
+	while ((nent = dirread(dir, &ent)) > 0) {
 		for(i = 0; i<nent; i++){
 			len = ent[i].length;
-			if(len && strncmp(ent[i].name, "fn#", 3)!=0){
-				snprint(envname, sizeof envname, "/env/%s", ent[i].name);
-				if((f = open(envname, 0))>=0){
-					buf = emalloc(len+1);
-					n = readn(f, buf, len);
-					if (n <= 0)
-						buf[0] = '\0';
-					else
-						buf[n] = '\0';
-					val = 0;
-					/* Charitably add a 0 at the end if need be */
-					if(buf[len-1])
-						buf[len++]='\0';
-					s = buf+len-1;
-					for(;;){
-						while(s!=buf && s[-1]!='\0') --s;
-						val = newword(s, val);
-						if(s==buf)
-							break;
-						--s;
-					}
-					setvar(ent[i].name, val);
-					vlook(ent[i].name)->changed = 0;
-					close(f);
-					efree(buf);
-				}
+			name = ent[i].name;
+			if(len <= 0 || strncmp(name, "fn#", 3) == 0)
+				continue;
+			if((f = openenv(name)) < 0)
+				continue;
+			buf = emalloc(len+1);
+			n = readn(f, buf, len);
+			if (n <= 0)
+				buf[0] = '\0';
+			else
+				buf[n] = '\0';
+			val = 0;
+			/* Charitably add a 0 at the end if need be */
+			if(buf[len-1])
+				buf[len++]='\0';
+			s = buf+len-1;
+			for(;;){
+				while(s!=buf && s[-1]!='\0')
+					--s;
+				val = newword(s, val);
+				if(s==buf)
+					break;
+				--s;
 			}
+			setvar(name, val);
+			namevar = vlook(name);
+			assert(namevar != nil);
+			namevar->changed = 0;
+			close(f);
+			efree(buf);
 		}
 		free(ent);
 	}
 	close(dir);
 }
+
 int envdir;
 
 void
 Xrdfn(void)
 {
-	int f, len;
+	int f;
 	Dir *e;
-	char envname[Maxenvname];
 	static Dir *ent, *allocent;
 	static int nent;
 
@@ -176,10 +200,8 @@
 		while(nent){
 			e = ent++;
 			nent--;
-			len = e->length;
-			if(len && strncmp(e->name, "fn#", 3)==0){
-				snprint(envname, sizeof envname, "/env/%s", e->name);
-				if((f = open(envname, 0))>=0){
+			if(e->length && strncmp(e->name, "fn#", 3)==0){
+				if((f = openenv(e->name)) >= 0){
 					execcmds(openfd(f));
 					return;
 				}
@@ -189,6 +211,7 @@
 	close(envdir);
 	Xreturn();
 }
+
 union code rdfns[4];
 
 void
@@ -222,6 +245,9 @@
 		return 0;
 
 	while((w = wait()) != nil){
+		/* this would otherwise go unreported by rc */
+		if(strstr(w->msg, "error in demand load") != nil)
+			pfmt(err, "rc: %s\n", w->msg);
 		delwaitpid(w->pid);
 		if(w->pid==pid){
 			setstatus(w->msg);
@@ -254,27 +280,20 @@
 void
 addenv(var *v)
 {
-	char envname[Maxenvname];
 	word *w;
 	int f;
 	io *fd;
 	if(v->changed){
 		v->changed = 0;
-		snprint(envname, sizeof envname, "/env/%s", v->name);
-		if((f = Creat(envname))<0)
-			pfmt(err, "rc: can't open %s: %r\n", envname);
-		else{
+		if((f = createenv("", v->name)) >= 0) {
 			for(w = v->val;w;w = w->next)
-				write(f, w->word, strlen(w->word)+1L);
+				write(f, w->word, strlen(w->word)+1);
 			close(f);
 		}
 	}
 	if(v->fnchanged){
 		v->fnchanged = 0;
-		snprint(envname, sizeof envname, "/env/fn#%s", v->name);
-		if((f = Creat(envname))<0)
-			pfmt(err, "rc: can't open %s: %r\n", envname);
-		else{
+		if((f = createenv("fn#", v->name)) >= 0) {
 			if(v->fn){
 				fd = openfd(f);
 				pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
@@ -339,43 +358,48 @@
 Execute(word *args, word *path)
 {
 	char **argv = mkargv(args);
-	char file[1024], errstr[1024];
+	char file[1024], errstr[ERRMAX+1];
 	int nc;
 
 	Updenv();
 	errstr[0] = '\0';
 	for(;path;path = path->next){
 		nc = strlen(path->word);
-		if(nc < sizeof file - 1){	/* 1 for / */
-			strcpy(file, path->word);
-			if(file[0]){
-				strcat(file, "/");
-				nc++;
-			}
-			if(nc + strlen(argv[1]) < sizeof file){
-				strcat(file, argv[1]);
-				exec(file, argv+1);
-				rerrstr(errstr, sizeof errstr);
-				/*
-				 * if file exists and is executable, exec should
-				 * have worked, unless it's a directory or an
-				 * executable for another architecture.  in
-				 * particular, if it failed due to lack of
-				 * swap/vm (e.g., arg. list too long) or other
-				 * allocation failure, stop searching and print
-				 * the reason for failure.
-				 */
-				if (strstr(errstr, " allocat") != nil ||
-				    strstr(errstr, " full") != nil)
-					break;
-			}
-			else werrstr("command name too long");
+		if(nc >= sizeof file - 1){	/* 1 for / */
+			werrstr("path component too long");
+			continue;
 		}
+		strcpy(file, path->word);
+		if(file[0]){
+			strcat(file, "/");
+			nc++;
+		}
+		if(nc + strlen(argv[1]) >= sizeof file){
+			werrstr("command name too long");
+			continue;
+		}
+		strcat(file, argv[1]);
+		exec(file, argv+1);
+		/*
+		 * if file exists and is executable, exec should have worked,
+		 * unless it's a directory or an executable for another
+		 * architecture.  in particular, if it failed due to lack of
+		 * swap/vm (e.g., arg. list too long) or other allocation or
+		 * i/o failure, stop searching and print the reason for failure.
+		 */
+		rerrstr(errstr, sizeof errstr);
+		if (strstr(errstr, " allocat") != nil ||
+		    strstr(errstr, " full") != nil ||
+		    strstr(errstr, "i/o error") != nil)
+			break;
 	}
+	if(errstr[0] == '\0')		/* pick up any werrstr "too long"s */
+		rerrstr(errstr, sizeof errstr);
 	pfmt(err, "%s: %s\n", argv[1], errstr);
 	efree((char *)argv);
 }
-#define	NDIR	256		/* shoud be a better way */
+
+#define	NDIR	256		/* should be a better way */
 
 int
 Globsize(char *p)
@@ -438,7 +462,7 @@
  * onlydirs is advisory -- it means you only
  * need to return the directories.  it's okay to
  * return files too (e.g., on unix where you can't
- * tell during the readdir), but that just makes 
+ * tell during the readdir), but that just makes
  * the globber work harder.
  */
 int
@@ -458,7 +482,7 @@
 				n = trimdirs(dir[f].dbuf, n);
 				if(n == 0)
 					goto Again;
-			}	
+			}
 			dir[f].n = n;
 		}else
 			dir[f].n = 0;
@@ -482,24 +506,29 @@
 	}
 	close(f);
 }
+
 int interrupted = 0;
+
 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;
-	}
+
+	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;
+		}
 	pfmt(err, "rc: note: %s\n", s);
 	noted(NDFLT);
 	return;
 Out:
-	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
+	if (strcmp(s, "interrupt") != 0 || trap[i] == 0) {
 		trap[i]++;
 		ntrap++;
 	}
-	if(ntrap>=32){	/* rc is probably in a trap loop */
+	if (ntrap >= 32) {	/* rc is probably in a trap loop */
 		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
 		abort();
 	}
@@ -530,12 +559,6 @@
 	return read(fd, buf, cnt);
 }
 
-long
-Seek(int fd, long cnt, long whence)
-{
-	return seek(fd, cnt, whence);
-}
-
 int
 Executable(char *file)
 {
@@ -553,7 +576,7 @@
 int
 Creat(char *file)
 {
-	return create(file, 1, 0666L);
+	return create(file, 1, 0666);
 }
 
 int
@@ -640,7 +663,7 @@
 delwaitpid(int pid)
 {
 	int r, w;
-	
+
 	for(r=w=0; r<nwaitpids; r++)
 		if(waitpids[r] != pid)
 			waitpids[w++] = waitpids[r];
@@ -669,4 +692,4 @@
 _efgfmt(Fmt *)
 {
 	return -1;
-}
+}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/rc.h /sys/src/cmd/rc/rc.h
--- /n/sources/plan9/sys/src/cmd/rc/rc.h	Thu Jun 13 23:14:33 2013
+++ /sys/src/cmd/rc/rc.h	Wed Aug 17 00:00:00 2016
@@ -1,28 +1,38 @@
 /*
  * Assume plan 9 by default; if Unix is defined, assume unix.
- * Please don't litter the code with ifdefs.  The five below should be enough.
+ * Please don't litter the code with ifdefs.  The three below should be enough.
  */
 
+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 redir redir;
+typedef struct thread thread;
+typedef struct builtin builtin;
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')	/* NB: unsafe macro */
+
 #ifndef Unix
 /* plan 9 */
 #include <u.h>
 #include <libc.h>
 
+#pragma incomplete word
+#pragma incomplete io
+
+/* unix compatibility */
+#define unixclsexec(wdirfd)
+
 #define	NSIG	32
 #define	SIGINT	2
 #define	SIGQUIT	3
-
-#define fcntl(fd, op, arg)	/* unix compatibility */
-#define F_SETFD
-#define FD_CLOEXEC
 #else
 #include "unix.h"
 #endif
 
-#ifndef ERRMAX
-#define ERRMAX 128
-#endif
-
 #define	YYMAXDEPTH	500
 #ifndef YYPREFIX
 #ifndef PAREN
@@ -30,21 +40,6 @@
 #endif
 #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 redir redir;
-typedef struct thread thread;
-typedef struct builtin builtin;
-
-#ifndef Unix
-#pragma incomplete word
-#pragma incomplete io
-#endif
-
 struct tree{
 	int	type;
 	int	rtype, fd0, fd1;	/* details of REDIR PIPE DUP tokens */
@@ -147,5 +142,10 @@
  */
 int ndot;
 char *getstatus(void);
-int lastc;
+Rune lastc;
 int lastword;
+
+#define	NFLAG	128		/* limited to ascii */
+
+extern char *flag[NFLAG];
+extern char flagset[];
diff -Nru /n/sources/plan9/sys/src/cmd/rc/rune.c /sys/src/cmd/rc/rune.c
--- /n/sources/plan9/sys/src/cmd/rc/rune.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/rc/rune.c	Wed Aug 17 00:00:00 2016
@@ -0,0 +1,165 @@
+#include "rc.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define	RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+	Bitx	= Bit(1),
+
+	Tx	= T(1),			/* 1000 0000 */
+	Rune1 = (1<<(Bit(0)+0*Bitx))-1,	/* 0000 0000 0000 0000 0111 1111 */
+
+	Maskx	= (1<<Bitx)-1,		/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,		/* 1100 0000 */
+
+	SurrogateMin	= 0xD800,
+	SurrogateMax	= 0xDFFF,
+
+	Bad	= Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+	int c[UTFmax], i;
+	Rune l;
+
+	/*
+	 * N character sequence
+	 *	00000-0007F => T1
+	 *	00080-007FF => T2 Tx
+	 *	00800-0FFFF => T3 Tx Tx
+	 *	10000-10FFFF => T4 Tx Tx Tx
+	 */
+
+	c[0] = *(uchar*)(str);
+	if(c[0] < Tx){
+		*rune = c[0];
+		return 1;
+	}
+	l = c[0];
+
+	for(i = 1; i < UTFmax; i++) {
+		c[i] = *(uchar*)(str+i);
+		c[i] ^= Tx;
+		if(c[i] & Testx)
+			goto bad;
+		l = (l << Bitx) | c[i];
+		if(c[0] < T(i + 2)) {
+			l &= RuneX(i + 1);
+			if(i == 1) {
+				if(c[0] < T(2) || l <= Rune1)
+					goto bad;
+			} else if(l <= RuneX(i) || l > Runemax)
+				goto bad;
+			if (i == 2 && SurrogateMin <= l && l <= SurrogateMax)
+				goto bad;
+			*rune = l;
+			return i + 1;
+		}
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+	int i, j;
+	Rune c;
+
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 * four character sequence (21-bit value)
+	 *     10000-1FFFFF => T4 Tx Tx Tx
+	 * If the Rune is out of range or a surrogate half,
+	 * convert it to the error rune.
+	 * Do this test when i==3 because the error rune encodes to three bytes.
+	 * Doing it earlier would duplicate work, since an out of range
+	 * Rune wouldn't have fit in one or two bytes.
+	 */
+	for(i = 2; i < UTFmax + 1; i++){
+		if(i == 3){
+			if(c > Runemax)
+				c = Runeerror;
+			if(SurrogateMin <= c && c <= SurrogateMax)
+				c = Runeerror;
+		}
+		if (c <= RuneX(i) || i == UTFmax ) {
+			str[0] = T(i) |  (c >> (i - 1)*Bitx);
+			for(j = 1; j < i; j++)
+				str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx);
+			return i;
+		}
+	}
+	return UTFmax;
+}
+
+int
+runelen(long c)
+{
+	Rune rune;
+	char str[10];
+
+	rune = c;
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+	int nb, i;
+	Rune c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1){
+			nb++;
+		} else {
+			for(i = 2; i < UTFmax + 1; i++)
+				if(c <= RuneX(i) || i == UTFmax){
+					nb += i;
+					break;
+				}
+		}
+	}
+	return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+	int  i;
+	Rune c;
+
+	if(n <= 0)
+		return 0;
+	c = *(uchar*)str;
+	if(c < Tx)
+		return 1;
+	for(i = 3; i < UTFmax + 1; i++)
+		if(c < T(i))
+			return n >= i - 1;
+	return n >= UTFmax;
+}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/simple.c /sys/src/cmd/rc/simple.c
--- /n/sources/plan9/sys/src/cmd/rc/simple.c	Thu Jun 13 23:21:01 2013
+++ /sys/src/cmd/rc/simple.c	Wed Aug 17 00:00:00 2016
@@ -2,7 +2,6 @@
  * Maybe `simple' is a misnomer.
  */
 #include "rc.h"
-#include "getflags.h"
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
@@ -10,7 +9,8 @@
  * Search through the following code to see if we're just going to exit.
  */
 int
-exitnext(void){
+exitnext(void)
+{
 	union code *c=&runq->code[runq->pc];
 	while(c->f==Xpopredir) c++;
 	return c->f==Xexit;
@@ -146,7 +146,7 @@
 		if(wdirfd==-2)	/* try only once */
 			wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
 		if(wdirfd>=0) {
-			fcntl(wdirfd, F_SETFD, FD_CLOEXEC);
+			unixclsexec(wdirfd);
 			write(wdirfd, word, strlen(word));
 		}
 	}
@@ -264,15 +264,6 @@
 }
 
 int
-octal(char *s)
-{
-	int n = 0;
-	while(*s==' ' || *s=='\t' || *s=='\n') s++;
-	while('0'<=*s && *s<='7') n = n*8+*s++-'0';
-	return n;
-}
-
-int
 mapfd(int fd)
 {
 	redir *rp;
@@ -447,7 +438,8 @@
 }
 
 void
-execwhatis(void){	/* mildly wrong -- should fork before writing */
+execwhatis(void)	/* mildly wrong -- should fork before writing */
+{
 	word *a, *b, *path;
 	var *v;
 	struct builtin *bp;
diff -Nru /n/sources/plan9/sys/src/cmd/rc/syn.y /sys/src/cmd/rc/syn.y
--- /n/sources/plan9/sys/src/cmd/rc/syn.y	Sun Dec 12 01:11:23 1999
+++ /sys/src/cmd/rc/syn.y	Wed Aug 17 00:00:00 2016
@@ -45,7 +45,7 @@
 |	IF NOT {skipnl();} cmd	{$$=mung1($2, $4);}
 |	FOR '(' word IN words ')' {skipnl();} cmd
 	/*
-	 * if ``words'' is nil, we need a tree element to distinguish between 
+	 * if ``words'' is nil, we need a tree element to distinguish between
 	 * for(i in ) and for(i), the former being a loop over the empty set
 	 * and the latter being the implicit argument loop.  so if $5 is nil
 	 * (the empty set), we represent it as "()".  don't parenthesize non-nil
@@ -73,7 +73,7 @@
 simple:	first
 |	simple word		{$$=tree2(ARGLIST, $1, $2);}
 |	simple redir		{$$=tree2(ARGLIST, $1, $2);}
-first:	comword	
+first:	comword
 |	first '^' word		{$$=tree2('^', $1, $3);}
 word:	keyword			{lastword=1; $1->type=WORD;}
 |	comword
diff -Nru /n/sources/plan9/sys/src/cmd/rc/tree.c /sys/src/cmd/rc/tree.c
--- /n/sources/plan9/sys/src/cmd/rc/tree.c	Tue Jun 26 22:52:20 2007
+++ /sys/src/cmd/rc/tree.c	Wed Aug 17 00:00:00 2016
@@ -138,7 +138,7 @@
 freetree(tree *p)
 {
 	if(p==0)
-		return;	
+		return;
 	freetree(p->child[0]);
 	freetree(p->child[1]);
 	freetree(p->child[2]);
diff -Nru /n/sources/plan9/sys/src/cmd/rc/unix.c /sys/src/cmd/rc/unix.c
--- /n/sources/plan9/sys/src/cmd/rc/unix.c	Fri Mar  1 22:25:23 2013
+++ /sys/src/cmd/rc/unix.c	Wed Aug 17 00:00:00 2016
@@ -6,7 +6,6 @@
 #include "rc.h"
 #include "io.h"
 #include "exec.h"
-#include "getflags.h"
 #include <errno.h>
 
 char *Rcmain = "/usr/lib/rcmain";
@@ -431,11 +430,6 @@
 {
 	return read(fd, buf, cnt);
 }
-Seek(fd, cnt, whence)
-long cnt;
-{
-	return lseek(fd, cnt, whence);
-}
 Executable(file)
 char *file;
 {
@@ -489,6 +483,15 @@
 	abort();
 }
 
+int
+octal(char *s)
+{
+	int n = 0;
+	while(*s==' ' || *s=='\t' || *s=='\n') s++;
+	while('0'<=*s && *s<='7') n = n*8+*s++-'0';
+	return n;
+}
+
 void
 execumask(void)		/* wrong -- should fork before writing */
 {
@@ -549,6 +552,12 @@
 rfork(int bits)
 {
 	return fork();
+}
+
+void
+unixclsexec(int fd)
+{
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
 }
 
 int *waitpids;
diff -Nru /n/sources/plan9/sys/src/cmd/rc/unix.h /sys/src/cmd/rc/unix.h
--- /n/sources/plan9/sys/src/cmd/rc/unix.h	Fri Mar  1 22:55:48 2013
+++ /sys/src/cmd/rc/unix.h	Wed Aug 17 00:00:00 2016
@@ -1,3 +1,5 @@
+/* mostly plan 9 compatibility */
+
 #undef _BSD_EXTENSION		/* avoid multiple def'n if predefined */
 #undef _PLAN9_SOURCE
 #undef _POSIX_SOURCE
@@ -22,17 +24,29 @@
 #define NSIG 32
 #endif
 
-/* plan 9 compatibility */
 #define RFPROC 1
 #define RFFDG 1
 #define RFNOTEG 1
 
-#define uintptr uintptr_t
+#define OREAD	O_RDONLY
+#define OWRITE	O_WRONLY
+#define ORDWR	O_RDWR
+#define OCEXEC	0
 
-char *strdup(const char *);
+#define ERRMAX 128
 
+#define uintptr uintptr_t
 #define nil ((void*)0)
 
+#define assert(cond)
+#define seek lseek
+#define print printf
+#define fprint fprintf
+#define snprint snprintf
+
+char *strdup(const char *);
+void unixclsexec(int);
+
 /* in case uchar, etc. are built-in types */
 #define uchar	_fmtuchar
 #define ushort	_fmtushort
@@ -47,7 +61,52 @@
 typedef unsigned long		ulong;
 typedef unsigned long long	uvlong;
 
-#define OREAD	O_RDONLY
-#define OWRITE	O_WRONLY
-#define ORDWR	O_RDWR
-#define OCEXEC	0
+typedef ulong Rune;
+
+enum
+{
+	UTFmax		= 4,		/* maximum bytes per rune */
+	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
+	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
+	Runeerror	= 0xFFFD,	/* decoding error in UTF */
+	Runemax		= 0x10FFFF,	/* 21-bit rune */
+	Runemask	= 0x1FFFFF,	/* bits used by runes (see grep) */
+};
+
+/*
+ * rune routines
+ */
+extern	int	runetochar(char*, Rune*);
+extern	int	chartorune(Rune*, char*);
+extern	int	runelen(long);
+extern	int	runenlen(Rune*, int);
+extern	int	fullrune(char*, int);
+extern	int	utflen(char*);
+extern	int	utfnlen(char*, long);
+extern	char*	utfrune(char*, long);
+extern	char*	utfrrune(char*, long);
+extern	char*	utfutf(char*, char*);
+extern	char*	utfecpy(char*, char*, char*);
+
+extern char *argv0;
+#define	ARGBEGIN	for((argv0||(argv0=*argv)),argv++,argc--;\
+			    argv[0] && argv[0][0]=='-' && argv[0][1];\
+			    argc--, argv++) {\
+				char *_args, *_argt;\
+				Rune _argc;\
+				_args = &argv[0][1];\
+				if(_args[0]=='-' && _args[1]==0){\
+					argc--; argv++; break;\
+				}\
+				_argc = 0;\
+				while(*_args && (_args += chartorune(&_argc, _args)))\
+				switch(_argc)
+#define	ARGEND		SET(_argt);USED(_argt,_argc,_args);}USED(argv, argc);
+#define	ARGF()		(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define	EARGF(x)	(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
+
+#define	ARGC()		_argc
+
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
diff -Nru /n/sources/plan9/sys/src/cmd/rc/utfrune.c /sys/src/cmd/rc/utfrune.c
--- /n/sources/plan9/sys/src/cmd/rc/utfrune.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/rc/utfrune.c	Wed Aug 17 00:00:00 2016
@@ -0,0 +1,28 @@
+#include "rc.h"
+
+char*
+utfrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return s;
+		s += n;
+	}
+}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/utfutf.c /sys/src/cmd/rc/utfutf.c
--- /n/sources/plan9/sys/src/cmd/rc/utfutf.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/rc/utfutf.c	Wed Aug 17 00:00:00 2016
@@ -0,0 +1,24 @@
+#include "rc.h"
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+utfutf(char *s1, char *s2)
+{
+	char *p;
+	long f, n1, n2;
+	Rune r;
+
+	n1 = chartorune(&r, s2);
+	f = r;
+	if(f <= Runesync)		/* represents self */
+		return strstr(s1, s2);
+
+	n2 = strlen(s2);
+	for(p=s1; p=utfrune(p, f); p+=n1)
+		if(strncmp(p, s2, n2) == 0)
+			return p;
+	return 0;
+}
diff -Nru /n/sources/plan9/sys/src/cmd/rc/var.c /sys/src/cmd/rc/var.c
--- /n/sources/plan9/sys/src/cmd/rc/var.c	Thu Jun 13 23:22:45 2013
+++ /sys/src/cmd/rc/var.c	Wed Aug 17 00:00:00 2016
@@ -67,7 +67,10 @@
 {
 	int h = hash(name, NVAR);
 	var *v;
-	for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
+
+	for (v = gvar[h]; v; v = v->next)
+		if (strcmp(v->name, name) == 0)
+			return v;
 	return gvar[h] = newvar(strdup(name), gvar[h]);
 }
 
@@ -75,9 +78,11 @@
 vlook(char *name)
 {
 	var *v;
-	if(runq)
-		for(v = runq->local;v;v = v->next)
-			if(strcmp(v->name, name)==0) return v;
+
+	if (runq)
+		for (v = runq->local; v; v = v->next)
+			if (strcmp(v->name, name) == 0)
+				return v;
 	return gvlook(name);
 }
 
diff -Nru /n/sources/plan9/sys/src/cmd/rc/win32.c /sys/src/cmd/rc/win32.c
--- /n/sources/plan9/sys/src/cmd/rc/win32.c	Fri Mar  1 19:53:47 2013
+++ /sys/src/cmd/rc/win32.c	Wed Aug 17 00:00:00 2016
@@ -7,7 +7,6 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-#include "getflags.h"
 char *Signame[] = {
 	"sigexit",	"sighup",	"sigint",	"sigquit",
 	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
@@ -456,12 +455,6 @@
 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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.