[hackers] [9base] upgraded 9base to p9p 20090731 || Anselm R Garbe

From: <hg_AT_suckless.org>
Date: Fri, 31 Jul 2009 20:03:15 +0000 (UTC)

changeset: 28:1161d90df941
tag: tip
user: Anselm R Garbe <anselm_AT_garbe.us>
date: Fri Jul 31 21:02:58 2009 +0100
files: Makefile awk/README awk/awk.h awk/awkgram.y awk/lex.c awk/lib.c awk/main.c awk/maketab.c awk/parse.c awk/proto.h awk/re.c awk/run.c awk/tran.c bc/bc.1 bc/bc.y config.mk dc/dc.c grep/comp.c grep/main.c grep/sub.c lib9/Makefile lib9/_exits.c lib9/_p9dialparse.c lib9/_p9dir.c lib9/atexit.c lib9/bio.h lib9/bio/bbuffered.c lib9/bio/bflush.c lib9/bio/bgetc.c lib9/bio/bgetd.c lib9/bio/binit.c lib9/bio/boffset.c lib9/bio/brdline.c lib9/bio/brdstr.c lib9/bio/bread.c lib9/bio/bseek.c lib9/bio/bvprint.c lib9/bio/bwrite.c lib9/bio/lib9.std.h lib9/convD2M.c lib9/convM2D.c lib9/convM2S.c lib9/convS2M.c lib9/crypt.c lib9/ctime.c lib9/debugmalloc.c lib9/dial.c lib9/dirfwstat.c lib9/dirread.c lib9/dirwstat.c lib9/encodefmt.c lib9/errstr.c lib9/exitcode.c lib9/fcallfmt.c lib9/fmt.h lib9/fmt/LICENSE lib9/fmt/NOTICE lib9/fmt/README lib9/fmt/charstod.c lib9/fmt/dofmt.c lib9/fmt/dorfmt.c lib9/fmt/errfmt.c lib9/fmt/fltfmt.c lib9/fmt/fmt.c lib9/fmt/fmtdef.h lib9/fmt/fmtfd.c lib9/fmt/fmtfdflush.c lib9/fmt/fmtlocale.c li
b9/fmt/fmtlock.c lib9/fmt/fmtnull.c lib9/fmt/fmtprint.c lib9/fmt/fmtquote.c lib9/fmt/fmtrune.c lib9/fmt/fmtstr.c lib9/fmt/fmtvprint.c lib9/fmt/fprint.c lib9/fmt/nan.h lib9/fmt/nan64.c lib9/fmt/plan9.h lib9/fmt/pow10.c lib9/fmt/print.c lib9/fmt/runefmtstr.c lib9/fmt/runeseprint.c lib9/fmt/runesmprint.c lib9/fmt/runesnprint.c lib9/fmt/runesprint.c lib9/fmt/runevseprint.c lib9/fmt/runevsmprint.c lib9/fmt/runevsnprint.c lib9/fmt/seprint.c lib9/fmt/smprint.c lib9/fmt/snprint.c lib9/fmt/sprint.c lib9/fmt/strtod.c lib9/fmt/test.c lib9/fmt/vfprint.c lib9/fmt/vseprint.c lib9/fmt/vsmprint.c lib9/fmt/vsnprint.c lib9/getcallerpc-arm.c lib9/getnetconn.c lib9/getns.c lib9/lib9.h lib9/libc.h lib9/malloctag.c lib9/nan.c lib9/netcrypt.c lib9/netmkaddr.c lib9/notify.c lib9/nrand.c lib9/nulldir.c lib9/opentemp.c lib9/pin.c lib9/portdate lib9/post9p.c lib9/rand.c lib9/readn.c lib9/regex/regcomp.c lib9/regex/regexec.c lib9/regex/rregexec.c lib9/rfork.c lib9/sendfd.c lib9/sleep.c lib9/sysfatal.c lib9/test.c lib9/testfltfmt.c lib9
/testfmt.c lib9/testprint.c lib9/tm2sec.c lib9/truerand.c lib9/u.h lib9/utf.h lib9/utf/NOTICE lib9/utf/README lib9/utf/lib9.h lib9/utf/rune.c lib9/utf/utfecpy.c lib9/write.c lib9/zoneinfo.c lib9/zoneinfo.h ls/ls.c mk/Makefile mk/NOTICE mk/README mk/arc.c mk/archive.c mk/bufblock.c mk/env.c mk/file.c mk/fns.h mk/graph.c mk/job.c mk/lex.c mk/main.c mk/match.c mk/mk.1 mk/mk.c mk/mk.h mk/parse.c mk/rc.c mk/recipe.c mk/rule.c mk/run.c mk/sh.c mk/shell.c mk/shprint.c mk/symtab.c mk/sys.h mk/sys.std.h mk/unix.c mk/var.c mk/varsub.c mk/word.c rc/Makefile rc/code.c rc/exec.c rc/exec.h rc/fns.h rc/getflags.c rc/glob.c rc/havefork.c rc/here.c rc/io.c rc/io.h rc/lex.c rc/pcmd.c rc/pfnc.c rc/plan9ish.c rc/rc.1 rc/rc.h rc/simple.c rc/subr.c rc/trap.c rc/tree.c rc/unixcrap.c rc/var.c sed/sed.1 sed/sed.c sort/sort.c test/test.1 test/test.c touch/touch.c yacc/yacc.c
description:
upgraded 9base to p9p 20090731

diff -r bb17f966e24a -r 1161d90df941 Makefile
--- a/Makefile Thu Feb 09 13:39:50 2006 +0100
+++ b/Makefile Fri Jul 31 21:02:58 2009 +0100
@@ -4,7 +4,7 @@
 include config.mk
 
 SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \
- mk rc read sed seq sleep sort tee test touch tr uniq
+ rc read sed seq sleep sort tee test touch tr uniq
 
 all:
         @echo 9base build options:
diff -r bb17f966e24a -r 1161d90df941 awk/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/awk/README Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,13 @@
+This 'awk' source is directly downloaded from the Plan 9 source
+
+http://cm.bell-labs.com/sources/plan9/sys/src/cmd/awk/
+
+as such, it's copyright is held by Lucent Technologies and distributed under the
+Lucent Public License version 1.02 [http://www.opensource.org/licenses/lucent1.02.php].
+
+Modifications were made by Jeff Sickel in order to build using Plan 9 from User
+Space [http://swtch.com/plan9port/] to the following files:
+
+ mkfile
+ re.c
+
diff -r bb17f966e24a -r 1161d90df941 awk/awk.h
--- a/awk/awk.h Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/awk.h Fri Jul 31 21:02:58 2009 +0100
@@ -182,3 +182,4 @@
 #define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR )
 
 #include "proto.h"
+
diff -r bb17f966e24a -r 1161d90df941 awk/awkgram.y
--- a/awk/awkgram.y Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/awkgram.y Fri Jul 31 21:02:58 2009 +0100
@@ -486,3 +486,4 @@
                 }
         }
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/lex.c
--- a/awk/lex.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/lex.c Fri Jul 31 21:02:58 2009 +0100
@@ -86,8 +86,8 @@
         { "system", FSYSTEM, BLTIN },
         { "tolower", FTOLOWER, BLTIN },
         { "toupper", FTOUPPER, BLTIN },
+ { "utf", FUTF, BLTIN },
         { "while", WHILE, WHILE },
- { "utf", FUTF, BLTIN },
 };
 
 #define DEBUG
@@ -567,3 +567,4 @@
         for (i = strlen(s)-1; i >= 0; i--)
                 unput(s[i]);
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/lib.c
--- a/awk/lib.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/lib.c Fri Jul 31 21:02:58 2009 +0100
@@ -673,6 +673,32 @@
 {
         double r;
         char *ep;
+
+ /*
+ * fast could-it-be-a-number check before calling strtod,
+ * which takes a surprisingly long time to reject non-numbers.
+ */
+ switch (*s) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ case '-':
+ case '+':
+ case '.':
+ case 'n': /* nans */
+ case 'N':
+ case 'i': /* infs */
+ case 'I':
+ break;
+ default:
+ return 0; /* can't be a number */
+ }
+
         errno = 0;
         r = strtod(s, &ep);
         if (ep == s || r == HUGE_VAL || errno == ERANGE)
@@ -684,3 +710,4 @@
         else
                 return 0;
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/main.c
--- a/awk/main.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/main.c Fri Jul 31 21:02:58 2009 +0100
@@ -57,7 +57,7 @@
 
         cmdname = argv[0];
         if (argc == 1) {
- fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname);
+ fprintf(stderr, "Usage: %s [-F fieldsep] [-mf n] [-mr n] [-v var=value] [-f programfile | 'program'] [file ...]\n", cmdname);
                 exit(1);
         }
         signal(SIGFPE, fpecatch);
@@ -195,3 +195,4 @@
         else
                 return NULL;
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/maketab.c
--- a/awk/maketab.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/maketab.c Fri Jul 31 21:02:58 2009 +0100
@@ -166,3 +166,4 @@
         printf("}\n");
         return 0;
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/parse.c
--- a/awk/parse.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/parse.c Fri Jul 31 21:02:58 2009 +0100
@@ -269,3 +269,4 @@
 {
         return (Node *) (long) i;
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/proto.h
--- a/awk/proto.h Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/proto.h Fri Jul 31 21:02:58 2009 +0100
@@ -21,6 +21,8 @@
 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
+
+#define getline p9getline
 
 extern int yywrap(void);
 extern void setfname(Cell *);
@@ -175,3 +177,4 @@
 
 extern FILE *popen(const char *, const char *);
 extern int pclose(FILE *);
+
diff -r bb17f966e24a -r 1161d90df941 awk/re.c
--- a/awk/re.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/re.c Fri Jul 31 21:02:58 2009 +0100
@@ -25,15 +25,13 @@
 
 #define DEBUG
 #include <stdio.h>
+#include <u.h>
+#include <libc.h>
 #include <ctype.h>
-#include <setjmp.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
+#include <bio.h>
+#include <regexp.h>
 #include "awk.h"
 #include "y.tab.h"
-#include "regexp.h"
 
         /* This file provides the interface between the main body of
          * awk and the pattern matching package. It preprocesses
@@ -187,7 +185,7 @@
 
         /* T/F match indication - matched string not exported */
 int
-match(void *p, char *s, char *q)
+match(void *p, char *s, char *start)
 {
         return regexec((Reprog *) p, (char *) s, 0, 0);
 }
@@ -222,10 +220,11 @@
 }
 /* in the parsing of regular expressions, metacharacters like . have */
 /* to be seen literally; \056 is not a metacharacter. */
-int
+
+int
 hexstr(char **pp) /* find and eval hex string at pp, return new p */
 {
- int c;
+ char c;
         int n = 0;
         int i;
 
@@ -323,3 +322,4 @@
 {
         FATAL("%s", "regular expression too big");
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/run.c
--- a/awk/run.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/run.c Fri Jul 31 21:02:58 2009 +0100
@@ -133,6 +133,7 @@
 
 Cell *execute(Node *u) /* execute a node of the parse tree */
 {
+ int nobj;
         Cell *(*proc)(Node **, int);
         Cell *x;
         Node *a;
@@ -149,10 +150,11 @@
                                 recbld();
                         return(x);
                 }
- if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
+ nobj = a->nobj;
+ if (notlegal(nobj)) /* probably a Cell* but too risky to print */
                         FATAL("illegal statement");
- proc = proctab[a->nobj-FIRSTTOKEN];
- x = (*proc)(a->narg, a->nobj);
+ proc = proctab[nobj-FIRSTTOKEN];
+ x = (*proc)(a->narg, nobj);
                 if (isfld(x) && !donefld)
                         fldbld();
                 else if (isrec(x) && !donerec)
@@ -901,8 +903,10 @@
                         if (isnum(x)) {
                                 if (getfval(x))
                                         sprintf(p, fmt, (int) getfval(x));
- else
+ else{
                                         *p++ = '\0';
+ *p = '\0';
+ }
                         } else
                                 sprintf(p, fmt, getsval(x)[0]);
                         break;
@@ -1540,6 +1544,7 @@
 
 Cell *printstat(Node **a, int n) /* print a[0] */
 {
+ int r;
         Node *x;
         Cell *y;
         FILE *fp;
@@ -1553,14 +1558,15 @@
                 fputs(getsval(y), fp);
                 tempfree(y);
                 if (x->nnext == NULL)
- fputs(*ORS, fp);
+ r = fputs(*ORS, fp);
                 else
- fputs(*OFS, fp);
+ r = fputs(*OFS, fp);
+ if (r == EOF)
+ FATAL("write error on %s", filename(fp));
         }
         if (a[1] != 0)
- fflush(fp);
- if (ferror(fp))
- FATAL("write error on %s", filename(fp));
+ if (fflush(fp) == EOF)
+ FATAL("write error on %s", filename(fp));
         return(True);
 }
 
@@ -1890,3 +1896,4 @@
         *pb_ptr = pb;
         *sptr_ptr = sptr;
 }
+
diff -r bb17f966e24a -r 1161d90df941 awk/tran.c
--- a/awk/tran.c Thu Feb 09 13:39:50 2006 +0100
+++ b/awk/tran.c Fri Jul 31 21:02:58 2009 +0100
@@ -432,3 +432,4 @@
         *bp++ = 0;
         return buf;
 }
+
diff -r bb17f966e24a -r 1161d90df941 bc/bc.1
--- a/bc/bc.1 Thu Feb 09 13:39:50 2006 +0100
+++ b/bc/bc.1 Fri Jul 31 21:02:58 2009 +0100
@@ -159,7 +159,7 @@
 .B ,
 .I L
 .B ){
-.PD
+.PD0
 .br
 .B auto
 .I L
diff -r bb17f966e24a -r 1161d90df941 bc/bc.y
--- a/bc/bc.y Thu Feb 09 13:39:50 2006 +0100
+++ b/bc/bc.y Fri Jul 31 21:02:58 2009 +0100
@@ -6,10 +6,8 @@
         #define bsp_max 5000
 
         Biobuf *in;
- #define stdin bstdin
- #define stdout bstdout
- Biobuf stdin;
- Biobuf stdout;
+ Biobuf bstdin;
+ Biobuf bstdout;
         char cary[1000];
         char* cp = { cary };
         char string[1000];
@@ -19,7 +17,7 @@
         int bindx = 0;
         int lev = 0;
         int ln;
- int* ttp;
+ char* ttp;
         char* ss = "";
         int bstack[10] = { 0 };
         char* numb[15] =
@@ -28,8 +26,8 @@
                 " 6", " 7", " 8", " 9", " 10", " 11",
                 " 12", " 13", " 14"
         };
- int* pre;
- int* post;
+ char* pre;
+ char* post;
 
         long peekc = -1;
         int sargc;
@@ -61,40 +59,39 @@
                 "u","v","w","x","y","z"
         };
         char* dot = { "." };
- int bspace[bsp_max];
- int* bsp_nxt = { bspace };
+ char* bspace[bsp_max];
+ char** bsp_nxt = bspace;
         int bdebug = 0;
         int lflag;
         int cflag;
         int sflag;
 
- int* bundle(int, ...);
- void conout(int*, char*);
+ char* bundle(int, ...);
+ void conout(char*, char*);
         int cpeek(int, int, int);
         int getch(void);
- int* geta(char*);
- int* getf(char*);
+ char* geta(char*);
+ char* getf(char*);
         void getout(void);
- void output(int*);
+ void output(char*);
         void pp(char*);
- void routput(int*);
+ void routput(char*);
         void tp(char*);
         void yyerror(char*, ...);
         int yyparse(void);
 
         typedef void* pointer;
-/* #pragma varargck type "lx" pointer */
+ #pragma varargck type "lx" pointer
 
 %}
 %union
 {
- int* iptr;
         char* cptr;
         int cc;
 }
 
-%type <iptr> pstat stat stat1 def slist dlets e ase nase
-%type <iptr> slist re fprefix cargs eora cons constant lora
+%type <cptr> pstat stat stat1 def slist dlets e ase nase
+%type <cptr> slist re fprefix cargs eora cons constant lora
 %type <cptr> crs
 
 %token <cptr> LETTER EQOP _AUTO DOT
@@ -124,7 +121,7 @@
                 ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
                 conout(ttp, (char*)$1);
                 rcrs = crs;
- output((int*)""); /* this is horse puk!! */
+ output("");
                 lev = bindx = 0;
         }
 
@@ -550,8 +547,8 @@
         _DEFINE LETTER '('
         {
                 $$ = getf($2);
- pre = (int*)"";
- post = (int*)"";
+ pre = (char*)"";
+ post = (char*)"";
                 lev = 1;
                 bindx = 0;
                 bstack[bindx] = 0;
@@ -789,76 +786,85 @@
         peekc = -1;
         if(ch >= 0)
                 return ch;
+
         ifile++;
- if(ifile > sargc) {
- if(ifile >= sargc+2)
+ if(ifile >= sargc) {
+ if(ifile >= sargc+1)
                         getout();
- in = &stdin;
+ in = &bstdin;
                 Binit(in, 0, OREAD);
                 ln = 0;
                 goto loop;
         }
- Bterm(in);
+ if(in)
+ Bterm(in);
         if((in = Bopen(sargv[ifile], OREAD)) != 0){
                 ln = 0;
                 ss = sargv[ifile];
                 goto loop;
         }
+ fprint(2, "open %s: %r\n", sargv[ifile]);
         yyerror("cannot open input file");
         return 0; /* shut up ken */
 }
 
-int*
+char*
 bundle(int a, ...)
 {
- int i, *p, *q;
-
- p = &a;
- i = *p++;
+ int i;
+ char **q;
+ va_list arg;
+
+ i = a;
+ va_start(arg, a);
         q = bsp_nxt;
         if(bdebug)
                 fprint(2, "bundle %d elements at %lx\n", i, q);
         while(i-- > 0) {
                 if(bsp_nxt >= &bspace[bsp_max])
                         yyerror("bundling space exceeded");
- *bsp_nxt++ = *p++;
+ *bsp_nxt++ = va_arg(arg, char*);
         }
         *bsp_nxt++ = 0;
- yyval.iptr = q;
- return q;
+ va_end(arg);
+ yyval.cptr = (char*)q;
+ return (char*)q;
 }
 
 void
-routput(int *p)
+routput(char *p)
 {
+ char **pp;
+
         if(bdebug)
                 fprint(2, "routput(%lx)\n", p);
- if(p >= &bspace[0] && p < &bspace[bsp_max]) {
+ if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
                 /* part of a bundle */
- while(*p != 0)
- routput((int*)(*p++));
+ pp = (char**)p;
+ while(*pp != 0)
+ routput(*pp++);
         } else
- Bprint(&stdout, (char*)p); /* character string */
+ Bprint(&bstdout, p); /* character string */
 }
 
 void
-output(int *p)
+output(char *p)
 {
         routput(p);
         bsp_nxt = &bspace[0];
- Bprint(&stdout, "\n");
- Bflush(&stdout);
+ Bprint(&bstdout, "\n");
+ Bflush(&bstdout);
         cp = cary;
         crs = rcrs;
 }
 
 void
-conout(int *p, char *s)
+conout(char *p, char *s)
 {
- Bprint(&stdout, "[");
+ Bprint(&bstdout, "[");
         routput(p);
- Bprint(&stdout, "]s%s\n", s);
- Bflush(&stdout);
+ Bprint(&bstdout, "]s%s\n", s);
+ Bflush(&bstdout);
         lev--;
 }
 
@@ -867,8 +873,8 @@
 {
         if(ifile > sargc)
                 ss = "teletype";
- Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
- Bflush(&stdout);
+ Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss);
+ Bflush(&bstdout);
         cp = cary;
         crs = rcrs;
         bindx = 0;
@@ -881,9 +887,9 @@
 {
         /* puts the relevant stuff on pre and post for the letter s */
         bundle(3, "S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
         bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
 }
 
 void
@@ -891,45 +897,45 @@
 {
         /* same as pp, but for temps */
         bundle(3, "0S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
         bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
 }
 
 void
 yyinit(int argc, char **argv)
 {
- Binit(&stdout, 1, OWRITE);
+ Binit(&bstdout, 1, OWRITE);
         sargv = argv;
- sargc = argc - 1;
+ sargc = argc;
         if(sargc == 0) {
- in = &stdin;
+ in = &bstdin;
                 Binit(in, 0, OREAD);
- } else if((in = Bopen(sargv[1], OREAD)) == 0)
+ } else if((in = Bopen(sargv[0], OREAD)) == 0)
                 yyerror("cannot open input file");
- ifile = 1;
+ ifile = 0;
         ln = 0;
- ss = sargv[1];
+ ss = sargv[0];
 }
 
 void
 getout(void)
 {
- Bprint(&stdout, "q");
- Bflush(&stdout);
+ Bprint(&bstdout, "q");
+ Bflush(&bstdout);
         exits(0);
 }
 
-int*
+char*
 getf(char *p)
 {
- return (int*)funtab[*p - 'a'];
+ return funtab[*p - 'a'];
 }
 
-int*
+char*
 geta(char *p)
 {
- return (int*)atab[*p - 'a'];
+ return atab[*p - 'a'];
 }
 
 void
@@ -937,37 +943,34 @@
 {
         int p[2];
 
- while(argc > 1 && *argv[1] == '-') {
- switch(argv[1][1]) {
- case 'd':
- bdebug++;
- break;
- case 'c':
- cflag++;
- break;
- case 'l':
- lflag++;
- break;
- case 's':
- sflag++;
- break;
- default:
- fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
- exits("usage");
- }
- argc--;
- argv++;
- }
+ ARGBEGIN{
+ case 'd':
+ bdebug++;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ default:
+ fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
+ exits("usage");
+ }ARGEND
+
         if(lflag) {
+ argc++;
                 argv--;
- argc++;
- argv[1] = unsharp("#9/lib/bclib");
+ *argv = unsharp("#9/lib/bclib");
         }
         if(cflag) {
                 yyinit(argc, argv);
                 for(;;)
                         yyparse();
- /* exits(0); */
+ exits(0);
         }
         pipe(p);
         if(fork() == 0) {
@@ -981,5 +984,5 @@
         dup(p[0], 0);
         close(p[0]);
         close(p[1]);
- execlp("dc", "dc", (char*)0);
+ execl(unsharp("#9/bin/dc"), "dc", nil);
 }
diff -r bb17f966e24a -r 1161d90df941 config.mk
--- a/config.mk Thu Feb 09 13:39:50 2006 +0100
+++ b/config.mk Fri Jul 31 21:02:58 2009 +0100
@@ -4,7 +4,9 @@
 PREFIX = /usr/local/9
 MANPREFIX = ${PREFIX}/share/man
 
-VERSION = 20060209
+VERSION = 200907
+# 386, arm, etc31
+OBJTYPE = x86_64
 
 # Linux/BSD
 CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. -DPREFIX="\"${PREFIX}\""
diff -r bb17f966e24a -r 1161d90df941 dc/dc.c
--- a/dc/dc.c Thu Feb 09 13:39:50 2006 +0100
+++ b/dc/dc.c Fri Jul 31 21:02:58 2009 +0100
@@ -165,7 +165,6 @@
 Blk* dcgetwd(Blk *p);
 void putwd(Blk *p, Blk *c);
 Blk* lookwd(Blk *p);
-char* nalloc(char *p, unsigned nbytes);
 int getstk(void);
 
 /********debug only**/
@@ -1222,7 +1221,7 @@
         readptr = &readstk[0];
         k=0;
         sp = sptr = &symlst[0];
- while(sptr < &symlst[TBLSZ]) {
+ while(sptr < &symlst[TBLSZ-1]) {
                 sptr->next = ++sp;
                 sptr++;
         }
@@ -2103,14 +2102,13 @@
         if(size > maxsize)
                 maxsize = size;
         sz = length(hptr);
- ptr = nalloc(hptr->beg, size);
+ ptr = malloc(size);
         if(ptr == 0) {
- garbage("copy");
- if((ptr = nalloc(hptr->beg, size)) == 0) {
- Bprint(&bout,"copy size %d\n",size);
- ospace("copy");
- }
+ Bprint(&bout,"copy size %d\n",size);
+ ospace("copy");
         }
+ memmove(ptr, hptr->beg, sz);
+ memset(ptr+sz, 0, size-sz);
         if((hdr = hfree) == 0)
                 hdr = morehd();
         hfree = (Blk *)hdr->rd;
@@ -2149,7 +2147,7 @@
                 lbytes += nn - hptr->last;
                 if(n > longest)
                         longest = n;
-/* free(hptr->beg); *//**/
+/* free(hptr->beg); */
                 p = realloc(hptr->beg, n);
                 if(p == 0) {
 /* hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg);
@@ -2194,7 +2192,7 @@
                 longest = size;
         lbytes += size/2;
         lmore++;
-/* free(hptr->beg);*//**/
+/* free(hptr->beg);*/
         p = realloc(hptr->beg, size);
 
         if(p == 0) {
@@ -2269,19 +2267,6 @@
         return(*wp->rdw);
 }
 
-char*
-nalloc(char *p, unsigned nbytes)
-{
- char *q, *r;
-
- q = r = malloc(nbytes);
- if(q==0)
- return(0);
- while(nbytes--)
- *q++ = *p++;
- return(r);
-}
-
 int
 getstk(void)
 {
diff -r bb17f966e24a -r 1161d90df941 grep/comp.c
--- a/grep/comp.c Thu Feb 09 13:39:50 2006 +0100
+++ b/grep/comp.c Fri Jul 31 21:02:58 2009 +0100
@@ -128,12 +128,12 @@
 Rune tab1[] =
 {
         0x007f,
- 0x07ff,
+ 0x07ff
 };
 Rune tab2[] =
 {
         0x003f,
- 0x0fff,
+ 0x0fff
 };
 
 Re2
@@ -144,7 +144,7 @@
         Re2 x;
 
         if(p0 > p1)
- return re2char(0xff, 0xff); // no match
+ return re2char(0xff, 0xff); /* no match */
 
         /*
          * bust range into same length
diff -r bb17f966e24a -r 1161d90df941 grep/main.c
--- a/grep/main.c Thu Feb 09 13:39:50 2006 +0100
+++ b/grep/main.c Fri Jul 31 21:02:58 2009 +0100
@@ -19,6 +19,10 @@
                 if(utfrune(validflags, ARGC()) == nil)
                         usage();
                 flags[ARGC()]++;
+ break;
+
+ case 'q': /* gnu grep -q means plan 9 grep -s */
+ flags['s']++;
                 break;
 
         case 'E': /* ignore, turns gnu grep into egrep */
@@ -170,11 +174,11 @@
                 increment(s, c);
                 goto loop;
         }
-// if(flags['2'])
-// if(s->match)
-// print("%d: %.2x**\n", s, c);
-// else
-// print("%d: %.2x\n", s, c);
+/* if(flags['2']) */
+/* if(s->match) */
+/* print("%d: %.2x**\n", s, c); */
+/* else */
+/* print("%d: %.2x\n", s, c); */
         lp++;
         s = ns;
         if(c == '\n') {
diff -r bb17f966e24a -r 1161d90df941 grep/sub.c
--- a/grep/sub.c Thu Feb 09 13:39:50 2006 +0100
+++ b/grep/sub.c Fri Jul 31 21:02:58 2009 +0100
@@ -30,7 +30,7 @@
         State *s;
 
         s = mal(sizeof(*s));
-// s->next = mal(256*sizeof(*s->next));
+/* s->next = mal(256*sizeof(*s->next)); */
         s->count = n;
         s->re = mal(n*sizeof(*state0->re));
         return s;
diff -r bb17f966e24a -r 1161d90df941 lib9/Makefile
--- a/lib9/Makefile Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/Makefile Fri Jul 31 21:02:58 2009 +0100
@@ -15,16 +15,203 @@
 
 LIB=lib9.a
 TARG=lib9
+O=o
 
 # following objects are not compiled for several reasons
-# crypt.o
-# netcrypt.o
-# convD2M.o
-# convM2D.o
-# convM2S.o
-# convS2M.o
+# crypt.$(O)
+# netcrypt.$(O)
+# convD2M.$(O)
+# convM2D.$(O)
+# convM2S.$(O)
+# convS2M.$(O)
+
+NUM=\
+ fmt/charstod.$(O)\
+ fmt/pow10.$(O)\
+
+FMTOFILES=\
+ fmt/dofmt.$(O)\
+ fmt/fltfmt.$(O)\
+ fmt/fmt.$(O)\
+ fmt/fmtfd.$(O)\
+ fmt/fmtfdflush.$(O)\
+ fmt/fmtlocale.$(O)\
+ fmtlock2.$(O)\
+ fmt/fmtnull.$(O)\
+ fmt/fmtprint.$(O)\
+ fmt/fmtquote.$(O)\
+ fmt/fmtrune.$(O)\
+ fmt/fmtstr.$(O)\
+ fmt/fmtvprint.$(O)\
+ fmt/fprint.$(O)\
+ fmt/nan64.$(O)\
+ fmt/print.$(O)\
+ fmt/runefmtstr.$(O)\
+ fmt/runeseprint.$(O)\
+ fmt/runesmprint.$(O)\
+ fmt/runesnprint.$(O)\
+ fmt/runesprint.$(O)\
+ fmt/runevseprint.$(O)\
+ fmt/runevsmprint.$(O)\
+ fmt/runevsnprint.$(O)\
+ fmt/seprint.$(O)\
+ fmt/smprint.$(O)\
+ fmt/snprint.$(O)\
+ fmt/sprint.$(O)\
+ fmt/strtod.$(O)\
+ fmt/vfprint.$(O)\
+ fmt/vseprint.$(O)\
+ fmt/vsmprint.$(O)\
+ fmt/vsnprint.$(O)\
+ $(NUM)\
+
+UTFOFILES=\
+ utf/rune.$(O)\
+ utf/runestrcat.$(O)\
+ utf/runestrchr.$(O)\
+ utf/runestrcmp.$(O)\
+ utf/runestrcpy.$(O)\
+ utf/runestrdup.$(O)\
+ utf/runestrlen.$(O)\
+ utf/runestrecpy.$(O)\
+ utf/runestrncat.$(O)\
+ utf/runestrncmp.$(O)\
+ utf/runestrncpy.$(O)\
+ utf/runestrrchr.$(O)\
+ utf/runestrstr.$(O)\
+ utf/runetype.$(O)\
+ utf/utfecpy.$(O)\
+ utf/utflen.$(O)\
+ utf/utfnlen.$(O)\
+ utf/utfrrune.$(O)\
+ utf/utfrune.$(O)\
+ utf/utfutf.$(O)\
+
+BIOFILES=\
+ bio/bbuffered.$(O)\
+ bio/bfildes.$(O)\
+ bio/bflush.$(O)\
+ bio/bgetc.$(O)\
+ bio/bgetrune.$(O)\
+ bio/bgetd.$(O)\
+ bio/binit.$(O)\
+ bio/boffset.$(O)\
+ bio/bprint.$(O)\
+ bio/bputc.$(O)\
+ bio/bputrune.$(O)\
+ bio/brdline.$(O)\
+ bio/brdstr.$(O)\
+ bio/bread.$(O)\
+ bio/bseek.$(O)\
+ bio/bvprint.$(O)\
+ bio/bwrite.$(O)\
+
+REGEXFILES=\
+ regex/regcomp.$(O)\
+ regex/regerror.$(O)\
+ regex/regexec.$(O)\
+ regex/regsub.$(O)\
+ regex/regaux.$(O)\
+ regex/rregexec.$(O)\
+ regex/rregsub.$(O)\
+
+LIB9OFILES=\
+ _exits.$(O)\
+ _p9dialparse.$(O)\
+ _p9dir.$(O)\
+ announce.$(O)\
+ argv0.$(O)\
+ atexit.$(O)\
+ atoi.$(O)\
+ atol.$(O)\
+ atoll.$(O)\
+ atnotify.$(O)\
+ await.$(O)\
+ cistrcmp.$(O)\
+ cistrncmp.$(O)\
+ cistrstr.$(O)\
+ cleanname.$(O)\
+ create.$(O)\
+ ctime.$(O)\
+ dial.$(O)\
+ dirfstat.$(O)\
+ dirfwstat.$(O)\
+ dirmodefmt.$(O)\
+ dirread.$(O)\
+ dirstat.$(O)\
+ dirwstat.$(O)\
+ dup.$(O)\
+ encodefmt.$(O)\
+ errstr.$(O)\
+ exec.$(O)\
+ execl.$(O)\
+ exitcode.$(O)\
+ fcallfmt.$(O)\
+ get9root.$(O)\
+ getcallerpc-$(OBJTYPE).$(O)\
+ getenv.$(O)\
+ getfields.$(O)\
+ getnetconn.$(O)\
+ getns.$(O)\
+ getuser.$(O)\
+ getwd.$(O)\
+ jmp.$(O)\
+ lrand.$(O)\
+ lnrand.$(O)\
+ main.$(O)\
+ malloc.$(O)\
+ malloctag.$(O)\
+ mallocz.$(O)\
+ nan.$(O)\
+ needsrcquote.$(O)\
+ needstack.$(O)\
+ netmkaddr.$(O)\
+ notify.$(O)\
+ nrand.$(O)\
+ nulldir.$(O)\
+ open.$(O)\
+ opentemp.$(O)\
+ pin.$(O)\
+ pipe.$(O)\
+ post9p.$(O)\
+ postnote.$(O)\
+ qlock.$(O)\
+ quote.$(O)\
+ rand.$(O)\
+ read9pmsg.$(O)\
+ readcons.$(O)\
+ readn.$(O)\
+ rfork.$(O)\
+ searchpath.$(O)\
+ seek.$(O)\
+ sendfd.$(O)\
+ sleep.$(O)\
+ strdup.$(O)\
+ strecpy.$(O)\
+ sysfatal.$(O)\
+ syslog.$(O)\
+ sysname.$(O)\
+ time.$(O)\
+ tm2sec.$(O)\
+ tokenize.$(O)\
+ truerand.$(O)\
+ u16.$(O)\
+ u32.$(O)\
+ u64.$(O)\
+ unsharp.$(O)\
+ wait.$(O)\
+ waitpid.$(O)\
+ write.$(O)\
+ zoneinfo.$(O)\
 
 OFILES=\
+ $(FMTOFILES)\
+ $(UTFOFILES)\
+ $(BIOFILES)\
+ $(REGEXFILES)\
+ $(LIB9OFILES)
+
+OFILESOLD=\
         fmt/dofmt.o\
         fmt/fltfmt.o\
         fmt/fmt.o\
diff -r bb17f966e24a -r 1161d90df941 lib9/_exits.c
--- a/lib9/_exits.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/_exits.c Fri Jul 31 21:02:58 2009 +0100
@@ -4,7 +4,7 @@
 void
 _exits(char *s)
 {
- if(s && *s)
- _exit(1);
- _exit(0);
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(exitcode(s));
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/_p9dialparse.c
--- a/lib9/_p9dialparse.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/_p9dialparse.c Fri Jul 31 21:02:58 2009 +0100
@@ -26,6 +26,8 @@
         "tcp", "venti", 17034,
         "tcp", "wiki", 17035,
         "tcp", "secstore", 5356,
+ "udp", "dns", 53,
+ "tcp", "dns", 53,
 };
 
 static int
@@ -81,9 +83,6 @@
         struct servent *se;
         struct hostent *he;
         struct sockaddr_un *sockun;
-
- if(strncmp(addr, "/net/", 5) == 0)
- addr += 5;
 
         *punix = nil;
         net = addr;
diff -r bb17f966e24a -r 1161d90df941 lib9/_p9dir.c
--- a/lib9/_p9dir.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/_p9dir.c Fri Jul 31 21:02:58 2009 +0100
@@ -7,50 +7,67 @@
 #include <pwd.h>
 #include <grp.h>
 
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__APPLE__)
+#define _HAVESTGEN
+#include <sys/disk.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ u64int bc;
+ u32int bs;
+
+ bs = 0;
+ bc = 0;
+ ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
+ ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
+ if(bs >0 && bc > 0)
+ return bc*bs;
+ return 0;
+}
+
+#elif defined(__FreeBSD__)
+#define _HAVESTGEN
+#include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/ioctl.h>
-static int diskdev[] = {
- 151, /* aacd */
- 116, /* ad */
- 157, /* ar */
- 118, /* afd */
- 133, /* amrd */
- 13, /* da */
- 102, /* fla */
- 109, /* idad */
- 95, /* md */
- 131, /* mlxd */
- 168, /* pst */
- 147, /* twed */
- 43, /* vn */
- 3, /* wd */
- 87, /* wfd */
-};
-static int
-isdisk(struct stat *st)
+static vlong
+disksize(int fd, struct stat *st)
 {
- int i, dev;
+ off_t mediasize;
+
+ if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+ return mediasize;
+ return 0;
+}
+
+#elif defined(__OpenBSD__)
+#define _HAVESTGEN
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ struct disklabel lab;
+ int n;
 
         if(!S_ISCHR(st->st_mode))
                 return 0;
- dev = major(st->st_rdev);
- for(i=0; i<nelem(diskdev); i++)
- if(diskdev[i] == dev)
- return 1;
- return 0;
+ if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+ return 0;
+ n = minor(st->st_rdev)&7;
+ if(n >= lab.d_npartitions)
+ return 0;
+ return (vlong)lab.d_partitions[n].p_size * lab.d_secsize;
 }
-#define _HAVEDISKLABEL
-#endif
 
-#if defined(__linux__)
+#elif defined(__linux__)
 #include <linux/hdreg.h>
 #include <linux/fs.h>
 #include <sys/ioctl.h>
 #undef major
 #define major(dev) ((int)(((dev) >> 8) & 0xff))
 static vlong
-disksize(int fd, int dev)
+disksize(int fd, struct stat *st)
 {
         u64int u64;
         long l;
@@ -64,18 +81,21 @@
                 return u64;
 #endif
         if(ioctl(fd, BLKGETSIZE, &l) >= 0)
- return (vlong)l*512;
+ return l*512;
         if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
                 return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
         return 0;
 }
-#define _HAVEDISKSIZE
+
+#else
+static vlong
+disksize(int fd, struct stat *st)
+{
+ return 0;
+}
 #endif
 
-#if !defined(__linux__) && !defined(__sun__)
-#define _HAVESTGEN
-#endif
-
+int _p9usepwlibrary = 1;
 /*
  * Caching the last group and passwd looked up is
  * a significant win (stupidly enough) on most systems.
@@ -122,11 +142,11 @@
         /* user */
         if(p && st->st_uid == uid && p->pw_uid == uid)
                 ;
- else{
+ else if(_p9usepwlibrary){
                 p = getpwuid(st->st_uid);
                 uid = st->st_uid;
         }
- if(p == nil){
+ if(p == nil || st->st_uid != uid || p->pw_uid != uid){
                 snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
                 s = tmp;
         }else
@@ -145,11 +165,11 @@
         /* group */
         if(g && st->st_gid == gid && g->gr_gid == gid)
                 ;
- else{
+ else if(_p9usepwlibrary){
                 g = getgrgid(st->st_gid);
                 gid = st->st_gid;
         }
- if(g == nil){
+ if(g == nil || st->st_gid != gid || g->gr_gid != gid){
                 snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
                 s = tmp;
         }else
@@ -173,57 +193,41 @@
 #ifdef _HAVESTGEN
                 d->qid.vers = st->st_gen;
 #endif
+ if(d->qid.vers == 0)
+ d->qid.vers = st->st_mtime + st->st_ctime;
                 d->mode = st->st_mode&0777;
                 d->atime = st->st_atime;
                 d->mtime = st->st_mtime;
                 d->length = st->st_size;
 
- if(S_ISDIR(st->st_mode)){
+ if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */
+ d->mode |= DMSYMLINK;
+ d->length = lst->st_size;
+ }
+ else if(S_ISDIR(st->st_mode)){
                         d->length = 0;
                         d->mode |= DMDIR;
                         d->qid.type = QTDIR;
                 }
- if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
- d->mode |= DMSYMLINK;
- if(S_ISFIFO(st->st_mode))
+ else if(S_ISFIFO(st->st_mode))
                         d->mode |= DMNAMEDPIPE;
- if(S_ISSOCK(st->st_mode))
+ else if(S_ISSOCK(st->st_mode))
                         d->mode |= DMSOCKET;
- if(S_ISBLK(st->st_mode)){
+ else if(S_ISBLK(st->st_mode)){
                         d->mode |= DMDEVICE;
                         d->qid.path = ('b'<<16)|st->st_rdev;
                 }
- if(S_ISCHR(st->st_mode)){
+ else if(S_ISCHR(st->st_mode)){
                         d->mode |= DMDEVICE;
                         d->qid.path = ('c'<<16)|st->st_rdev;
                 }
                 /* fetch real size for disks */
-#ifdef _HAVEDISKSIZE
- if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
- d->length = disksize(fd, major(st->st_dev));
- close(fd);
+ if(S_ISBLK(lst->st_mode) || S_ISCHR(lst->st_mode)){
+ if((fd = open(name, O_RDONLY)) >= 0){
+ d->length = disksize(fd, st);
+ close(fd);
+ }
                 }
-#endif
-#ifdef _HAVEDISKLABEL
- if(isdisk(st)){
- int fd, n;
- struct disklabel lab;
-
- if((fd = open(name, O_RDONLY)) < 0)
- goto nosize;
- if(ioctl(fd, DIOCGDINFO, &lab) < 0)
- goto nosize;
- n = minor(st->st_rdev)&7;
- if(n >= lab.d_npartitions)
- goto nosize;
-
- d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
-
- nosize:
- if(fd >= 0)
- close(fd);
- }
-#endif
         }
 
         return sz;
diff -r bb17f966e24a -r 1161d90df941 lib9/atexit.c
--- a/lib9/atexit.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/atexit.c Fri Jul 31 21:02:58 2009 +0100
@@ -50,5 +50,7 @@
                         onex[i].f = 0;
                         (*f)();
                 }
- exit(s && *s ? 1 : 0);
+ if(s == 0 || *s == 0)
+ exit(0);
+ exit(exitcode(s));
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/bio.h
--- a/lib9/bio.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio.h Fri Jul 31 21:02:58 2009 +0100
@@ -8,22 +8,7 @@
 AUTOLIB(bio)
 #endif
 
-#include <sys/types.h> /* for off_t */
-#include <stdarg.h>
 #include <fcntl.h> /* for O_RDONLY, O_WRONLY */
-
-#define OREAD 0 /* open for read */
-#define OWRITE 1 /* write */
-#define ORDWR 2 /* read and write */
-#define OEXEC 3 /* execute, == read but check execute permission */
-#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
-#define OCEXEC 32 /* or'ed in, close on exec */
-#define ORCLOSE 64 /* or'ed in, remove on close */
-#define ODIRECT 128 /* or'ed in, direct access */
-#define ONONBLOCK 256 /* or'ed in, non-blocking call */
-#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
-#define OLOCK 0x2000 /* or'ed in, lock after opening */
-#define OAPPEND 0x4000 /* or'ed in, append only */
 
 typedef struct Biobuf Biobuf;
 
@@ -52,7 +37,7 @@
         int state; /* r/w/inactive */
         int fid; /* open file */
         int flag; /* magic if malloc'ed */
- off_t offset; /* offset of buffer in file */
+ long long offset; /* offset of buffer in file */
         int bsize; /* size of buffer */
         unsigned char* bbuf; /* pointer to beginning of buffer */
         unsigned char* ebuf; /* pointer to end of buffer */
@@ -85,7 +70,7 @@
 int Binit(Biobuf*, int, int);
 int Binits(Biobuf*, int, int, unsigned char*, int);
 int Blinelen(Biobuf*);
-off_t Boffset(Biobuf*);
+long long Boffset(Biobuf*);
 Biobuf* Bopen(char*, int);
 int Bprint(Biobuf*, char*, ...);
 int Bputc(Biobuf*, int);
@@ -93,7 +78,7 @@
 void* Brdline(Biobuf*, int);
 char* Brdstr(Biobuf*, int, int);
 long Bread(Biobuf*, void*, long);
-off_t Bseek(Biobuf*, off_t, int);
+long long Bseek(Biobuf*, long long, int);
 int Bterm(Biobuf*);
 int Bungetc(Biobuf*);
 int Bungetrune(Biobuf*);
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bbuffered.c
--- a/lib9/bio/bbuffered.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bbuffered.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
 
 int
 Bbuffered(Biobuf *bp)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bflush.c
--- a/lib9/bio/bflush.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bflush.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <unistd.h>
 
 int
 Bflush(Biobuf *bp)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bgetc.c
--- a/lib9/bio/bgetc.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bgetc.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <unistd.h>
 
 int
 Bgetc(Biobuf *bp)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bgetd.c
--- a/lib9/bio/bgetd.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bgetd.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
 
 struct bgetd
 {
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/binit.c
--- a/lib9/bio/binit.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/binit.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,8 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
-#include <stdlib.h>
-#include <unistd.h>
 
 enum
 {
@@ -125,13 +122,13 @@
                 return 0;
 
         case OREAD:
- f = open(name, OREAD);
+ f = open(name, mode);
                 if(f < 0)
                         return 0;
                 break;
 
         case OWRITE:
- f = creat(name, 0666);
+ f = create(name, mode, 0666);
                 if(f < 0)
                         return 0;
         }
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/boffset.c
--- a/lib9/bio/boffset.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/boffset.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,11 +1,10 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
 
-off_t
+vlong
 Boffset(Biobuf *bp)
 {
- off_t n;
+ vlong n;
 
         switch(bp->state) {
         default:
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/brdline.c
--- a/lib9/bio/brdline.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/brdline.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <unistd.h>
 
 void*
 Brdline(Biobuf *bp, int delim)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/brdstr.c
--- a/lib9/bio/brdstr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/brdstr.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,7 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <stdlib.h>
-#include <unistd.h>
 
 static char*
 badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bread.c
--- a/lib9/bio/bread.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bread.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <unistd.h>
 
 long
 Bread(Biobuf *bp, void *ap, long count)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bseek.c
--- a/lib9/bio/bseek.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bseek.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,13 +1,10 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-off_t
-Bseek(Biobuf *bp, off_t offset, int base)
+long long
+Bseek(Biobuf *bp, long long offset, int base)
 {
- long long n, d;
+ vlong n, d;
         int bufsz;
 
         switch(bp->state) {
@@ -55,7 +52,7 @@
 
         case Bwactive:
                 Bflush(bp);
- n = lseek(bp->fid, offset, base);
+ n = seek(bp->fid, offset, base);
                 break;
         }
         bp->offset = n;
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bvprint.c
--- a/lib9/bio/bvprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bvprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <fmt.h>
 
 static int
 fmtBflush(Fmt *f)
@@ -30,10 +29,10 @@
         f.flush = fmtBflush;
         f.farg = bp;
         f.nfmt = 0;
+ fmtlocaleinit(&f, nil, nil, nil);
         n = fmtvprint(&f, fmt, arg);
         bp->ocount = (char*)f.to - (char*)f.stop;
+ if(n == 0)
+ n = f.nfmt;
         return n;
 }
-
-
-
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/bwrite.c
--- a/lib9/bio/bwrite.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/bwrite.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,5 @@
 #include "lib9.h"
 #include <bio.h>
-#include <unistd.h>
 
 long
 Bwrite(Biobuf *bp, void *ap, long count)
diff -r bb17f966e24a -r 1161d90df941 lib9/bio/lib9.std.h
--- a/lib9/bio/lib9.std.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/bio/lib9.std.h Fri Jul 31 21:02:58 2009 +0100
@@ -1,3 +1,6 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+
 #include <utf.h>
 #include <fmt.h>
 
@@ -13,8 +16,11 @@
 #define ORCLOSE 0
 #define OTRUNC 0
 
-
 #define nil ((void*)0)
 
 typedef long long vlong;
 typedef unsigned long long uvlong;
+
+#define seek(fd, offset, whence) lseek(fd, offset, whence)
+#define create(name, mode, perm) creat(name, perm)
+
diff -r bb17f966e24a -r 1161d90df941 lib9/convD2M.c
--- a/lib9/convD2M.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/convD2M.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,30 +3,44 @@
 #include <fcall.h>
 
 uint
-sizeD2M(Dir *d)
+sizeD2Mu(Dir *d, int dotu)
 {
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr, fixlen;
 
         sv[0] = d->name;
         sv[1] = d->uid;
         sv[2] = d->gid;
         sv[3] = d->muid;
-
+
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
         ns = 0;
- for(i = 0; i < 4; i++)
+ for(i = 0; i < nstr; i++)
                 if(sv[i])
                         ns += strlen(sv[i]);
 
- return STATFIXLEN + ns;
+ return fixlen + ns;
 }
 
 uint
-convD2M(Dir *d, uchar *buf, uint nbuf)
+sizeD2M(Dir *d)
+{
+ return sizeD2Mu(d, 0);
+}
+
+uint
+convD2Mu(Dir *d, uchar *buf, uint nbuf, int dotu)
 {
         uchar *p, *ebuf;
- char *sv[4];
- int i, ns, nsv[4], ss;
+ char *sv[5];
+ int i, ns, nsv[5], ss, nstr, fixlen;
 
         if(nbuf < BIT16SZ)
                 return 0;
@@ -39,8 +53,16 @@
         sv[2] = d->gid;
         sv[3] = d->muid;
 
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
         ns = 0;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
                 if(sv[i])
                         nsv[i] = strlen(sv[i]);
                 else
@@ -48,7 +70,7 @@
                 ns += nsv[i];
         }
 
- ss = STATFIXLEN + ns;
+ ss = fixlen + ns;
 
         /* set size befor erroring, so user can know how much is needed */
         /* note that length excludes count field itself */
@@ -77,7 +99,7 @@
         PBIT64(p, d->length);
         p += BIT64SZ;
 
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
                 ns = nsv[i];
                 if(p + ns + BIT16SZ > ebuf)
                         return 0;
@@ -87,9 +109,24 @@
                         memmove(p, sv[i], ns);
                 p += ns;
         }
+
+ if(dotu){
+ PBIT32(p, d->uidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->gidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->muidnum);
+ p += BIT32SZ;
+ }
 
         if(ss != p - buf)
                 return 0;
 
         return p - buf;
 }
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ return convD2Mu(d, buf, nbuf, 0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/convM2D.c
--- a/lib9/convM2D.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/convM2D.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,10 +3,10 @@
 #include <fcall.h>
 
 int
-statcheck(uchar *buf, uint nbuf)
+statchecku(uchar *buf, uint nbuf, int dotu)
 {
         uchar *ebuf;
- int i;
+ int i, nstr;
 
         ebuf = buf + nbuf;
 
@@ -15,11 +15,17 @@
 
         buf += STATFIXLEN - 4 * BIT16SZ;
 
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
                 if(buf + BIT16SZ > ebuf)
                         return -1;
                 buf += BIT16SZ + GBIT16(buf);
         }
+
+ if(dotu)
+ buf += 3*BIT32SZ;
 
         if(buf != ebuf)
                 return -1;
@@ -27,14 +33,20 @@
         return 0;
 }
 
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ return statchecku(buf, nbuf, 0);
+}
+
 static char nullstring[] = "";
 
 uint
-convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+convM2Du(uchar *buf, uint nbuf, Dir *d, char *strs, int dotu)
 {
         uchar *p, *ebuf;
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr;
 
         if(nbuf < STATFIXLEN)
                 return 0;
@@ -62,7 +74,10 @@
         d->length = GBIT64(p);
         p += BIT64SZ;
 
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
                 if(p + BIT16SZ > ebuf)
                         return 0;
                 ns = GBIT16(p);
@@ -78,17 +93,38 @@
                 p += ns;
         }
 
+ if(dotu){
+ if(p + BIT32SZ*3 > ebuf)
+ return 0;
+ d->uidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->gidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->muidnum = GBIT32(p);
+ p += BIT32SZ;
+ }
+
         if(strs){
                 d->name = sv[0];
                 d->uid = sv[1];
                 d->gid = sv[2];
                 d->muid = sv[3];
+ d->ext = nullstring;
+ if(dotu)
+ d->ext = sv[4];
         }else{
                 d->name = nullstring;
                 d->uid = nullstring;
                 d->gid = nullstring;
                 d->muid = nullstring;
+ d->ext = nullstring;
         }
         
         return p - buf;
 }
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ return convM2Du(buf, nbuf, d, strs, 0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/convM2S.c
--- a/lib9/convM2S.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/convM2S.c Fri Jul 31 21:02:58 2009 +0100
@@ -48,7 +48,7 @@
  * to test at end of routine.
  */
 uint
-convM2S(uchar *ap, uint nap, Fcall *f)
+convM2Su(uchar *ap, uint nap, Fcall *f, int dotu)
 {
         uchar *p, *ep;
         uint i, size;
@@ -161,6 +161,8 @@
                 p += BIT32SZ;
                 f->mode = GBIT8(p);
                 p += BIT8SZ;
+ if(dotu)
+ p = gstring(p, ep, &f->extension);
                 break;
 
         case Tread:
@@ -229,6 +231,13 @@
 
         case Rerror:
                 p = gstring(p, ep, &f->ename);
+ f->errornum = 0;
+ if(dotu){
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->errornum = GBIT16(p);
+ p += BIT16SZ;
+ }
                 break;
 
         case Rflush:
@@ -321,3 +330,9 @@
                 return size;
         return 0;
 }
+
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ return convM2Su(ap, nap, f, 0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/convS2M.c
--- a/lib9/convS2M.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/convS2M.c Fri Jul 31 21:02:58 2009 +0100
@@ -46,7 +46,7 @@
 }
 
 uint
-sizeS2M(Fcall *f)
+sizeS2Mu(Fcall *f, int dotu)
 {
         uint n;
         int i;
@@ -102,6 +102,8 @@
                 n += stringsz(f->name);
                 n += BIT32SZ;
                 n += BIT8SZ;
+ if(dotu)
+ n += stringsz(f->extension);
                 break;
 
         case Tread:
@@ -141,6 +143,8 @@
 
         case Rerror:
                 n += stringsz(f->ename);
+ if(dotu)
+ n += BIT16SZ;
                 break;
 
         case Rflush:
@@ -198,12 +202,18 @@
 }
 
 uint
-convS2M(Fcall *f, uchar *ap, uint nap)
+sizeS2M(Fcall *f)
+{
+ return sizeS2Mu(f, 0);
+}
+
+uint
+convS2Mu(Fcall *f, uchar *ap, uint nap, int dotu)
 {
         uchar *p;
         uint i, size;
 
- size = sizeS2M(f);
+ size = sizeS2Mu(f, dotu);
         if(size == 0)
                 return 0;
         if(size > nap)
@@ -279,6 +289,8 @@
                 p += BIT32SZ;
                 PBIT8(p, f->mode);
                 p += BIT8SZ;
+ if(dotu)
+ p = pstring(p, f->extension);
                 break;
 
         case Tread:
@@ -331,6 +343,10 @@
 
         case Rerror:
                 p = pstring(p, f->ename);
+ if(dotu){
+ PBIT16(p, f->errornum);
+ p += BIT16SZ;
+ }
                 break;
 
         case Rflush:
@@ -397,3 +413,9 @@
                 return 0;
         return size;
 }
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ return convS2Mu(f, ap, nap, 0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/crypt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/crypt.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,68 @@
+/*
+ * Data Encryption Standard
+ * D.P.Mitchell 83/06/08.
+ *
+ * block_cipher(key, block, decrypting)
+ *
+ * these routines use the non-standard 7 byte format
+ * for DES keys.
+ */
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <libsec.h>
+
+/*
+ * destructively encrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+encrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[32];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ for(i = 0; i < n; i++){
+ block_cipher(ekey, buf, 0);
+ buf += 7;
+ }
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 0);
+ return 1;
+}
+
+/*
+ * destructively decrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+decrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[128];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ buf += n * 7;
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 1);
+ for(i = 0; i < n; i++){
+ buf -= 7;
+ block_cipher(ekey, buf, 1);
+ }
+ return 1;
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/ctime.c
--- a/lib9/ctime.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/ctime.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,21 +1,135 @@
+/*
+ * This routine converts time as follows.
+ * The epoch is 0000 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * The localtime(t) entry returns a pointer to an array
+ * containing
+ *
+ * seconds (0-59)
+ * minutes (0-59)
+ * hours (0-23)
+ * day of month (1-31)
+ * month (0-11)
+ * year-1970
+ * weekday (0-6, Sun is 0)
+ * day of the year
+ * daylight savings flag
+ *
+ * The routine gets the daylight savings time from the environment.
+ *
+ * asctime(tvec))
+ * where tvec is produced by localtime
+ * returns a ptr to a character string
+ * that has the ascii time in the form
+ *
+ * \\
+ * Thu Jan 01 00:00:00 GMT 1970n0
+ * 012345678901234567890123456789
+ * 0 1 2
+ *
+ * ctime(t) just calls localtime, then asctime.
+ */
+
 #include <u.h>
 #include <libc.h>
 
-static
-void
-ct_numb(char *cp, int n)
+#include "zoneinfo.h"
+
+static char dmsize[12] =
 {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
 
- cp[0] = ' ';
- if(n >= 10)
- cp[0] = (n/10)%10 + '0';
- cp[1] = n%10 + '0';
+#define dysize ctimedysize
+static int dysize(int);
+static void ct_numb(char*, int);
+
+char*
+ctime(long t)
+{
+ return asctime(localtime(t));
+}
+
+Tm*
+localtime(long tim)
+{
+ Tinfo ti;
+ Tm *ct;
+
+ if (zonelookuptinfo(&ti, tim)!=-1) {
+ ct = gmtime(tim+ti.tzoff);
+ strncpy(ct->zone, ti.zone, sizeof ct->zone);
+ ct->zone[sizeof ct->zone-1] = 0;
+ ct->tzoff = ti.tzoff;
+ return ct;
+ }
+ return gmtime(tim);
+}
+
+Tm*
+gmtime(long tim)
+{
+ int d0, d1;
+ long hms, day;
+ static Tm xtime;
+
+ /*
+ * break initial number into days
+ */
+ hms = tim % 86400L;
+ day = tim / 86400L;
+ if(hms < 0) {
+ hms += 86400L;
+ day -= 1;
+ }
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ xtime.sec = hms % 60;
+ d1 = hms / 60;
+ xtime.min = d1 % 60;
+ d1 /= 60;
+ xtime.hour = d1;
+
+ /*
+ * day is the day number.
+ * generate day of the week.
+ * The addend is 4 mod 7 (1/1/1970 was Thursday)
+ */
+
+ xtime.wday = (day + 7340036L) % 7;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d1 = 1970; day >= dysize(d1); d1++)
+ day -= dysize(d1);
+ else
+ for (d1 = 1970; day < 0; d1--)
+ day += dysize(d1-1);
+ xtime.year = d1-1900;
+ xtime.yday = d0 = day;
+
+ /*
+ * generate month
+ */
+
+ if(dysize(d1) == 366)
+ dmsize[1] = 29;
+ for(d1 = 0; d0 >= dmsize[d1]; d1++)
+ d0 -= dmsize[d1];
+ dmsize[1] = 28;
+ xtime.mday = d0 + 1;
+ xtime.mon = d1;
+ strcpy(xtime.zone, "GMT");
+ return &xtime;
 }
 
 char*
 asctime(Tm *t)
 {
- int i;
         char *ncp;
         static char cbuf[30];
 
@@ -33,12 +147,6 @@
         ct_numb(cbuf+14, t->min+100);
         ct_numb(cbuf+17, t->sec+100);
         ncp = t->zone;
- for(i=0; i<3; i++)
- if(ncp[i] == 0)
- break;
- for(; i<3; i++)
- ncp[i] = '?';
- ncp = t->zone;
         cbuf[20] = *ncp++;
         cbuf[21] = *ncp++;
         cbuf[22] = *ncp;
@@ -50,9 +158,24 @@
         return cbuf;
 }
 
-char*
-ctime(long t)
+static
+int
+dysize(int y)
 {
- return asctime(localtime(t));
+
+ if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
+ return 366;
+ return 365;
 }
 
+static
+void
+ct_numb(char *cp, int n)
+{
+
+ cp[0] = ' ';
+ if(n >= 10)
+ cp[0] = (n/10)%10 + '0';
+ cp[1] = n%10 + '0';
+}
+
diff -r bb17f966e24a -r 1161d90df941 lib9/debugmalloc.c
--- a/lib9/debugmalloc.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/debugmalloc.c Fri Jul 31 21:02:58 2009 +0100
@@ -111,13 +111,13 @@
         void *v;
         if(n == 0)
                 n++;
-//fprint(2, "%s %d malloc\n", argv0, getpid());
+/*fprint(2, "%s %d malloc\n", argv0, getpid()); */
         lock(&malloclock);
         mallocpid = getpid();
         v = malloc(n+Overhead);
         v = mark(v, getcallerpc(&n), n, MallocMagic);
         unlock(&malloclock);
-//fprint(2, "%s %d donemalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */
         return v;
 }
 
@@ -127,13 +127,13 @@
         if(v == nil)
                 return;
 
-//fprint(2, "%s %d free\n", argv0, getpid());
+/*fprint(2, "%s %d free\n", argv0, getpid()); */
         lock(&malloclock);
         mallocpid = getpid();
         v = mark(v, getcallerpc(&v), 0, FreeMagic);
         free(v);
         unlock(&malloclock);
-//fprint(2, "%s %d donefree\n", argv0, getpid());
+/*fprint(2, "%s %d donefree\n", argv0, getpid()); */
 }
 
 void*
@@ -141,26 +141,26 @@
 {
         void *v;
 
-//fprint(2, "%s %d calloc\n", argv0, getpid());
+/*fprint(2, "%s %d calloc\n", argv0, getpid()); */
         lock(&malloclock);
         mallocpid = getpid();
         v = calloc(a*b+Overhead, 1);
         v = mark(v, getcallerpc(&a), a*b, CallocMagic);
         unlock(&malloclock);
-//fprint(2, "%s %d donecalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */
         return v;
 }
 
 void*
 p9realloc(void *v, ulong n)
 {
-//fprint(2, "%s %d realloc\n", argv0, getpid());
+/*fprint(2, "%s %d realloc\n", argv0, getpid()); */
         lock(&malloclock);
         mallocpid = getpid();
         v = mark(v, getcallerpc(&v), 0, CheckMagic);
         v = realloc(v, n+Overhead);
         v = mark(v, getcallerpc(&v), n, ReallocMagic);
         unlock(&malloclock);
-//fprint(2, "%s %d donerealloc\n", argv0, getpid());
+/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */
         return v;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/dial.c
--- a/lib9/dial.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/dial.c Fri Jul 31 21:02:58 2009 +0100
@@ -60,10 +60,6 @@
         }
         free(buf);
 
- memset(&sa, 0, sizeof sa);
- memmove(&sa.sin_addr, &host, 4);
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
         if((s = socket(AF_INET, proto, 0)) < 0)
                 return -1;
                 
@@ -98,9 +94,17 @@
                 free(buf);
         }
 
- if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
- close(s);
- return -1;
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
+ if(host != 0){
+ memset(&sa, 0, sizeof sa);
+ memmove(&sa.sin_addr, &host, 4);
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
+ close(s);
+ return -1;
+ }
         }
         if(proto == SOCK_STREAM){
                 int one = 1;
@@ -114,6 +118,9 @@
                 free(buf);
                 return -1;
         }
+ /* Allow regular files in addition to Unix sockets. */
+ if((s = open(unix, ORDWR)) >= 0)
+ return s;
         memset(&su, 0, sizeof su);
         su.sun_family = AF_UNIX;
         if(strlen(unix)+1 > sizeof su.sun_path){
diff -r bb17f966e24a -r 1161d90df941 lib9/dirfwstat.c
--- a/lib9/dirfwstat.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/dirfwstat.c Fri Jul 31 21:02:58 2009 +0100
@@ -4,7 +4,7 @@
 #include <sys/time.h>
 #include <sys/stat.h>
 
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__)
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
 /* do nothing -- futimes exists and is fine */
 
 #elif defined(__SunOS5_9__)
@@ -48,6 +48,10 @@
                 if(futimes(fd, tv) < 0)
                         ret = -1;
         }
+ if(~dir->length != 0){
+ if(ftruncate(fd, dir->length) < 0)
+ ret = -1;
+ }
         return ret;
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/dirread.c
--- a/lib9/dirread.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/dirread.c Fri Jul 31 21:02:58 2009 +0100
@@ -18,18 +18,24 @@
         nn = getdirentries(fd, (void*)buf, n, &off);
         return nn;
 }
-#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 static int
 mygetdents(int fd, struct dirent *buf, int n)
 {
         long off;
         return getdirentries(fd, (void*)buf, n, &off);
 }
-#elif defined(__sun__)
+#elif defined(__sun__) || defined(__NetBSD__)
 static int
 mygetdents(int fd, struct dirent *buf, int n)
 {
         return getdents(fd, (void*)buf, n);
+}
+#elif defined(__AIX__)
+static int
+mygetdents(int fd, struct dirent *buf, int n)
+{
+ return getdirent(fd, (void*)buf, n);
 }
 #endif
 
diff -r bb17f966e24a -r 1161d90df941 lib9/dirwstat.c
--- a/lib9/dirwstat.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/dirwstat.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,17 +3,29 @@
 #include <libc.h>
 #include <sys/time.h>
 #include <utime.h>
+#include <sys/stat.h>
 
 int
 dirwstat(char *file, Dir *dir)
 {
+ int ret;
         struct utimbuf ub;
 
         /* BUG handle more */
- if(~dir->mtime == 0)
- return 0;
-
- ub.actime = dir->mtime;
- ub.modtime = dir->mtime;
- return utime(file, &ub);
+ ret = 0;
+ if(~dir->mode != 0){
+ if(chmod(file, dir->mode) < 0)
+ ret = -1;
+ }
+ if(~dir->mtime != 0){
+ ub.actime = dir->mtime;
+ ub.modtime = dir->mtime;
+ if(utime(file, &ub) < 0)
+ ret = -1;
+ }
+ if(~dir->length != 0){
+ if(truncate(file, dir->length) < 0)
+ ret = -1;
+ }
+ return ret;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/encodefmt.c
--- a/lib9/encodefmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/encodefmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,11 +1,4 @@
 #include <lib9.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "fmt.h"
-
-extern int enc64(char*, int, uchar*, int);
-extern int enc32(char*, int, uchar*, int);
-extern int enc16(char*, int, uchar*, int);
 
 int
 encodefmt(Fmt *f)
@@ -16,7 +9,7 @@
         int ilen;
         int rv;
         uchar *b;
- char obuf[64]; // rsc optimization
+ char obuf[64]; /* rsc optimization */
 
         b = va_arg(f->args, uchar*);
         if(b == 0)
@@ -51,7 +44,7 @@
         } else
                 buf = obuf;
 
- // convert
+ /* convert */
         out = buf;
         switch(f->r){
         case '<':
diff -r bb17f966e24a -r 1161d90df941 lib9/errstr.c
--- a/lib9/errstr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/errstr.c Fri Jul 31 21:02:58 2009 +0100
@@ -12,7 +12,7 @@
 
 enum
 {
- EPLAN9 = 0x19283745,
+ EPLAN9 = 0x19283745
 };
 
 char *(*_syserrstr)(void);
diff -r bb17f966e24a -r 1161d90df941 lib9/exitcode.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/exitcode.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,9 @@
+#include <u.h>
+#include <libc.h>
+
+int
+exitcode(char *s)
+{
+ return 1;
+}
+
diff -r bb17f966e24a -r 1161d90df941 lib9/fcallfmt.c
--- a/lib9/fcallfmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fcallfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -124,7 +124,7 @@
                 break;
         case Rstat:
                 p = seprint(buf, e, "Rstat tag %ud ", tag);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
                         seprint(p, e, " stat(%d bytes)", f->nstat);
                 else{
                         d = (Dir*)tmp;
@@ -135,7 +135,7 @@
                 break;
         case Twstat: /* 126 */
                 p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
                         seprint(p, e, " stat(%d bytes)", f->nstat);
                 else{
                         d = (Dir*)tmp;
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt.h
--- a/lib9/fmt.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt.h Fri Jul 31 21:02:58 2009 +0100
@@ -34,6 +34,18 @@
         int width;
         int prec;
         unsigned long flags;
+ char *decimal; /* decimal point; cannot be "" */
+
+ /* For %'d */
+ char *thousands; /* separator for thousands */
+
+ /*
+ * Each char is an integer indicating #digits before next separator. Values:
+ * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
+ * \x00: repeat previous indefinitely
+ * \x**: count that many
+ */
+ char *grouping; /* descriptor of separator placement */
 };
 
 enum{
@@ -43,7 +55,8 @@
         FmtSharp = FmtPrec << 1,
         FmtSpace = FmtSharp << 1,
         FmtSign = FmtSpace << 1,
- FmtZero = FmtSign << 1,
+ FmtApost = FmtSign << 1,
+ FmtZero = FmtApost << 1,
         FmtUnsigned = FmtZero << 1,
         FmtShort = FmtUnsigned << 1,
         FmtLong = FmtShort << 1,
@@ -64,6 +77,8 @@
 int fmtfdflush(Fmt *f);
 int fmtfdinit(Fmt *f, int fd, char *buf, int size);
 int fmtinstall(int c, int (*f)(Fmt*));
+int fmtnullinit(Fmt*);
+void fmtlocaleinit(Fmt*, char*, char*, char*);
 int fmtprint(Fmt *f, char *fmt, ...);
 int fmtrune(Fmt *f, int r);
 int fmtrunestrcpy(Fmt *f, Rune *s);
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/LICENSE
--- a/lib9/fmt/LICENSE Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/LICENSE Fri Jul 31 21:02:58 2009 +0100
@@ -1,19 +1,22 @@
 /*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose without fee is hereby granted, provided that this entire notice
  * is included in all copies of any software which is or includes a copy
  * or modification of this software and in all copies of the supporting
  * documentation for such software.
  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-*/
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
 
 This is a Unix port of the Plan 9 formatted I/O package.
 
-Please send comments about the packaging
-to Russ Cox <rsc_AT_post.harvard.edu>.
+Please send comments about the packaging to Russ Cox <rsc_AT_swtch.com>.
 
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/NOTICE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/fmt/NOTICE Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,19 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+This is a Unix port of the Plan 9 formatted I/O package.
+
+Please send comments about the packaging
+to Russ Cox <rsc_AT_post.harvard.edu>.
+
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/fmt/README Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,19 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+This is a Unix port of the Plan 9 formatted I/O package.
+
+Please send comments about the packaging
+to Russ Cox <rsc_AT_post.harvard.edu>.
+
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/charstod.c
--- a/lib9/fmt/charstod.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/charstod.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/dofmt.c
--- a/lib9/fmt/dofmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/dofmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -97,7 +87,7 @@
 
 /*
  * put a formatted block of memory sz bytes long of n runes into the output buffer,
- * left/right justified in a field of at least f->width charactes
+ * left/right justified in a field of at least f->width characters (if FmtWidth is set)
  */
 int
 __fmtpad(Fmt *f, int n)
@@ -139,8 +129,10 @@
 
         m = (char*)vm;
         me = m + sz;
- w = f->width;
         fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
         if((fl & FmtPrec) && n > f->prec)
                 n = f->prec;
         if(f->runes){
@@ -194,8 +186,10 @@
         int w;
 
         m = (Rune*)vm;
- w = f->width;
         fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
         if((fl & FmtPrec) && n > f->prec)
                 n = f->prec;
         if(f->runes){
@@ -252,15 +246,23 @@
 fmtstrcpy(Fmt *f, char *s)
 {
         int i, j;
- Rune r;
 
         if(!s)
                 return __fmtcpy(f, "<nil>", 5, 5);
         /* if precision is specified, make sure we don't wander off the end */
         if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+ Rune r;
                 i = 0;
                 for(j=0; j<f->prec && s[i]; j++)
                         i += chartorune(&r, s+i);
+#else
+ /* ANSI requires precision in bytes, not Runes */
+ for(i=0; i<f->prec; i++)
+ if(s[i] == 0)
+ break;
+ j = utfnlen(s, i); /* won't print partial at end */
+#endif
                 return __fmtcpy(f, s, j, i);
         }
         return __fmtcpy(f, s, utflen(s), strlen(s));
@@ -324,10 +326,14 @@
 int
 __ifmt(Fmt *f)
 {
- char buf[70], *p, *conv;
+ char buf[140], *p, *conv;
+ /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
         uvlong vu;
         ulong u;
         int neg, base, i, n, fl, w, isv;
+ int ndig, len, excess, bytelen;
+ char *grouping;
+ char *thousands;
 
         neg = 0;
         fl = f->flags;
@@ -339,11 +345,11 @@
          * Unsigned verbs for ANSI C
          */
         switch(f->r){
+ case 'o':
+ case 'p':
+ case 'u':
         case 'x':
         case 'X':
- case 'o':
- case 'u':
- case 'p':
                 fl |= FmtUnsigned;
                 fl &= ~(FmtSign|FmtSpace);
                 break;
@@ -381,21 +387,25 @@
                         u = va_arg(f->args, int);
         }
         conv = "0123456789abcdef";
+ grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
+ thousands = f->thousands;
         switch(f->r){
         case 'd':
         case 'i':
         case 'u':
                 base = 10;
+ grouping = f->grouping;
                 break;
+ case 'X':
+ conv = "0123456789ABCDEF";
+ /* fall through */
         case 'x':
                 base = 16;
- break;
- case 'X':
- base = 16;
- conv = "0123456789ABCDEF";
+ thousands = ":";
                 break;
         case 'b':
                 base = 2;
+ thousands = ":";
                 break;
         case 'o':
                 base = 8;
@@ -413,7 +423,11 @@
                 }
         }
         p = buf + sizeof buf - 1;
- n = 0;
+ n = 0; /* in runes */
+ excess = 0; /* number of bytes > number runes */
+ ndig = 0;
+ len = utflen(thousands);
+ bytelen = strlen(thousands);
         if(isv){
                 while(vu){
                         i = vu % base;
@@ -421,6 +435,12 @@
                         if((fl & FmtComma) && n % 4 == 3){
                                 *p-- = ',';
                                 n++;
+ }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
                         }
                         *p-- = conv[i];
                         n++;
@@ -433,16 +453,47 @@
                                 *p-- = ',';
                                 n++;
                         }
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
                         *p-- = conv[i];
                         n++;
                 }
         }
         if(n == 0){
+ /*
+ * "The result of converting a zero value with
+ * a precision of zero is no characters." - ANSI
+ *
+ * "For o conversion, # increases the precision, if and only if
+ * necessary, to force the first digit of the result to be a zero
+ * (if the value and precision are both 0, a single 0 is printed)." - ANSI
+ */
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
+ *p-- = '0';
+ n = 1;
+ if(fl & FmtApost)
+ __needsep(&ndig, &grouping);
+ }
+
+ /*
+ * Zero values don't get 0x.
+ */
+ if(f->r == 'x' || f->r == 'X')
+ fl &= ~FmtSharp;
+ }
+ for(w = f->prec; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
                 *p-- = '0';
- n = 1;
         }
- for(w = f->prec; n < w && p > buf+3; n++)
- *p-- = '0';
         if(neg || (fl & (FmtSign|FmtSpace)))
                 n++;
         if(fl & FmtSharp){
@@ -456,9 +507,19 @@
                 }
         }
         if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
- for(w = f->width; n < w && p > buf+3; n++)
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ for(; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
                         *p-- = '0';
- f->width = 0;
+ }
+ f->flags &= ~FmtWidth;
         }
         if(fl & FmtSharp){
                 if(base == 16)
@@ -473,7 +534,7 @@
         else if(fl & FmtSpace)
                 *p-- = ' ';
         f->flags &= ~FmtPrec;
- return __fmtcpy(f, p + 1, n, n);
+ return __fmtcpy(f, p + 1, n, n + excess);
 }
 
 int
@@ -514,6 +575,9 @@
         case '#':
                 f->flags |= FmtSharp;
                 break;
+ case '\'':
+ f->flags |= FmtApost;
+ break;
         case ' ':
                 f->flags |= FmtSpace;
                 break;
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/dorfmt.c
--- a/lib9/fmt/dorfmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/dorfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -19,6 +7,7 @@
 
 /* format the output into f->to and return the number of characters fmted */
 
+/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
 int
 dorfmt(Fmt *f, const Rune *fmt)
 {
@@ -30,8 +19,8 @@
         nfmt = f->nfmt;
         for(;;){
                 if(f->runes){
- rt = f->to;
- rs = f->stop;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
                         while((r = *fmt++) && r != '%'){
                                 FMTRCHAR(f, rt, rs, r);
                         }
@@ -41,8 +30,8 @@
                                 return f->nfmt - nfmt;
                         f->stop = rs;
                 }else{
- t = f->to;
- s = f->stop;
+ t = (char*)f->to;
+ s = (char*)f->stop;
                         while((r = *fmt++) && r != '%'){
                                 FMTRUNE(f, t, f->stop, r);
                         }
@@ -53,7 +42,7 @@
                         f->stop = s;
                 }
 
- fmt = __fmtdispatch(f, (Rune*)fmt, 1);
+ fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
                 if(fmt == nil)
                         return -1;
         }
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/errfmt.c
--- a/lib9/fmt/errfmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/errfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <errno.h>
 #include <string.h>
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fltfmt.c
--- a/lib9/fmt/fltfmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fltfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdio.h>
 #include <math.h>
 #include <float.h>
@@ -18,11 +6,12 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <stdarg.h>
-#include <ctype.h>
 #include <fmt.h>
+#include <assert.h>
 #include "plan9.h"
 #include "fmt.h"
 #include "fmtdef.h"
+#include "nan.h"
 
 enum
 {
@@ -54,8 +43,8 @@
         1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
         1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
 };
-
-#define pow10(x) fmtpow10(x)
+#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#define pow10(x) fmtpow10(x)
 
 static double
 pow10(int n)
@@ -65,330 +54,615 @@
 
         neg = 0;
         if(n < 0){
- if(n < DBL_MIN_10_EXP){
- return 0.;
- }
                 neg = 1;
                 n = -n;
- }else if(n > DBL_MAX_10_EXP){
- return HUGE_VAL;
         }
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
+
+ if(n < npows10)
                 d = pows10[n];
         else{
- d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d = pows10[npows10-1];
                 for(;;){
- n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
+ n -= npows10 - 1;
+ if(n < npows10){
                                 d *= pows10[n];
                                 break;
                         }
- d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d *= pows10[npows10 - 1];
                 }
         }
- if(neg){
+ if(neg)
                 return 1./d;
- }
         return d;
 }
 
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
 static int
-xadd(char *a, int n, int v)
+xadd1(char *a, int n)
 {
         char *b;
         int c;
 
- if(n < 0 || n >= NSIGNIF)
+ if(n < 0 || n > NSIGNIF)
                 return 0;
- for(b = a+n; b >= a; b--) {
- c = *b + v;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b + 1;
                 if(c <= '9') {
                         *b = c;
                         return 0;
                 }
                 *b = '0';
- v = 1;
         }
- *a = '1'; /* overflow adding */
+ /*
+ * need to overflow adding digit.
+ * shift number down and insert 1 at beginning.
+ * decimal is known to be 0s or we wouldn't
+ * have gotten this far. (e.g., 99999+1 => 00000)
+ */
+ a[0] = '1';
         return 1;
 }
 
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point. this way, xsub1 is inverse of xadd1.
+ */
 static int
-xsub(char *a, int n, int v)
+xsub1(char *a, int n)
 {
         char *b;
         int c;
 
- for(b = a+n; b >= a; b--) {
- c = *b - v;
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b - 1;
                 if(c >= '0') {
+ if(c == '0' && b == a) {
+ /*
+ * just zeroed the top digit; shift everyone up.
+ * decimal is known to be 9s or we wouldn't
+ * have gotten this far. (e.g., 10000-1 => 09999)
+ */
+ *b = '9';
+ return 1;
+ }
                         *b = c;
                         return 0;
                 }
                 *b = '9';
- v = 1;
         }
- *a = '9'; /* underflow subtracting */
- return 1;
+ /*
+ * can't get here. the number a is always normalized
+ * so that it has a nonzero first digit.
+ */
+ abort();
 }
 
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
 static void
-xdtoa(Fmt *fmt, char *s2, double f)
+xfmtexp(char *p, int e, int ucase)
 {
- char s1[NSIGNIF+10];
- double g, h;
- int e, d, i, n;
- int c1, c2, c3, c4, ucase, sign, chr, prec;
+ char se[9];
+ int i;
 
- prec = FDEFLT;
- if(fmt->flags & FmtPrec)
- prec = fmt->prec;
- if(prec > FDIGIT)
- prec = FDIGIT;
- if(__isNaN(f)) {
- strcpy(s2, "NaN");
- return;
+ *p++ = ucase ? 'E' : 'e';
+ if(e < 0) {
+ *p++ = '-';
+ e = -e;
+ } else
+ *p++ = '+';
+ i = 0;
+ while(e) {
+ se[i++] = e % 10 + '0';
+ e /= 10;
         }
- if(__isInf(f, 1)) {
- strcpy(s2, "+Inf");
- return;
- }
- if(__isInf(f, -1)) {
- strcpy(s2, "-Inf");
- return;
- }
- sign = 0;
+ while(i < 2)
+ se[i++] = '0';
+ while(i > 0)
+ *p++ = se[--i];
+ *p++ = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ * f = m*10^exp
+ * m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+ int c, d, e2, e, ee, i, ndigit, oerrno;
+ char tmp[NSIGNIF+10];
+ double g;
+
+ oerrno = errno; /* in case strtod smashes errno */
+
+ /*
+ * make f non-negative.
+ */
+ *neg = 0;
         if(f < 0) {
                 f = -f;
- sign++;
- }
- ucase = 0;
- chr = fmt->r;
- if(isupper(chr)) {
- ucase = 1;
- chr = tolower(chr);
- }
-
- e = 0;
- g = f;
- if(g != 0) {
- frexp(f, &e);
- e = e * .301029995664;
- if(e >= -150 && e <= +150) {
- d = 0;
- h = f;
- } else {
- d = e/2;
- h = f * pow10(-d);
- }
- g = h * pow10(d-e);
- while(g < 1) {
- e--;
- g = h * pow10(d-e);
- }
- while(g >= 10) {
- e++;
- g = h * pow10(d-e);
- }
+ *neg = 1;
         }
 
         /*
- * convert NSIGNIF digits and convert
- * back to get accuracy.
+ * must handle zero specially.
          */
- for(i=0; i<NSIGNIF; i++) {
- d = g;
- s1[i] = d + '0';
- g = (g - d) * 10;
+ if(f == 0){
+ *exp = 0;
+ s[0] = '0';
+ s[1] = '\0';
+ *ns = 1;
+ return;
         }
- s1[i] = 0;
-
+
         /*
- * try decimal rounding to eliminate 9s
+ * find g,e such that f = g*10^e.
+ * guess 10-exponent using 2-exponent, then fine tune.
          */
- c2 = prec + 1;
- if(chr == 'f')
- c2 += e;
- if(c2 >= NSIGNIF-2) {
- strcpy(s2, s1);
- d = e;
- s1[NSIGNIF-2] = '0';
- s1[NSIGNIF-1] = '0';
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- if(xadd(s1, NSIGNIF-3, 1)) {
- e++;
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- }
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- strcpy(s1, s2);
- e = d;
+ frexp(f, &e2);
+ e = (int)(e2 * .301029995664);
+ g = f * pow10(-e);
+ while(g < 1) {
+ e--;
+ g = f * pow10(-e);
+ }
+ while(g >= 10) {
+ e++;
+ g = f * pow10(-e);
         }
 
         /*
- * convert back so s1 gets exact answer
+ * convert NSIGNIF digits as a first approximation.
          */
- for(;;) {
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
+ for(i=0; i<NSIGNIF; i++) {
+ d = (int)g;
+ s[i] = d+'0';
+ g = (g-d) * 10;
+ }
+ s[i] = 0;
+
+ /*
+ * adjust e because s is 314159... not 3.14159...
+ */
+ e -= NSIGNIF-1;
+ xfmtexp(s+NSIGNIF, e, 0);
+
+ /*
+ * adjust conversion until strtod(s) == f exactly.
+ */
+ for(i=0; i<10; i++) {
+ g = fmtstrtod(s, nil);
                 if(f > g) {
- if(xadd(s1, NSIGNIF-1, 1))
+ if(xadd1(s, NSIGNIF)) {
+ /* gained a digit */
                                 e--;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
                         continue;
                 }
                 if(f < g) {
- if(xsub(s1, NSIGNIF-1, 1))
+ if(xsub1(s, NSIGNIF)) {
+ /* lost a digit */
                                 e++;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
                         continue;
                 }
                 break;
         }
 
-found:
         /*
- * sign
+ * play with the decimal to try to simplify.
          */
- d = 0;
- i = 0;
- if(sign)
- s2[d++] = '-';
- else if(fmt->flags & FmtSign)
- s2[d++] = '+';
- else if(fmt->flags & FmtSpace)
- s2[d++] = ' ';
 
         /*
- * copy into final place
- * c1 digits of leading '0'
- * c2 digits from conversion
- * c3 digits of trailing '0'
- * c4 digits after '.'
+ * bump last few digits up to 9 if we can
          */
- c1 = 0;
- c2 = prec + 1;
- c3 = 0;
- c4 = prec;
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '9') {
+ s[i] = '9';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add 1 in hopes of turning 9s to 0s
+ */
+ if(s[NSIGNIF-1] == '9') {
+ strcpy(tmp, s);
+ ee = e;
+ if(xadd1(tmp, NSIGNIF)) {
+ ee--;
+ xfmtexp(tmp+NSIGNIF, ee, 0);
+ }
+ g = fmtstrtod(tmp, nil);
+ if(g == f) {
+ strcpy(s, tmp);
+ e = ee;
+ }
+ }
+
+ /*
+ * bump last few digits down to 0 as we can.
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '0') {
+ s[i] = '0';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * remove trailing zeros.
+ */
+ ndigit = NSIGNIF;
+ while(ndigit > 1 && s[ndigit-1] == '0'){
+ e++;
+ --ndigit;
+ }
+ s[ndigit] = 0;
+ *exp = e;
+ *ns = ndigit;
+ errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+ char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+ double f;
+ int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
+ int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+ Rune r, *rs, *rt;
+
+ if(fmt->flags&FmtLong)
+ f = va_arg(fmt->args, long double);
+ else
+ f = va_arg(fmt->args, double);
+
+ /*
+ * extract formatting flags
+ */
+ fl = fmt->flags;
+ fmt->flags = 0;
+ prec = FDEFLT;
+ if(fl & FmtPrec)
+ prec = fmt->prec;
+ chr = fmt->r;
+ ucase = 0;
         switch(chr) {
- default:
- if(xadd(s1, c2, 5))
- e++;
- break;
- case 'g':
- /*
- * decide on 'e' of 'f' style convers
- */
- if(xadd(s1, c2, 5))
- e++;
- if(e >= -5 && e <= prec) {
- c1 = -e - 1;
- c4 = prec - e;
- chr = 'h'; // flag for 'f' style
- }
- break;
- case 'f':
- if(xadd(s1, c2+e, 5))
- e++;
- c1 = -e;
- if(c1 > prec)
- c1 = c2;
- c2 += e;
+ case 'A':
+ case 'E':
+ case 'F':
+ case 'G':
+ chr += 'a'-'A';
+ ucase = 1;
                 break;
         }
 
         /*
- * clean up c1 c2 and c3
+ * pick off special numbers.
          */
- if(c1 < 0)
- c1 = 0;
- if(c2 < 0)
- c2 = 0;
- if(c2 > NSIGNIF) {
- c3 = c2-NSIGNIF;
- c2 = NSIGNIF;
+ if(__isNaN(f)) {
+ s = special[0+ucase];
+ special:
+ fmt->flags = fl & (FmtWidth|FmtLeft);
+ return __fmtcpy(fmt, s, strlen(s), strlen(s));
+ }
+ if(__isInf(f, 1)) {
+ s = special[2+ucase];
+ goto special;
+ }
+ if(__isInf(f, -1)) {
+ s = special[4+ucase];
+ goto special;
         }
 
         /*
- * copy digits
+ * get exact representation.
          */
- while(c1 > 0) {
- if(c1+c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c1--;
+ digits = buf;
+ xdtoa(f, digits, &exp, &neg, &ndigits);
+
+ /*
+ * get locale's decimal point.
+ */
+ dot = fmt->decimal;
+ if(dot == nil)
+ dot = ".";
+ dotwid = utflen(dot);
+
+ /*
+ * now the formatting fun begins.
+ * compute parameters for actual fmt:
+ *
+ * pad: number of spaces to insert before/after field.
+ * z1: number of zeros to insert before digits
+ * z2: number of zeros to insert after digits
+ * point: number of digits to print before decimal point
+ * ndigits: number of digits to use from digits[]
+ * suf: trailing suffix, like "e-5"
+ */
+ realchr = chr;
+ switch(chr){
+ case 'g':
+ /*
+ * convert to at most prec significant digits. (prec=0 means 1)
+ */
+ if(prec == 0)
+ prec = 1;
+ if(ndigits > prec) {
+ if(digits[prec] >= '5' && xadd1(digits, prec))
+ exp++;
+ exp += ndigits-prec;
+ ndigits = prec;
+ }
+
+ /*
+ * extra rules for %g (implemented below):
+ * trailing zeros removed after decimal unless FmtSharp.
+ * decimal point only if digit follows.
+ */
+
+ /* fall through to %e */
+ default:
+ case 'e':
+ /*
+ * one significant digit before decimal, no leading zeros.
+ */
+ point = 1;
+ z1 = 0;
+
+ /*
+ * decimal point is after ndigits digits right now.
+ * slide to be after first.
+ */
+ e = exp + (ndigits-1);
+
+ /*
+ * if this is %g, check exponent and convert prec
+ */
+ if(realchr == 'g') {
+ if(-4 <= e && e < prec)
+ goto casef;
+ prec--; /* one digit before decimal; rest after */
+ }
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(1+prec >= ndigits)
+ z2 = 1+prec - ndigits;
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = 1+prec;
+ if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * had 999e4, now have 100e5
+ */
+ e++;
+ }
+ ndigits = newndigits;
+ z2 = 0;
+ }
+ xfmtexp(suf, e, ucase);
+ sufwid = strlen(suf);
+ break;
+
+ casef:
+ case 'f':
+ /*
+ * determine where digits go with respect to decimal point
+ */
+ if(ndigits+exp > 0) {
+ point = ndigits+exp;
+ z1 = 0;
+ } else {
+ point = 1;
+ z1 = 1 + -(ndigits+exp);
+ }
+
+ /*
+ * %g specifies prec = number of significant digits
+ * convert to number of digits after decimal point
+ */
+ if(realchr == 'g')
+ prec += z1 - point;
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(point+prec >= z1+ndigits)
+ z2 = point+prec - (z1+ndigits);
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = point+prec - z1;
+ if(newndigits < 0) {
+ z1 += newndigits;
+ newndigits = 0;
+ } else if(newndigits == 0) {
+ /* perhaps round up */
+ if(digits[0] >= '5'){
+ digits[0] = '1';
+ newndigits = 1;
+ goto newdigit;
+ }
+ } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * digits was 999, is now 100; make it 1000
+ */
+ digits[newndigits++] = '0';
+ newdigit:
+ /*
+ * account for new digit
+ */
+ if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
+ z1--;
+ else /* 9.99 => 10.00 */
+ point++;
+ }
+ z2 = 0;
+ ndigits = newndigits;
+ }
+ sufwid = 0;
+ break;
         }
- while(c2 > 0) {
- if(c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = s1[i++];
- c2--;
- }
- while(c3 > 0) {
- if(c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c3--;
+
+ /*
+ * if %g is given without FmtSharp, remove trailing zeros.
+ * must do after truncation, so that e.g. print %.3g 1.001
+ * produces 1, not 1.00. sorry, but them's the rules.
+ */
+ if(realchr == 'g' && !(fl & FmtSharp)) {
+ if(z1+ndigits+z2 >= point) {
+ if(z1+ndigits < point)
+ z2 = point - (z1+ndigits);
+ else{
+ z2 = 0;
+ while(z1+ndigits > point && digits[ndigits-1] == '0')
+ ndigits--;
+ }
+ }
         }
 
         /*
- * strip trailing '0' on g conv
+ * compute width of all digits and decimal point and suffix if any
          */
- if(fmt->flags & FmtSharp) {
- if(0 == c4)
- s2[d++] = '.';
- } else
- if(chr == 'g' || chr == 'h') {
- for(n=d-1; n>=0; n--)
- if(s2[n] != '0')
- break;
- for(i=n; i>=0; i--)
- if(s2[i] == '.') {
- d = n;
- if(i != n)
- d++;
- break;
+ wid = z1+ndigits+z2;
+ if(wid > point)
+ wid += dotwid;
+ else if(wid == point){
+ if(fl & FmtSharp)
+ wid += dotwid;
+ else
+ point++; /* do not print any decimal point */
+ }
+ wid += sufwid;
+
+ /*
+ * determine sign
+ */
+ sign = 0;
+ if(neg)
+ sign = '-';
+ else if(fl & FmtSign)
+ sign = '+';
+ else if(fl & FmtSpace)
+ sign = ' ';
+ if(sign)
+ wid++;
+
+ /*
+ * compute padding
+ */
+ pad = 0;
+ if((fl & FmtWidth) && fmt->width > wid)
+ pad = fmt->width - wid;
+ if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+ z1 += pad;
+ point += pad;
+ pad = 0;
+ }
+
+ /*
+ * format the actual field. too bad about doing this twice.
+ */
+ if(fmt->runes){
+ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ rt = (Rune*)fmt->to;
+ rs = (Rune*)fmt->stop;
+ if(sign)
+ FMTRCHAR(fmt, rt, rs, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
                         }
+ FMTRCHAR(fmt, rt, rs, c);
+ if(--point == 0) {
+ for(p = dot; *p; ){
+ p += chartorune(&r, p);
+ FMTRCHAR(fmt, rt, rs, r);
+ }
+ }
+ }
+ fmt->nfmt += rt - (Rune*)fmt->to;
+ fmt->to = rt;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ }else{
+ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ t = (char*)fmt->to;
+ s = (char*)fmt->stop;
+ if(sign)
+ FMTCHAR(fmt, t, s, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTCHAR(fmt, t, s, c);
+ if(--point == 0)
+ for(p=dot; *p; p++)
+ FMTCHAR(fmt, t, s, *p);
+ }
+ fmt->nfmt += t - (char*)fmt->to;
+ fmt->to = t;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
         }
- if(chr == 'e' || chr == 'g') {
- if(ucase)
- s2[d++] = 'E';
- else
- s2[d++] = 'e';
- c1 = e;
- if(c1 < 0) {
- s2[d++] = '-';
- c1 = -c1;
- } else
- s2[d++] = '+';
- if(c1 >= 100) {
- s2[d++] = c1/100 + '0';
- c1 = c1%100;
- }
- s2[d++] = c1/10 + '0';
- s2[d++] = c1%10 + '0';
- }
- s2[d] = 0;
-}
-
-static int
-floatfmt(Fmt *fmt, double f)
-{
- char s[FDIGIT+10];
-
- xdtoa(fmt, s, f);
- fmt->flags &= FmtWidth|FmtLeft;
- __fmtcpy(fmt, s, strlen(s), strlen(s));
         return 0;
 }
 
-int
-__efgfmt(Fmt *f)
-{
- double d;
-
- d = va_arg(f->args, double);
- return floatfmt(f, d);
-}
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmt.c
--- a/lib9/fmt/fmt.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -29,7 +17,7 @@
         volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
 };
 
-struct
+static struct
 {
         /* lock by calling __fmtlock, __fmtunlock */
         int nfmt;
@@ -40,6 +28,7 @@
         ' ', __flagfmt,
         '#', __flagfmt,
         '%', __percentfmt,
+ '\'', __flagfmt,
         '+', __flagfmt,
         ',', __flagfmt,
         '-', __flagfmt,
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtdef.h
--- a/lib9/fmt/fmtdef.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtdef.h Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 
 /*
  * dofmt -- format to a buffer
@@ -53,6 +41,7 @@
 int __ifmt(Fmt *f);
 int __isInf(double d, int sign);
 int __isNaN(double d);
+int __needsep(int*, char**);
 int __needsquotes(char *s, int *quotelenp);
 int __percentfmt(Fmt *f);
 void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
@@ -66,9 +55,9 @@
 #define FMTCHAR(f, t, s, c)\
         do{\
         if(t + 1 > (char*)s){\
- t = __fmtflush(f, t, 1);\
+ t = (char*)__fmtflush(f, t, 1);\
                 if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
                 else\
                         return -1;\
         }\
@@ -78,9 +67,9 @@
 #define FMTRCHAR(f, t, s, c)\
         do{\
         if(t + 1 > (Rune*)s){\
- t = __fmtflush(f, t, sizeof(Rune));\
+ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
                 if(t != nil)\
- s = f->stop;\
+ s = (Rune*)f->stop;\
                 else\
                         return -1;\
         }\
@@ -92,9 +81,9 @@
         Rune _rune;\
         int _runelen;\
         if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
- t = __fmtflush(f, t, _runelen);\
+ t = (char*)__fmtflush(f, t, _runelen);\
                 if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
                 else\
                         return -1;\
         }\
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtfd.c
--- a/lib9/fmt/fmtfd.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtfd.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -40,7 +28,9 @@
         f->to = buf;
         f->stop = buf + size;
         f->flush = __fmtFdFlush;
- f->farg = (void*)fd;
+ f->farg = (void*)(uintptr_t)fd;
+ f->flags = 0;
         f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
         return 0;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtfdflush.c
--- a/lib9/fmt/fmtfdflush.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtfdflush.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <unistd.h>
 #include "plan9.h"
@@ -27,7 +15,7 @@
         int n;
 
         n = (char*)f->to - (char*)f->start;
- if(n && write((int)f->farg, f->start, n) != n)
+ if(n && write((uintptr)f->farg, f->start, n) != n)
                 return 0;
         f->to = f->start;
         return 1;
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtlocale.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/fmt/fmtlocale.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,55 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ * decimal is a period
+ * thousands separator is a comma
+ * thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+ if(decimal == nil || decimal[0] == '\0')
+ decimal = ".";
+ if(thousands == nil)
+ thousands = ",";
+ if(grouping == nil)
+ grouping = "\3";
+ f->decimal = decimal;
+ f->thousands = thousands;
+ f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d. If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator. Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+ int group;
+
+ (*ndig)++;
+ group = *(unsigned char*)*grouping;
+ /* CHAR_MAX means no further grouping. \0 means we got the empty string */
+ if(group == 0xFF || group == 0x7f || group == 0x00)
+ return 0;
+ if(*ndig > group){
+ /* if we're at end of string, continue with this grouping; else advance */
+ if((*grouping)[1] != '\0')
+ (*grouping)++;
+ *ndig = 1;
+ return 1;
+ }
+ return 0;
+}
+
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtlock.c
--- a/lib9/fmt/fmtlock.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtlock.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtnull.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/fmt/fmtnull.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,33 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+ f->to = nullbuf;
+ f->nfmt = 0;
+ return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+ memset(f, 0, sizeof *f);
+ f->runes = 1;
+ f->start = nullbuf;
+ f->to = nullbuf;
+ f->stop = nullbuf+nelem(nullbuf);
+ f->flush = __fmtnullflush;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtprint.c
--- a/lib9/fmt/fmtprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtquote.c
--- a/lib9/fmt/fmtquote.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtquote.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -103,6 +91,11 @@
                 /* advance output */
                 q->nbytesout += w;
                 q->nrunesout++;
+
+#ifndef PLAN9PORT
+ /* ANSI requires precision in bytes, not Runes. */
+ nin-= w-1; /* and then n-- in the loop */
+#endif
         }
 }
 
@@ -120,8 +113,10 @@
         rm = rin;
         rme = rm + q->nrunesin;
 
- w = f->width;
         fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
         if(f->runes){
                 if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
                         return -1;
@@ -209,7 +204,7 @@
                 outlen = (char*)f->stop - (char*)f->to;
 
         __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
-//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
 
         if(runesin){
                 if(!q.quoted)
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtrune.c
--- a/lib9/fmt/fmtrune.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtrune.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtstr.c
--- a/lib9/fmt/fmtstr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtstr.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdlib.h>
 #include <stdarg.h>
 #include "plan9.h"
@@ -23,5 +11,6 @@
         if(f->start == nil)
                 return nil;
         *(char*)f->to = '\0';
+ f->to = f->start;
         return (char*)f->start;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fmtvprint.c
--- a/lib9/fmt/fmtvprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fmtvprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/fprint.c
--- a/lib9/fmt/fprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/fprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/nan.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/fmt/nan.h Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern int __isNaN(double);
+extern int __isInf(double, int);
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/nan64.c
--- a/lib9/fmt/nan64.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/nan64.c Fri Jul 31 21:02:58 2009 +0100
@@ -6,58 +6,67 @@
  */
 
 #include "plan9.h"
+#include <assert.h>
 #include "fmt.h"
 #include "fmtdef.h"
-
-#if defined (__APPLE__) || (__powerpc__)
-#define _NEEDLL
-#endif
 
 static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
 static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
 static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
 
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.d = d;
+ return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.v = v;
+ return u.d;
+}
+
 double
 __NaN(void)
 {
- uvlong *p;
-
- /* gcc complains about "return *(double*)&uvnan;" */
- p = &uvnan;
- return *(double*)p;
+ return u2d(uvnan);
 }
 
 int
 __isNaN(double d)
 {
         uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
- return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
+
+ x = d2u(d);
+ /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+ return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
 }
 
 double
 __Inf(int sign)
 {
- uvlong *p;
-
- if(sign < 0)
- p = &uvinf;
- else
- p = &uvneginf;
- return *(double*)p;
+ return u2d(sign < 0 ? uvneginf : uvinf);
 }
 
 int
 __isInf(double d, int sign)
 {
         uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
+
+ x = d2u(d);
         if(sign == 0)
                 return x==uvinf || x==uvneginf;
         else if(sign > 0)
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/plan9.h
--- a/lib9/fmt/plan9.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/plan9.h Fri Jul 31 21:02:58 2009 +0100
@@ -1,3 +1,5 @@
+#include <inttypes.h>
+
 /*
  * compiler directive on Plan 9
  */
@@ -14,12 +16,15 @@
 #define ulong _fmtulong
 #define vlong _fmtvlong
 #define uvlong _fmtuvlong
+#define uintptr _fmtuintptr
+
 typedef unsigned char uchar;
 typedef unsigned short ushort;
 typedef unsigned int uint;
 typedef unsigned long ulong;
 typedef unsigned long long uvlong;
 typedef long long vlong;
+typedef uintptr_t uintptr;
 
 /*
  * nil cannot be ((void*)0) on ANSI C,
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/pow10.c
--- a/lib9/fmt/pow10.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/pow10.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/print.c
--- a/lib9/fmt/print.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/print.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runefmtstr.c
--- a/lib9/fmt/runefmtstr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runefmtstr.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <stdlib.h>
 #include "plan9.h"
@@ -23,5 +11,6 @@
         if(f->start == nil)
                 return nil;
         *(Rune*)f->to = '\0';
+ f->to = f->start;
         return f->start;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runeseprint.c
--- a/lib9/fmt/runeseprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runeseprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runesmprint.c
--- a/lib9/fmt/runesmprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runesmprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runesnprint.c
--- a/lib9/fmt/runesnprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runesnprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runesprint.c
--- a/lib9/fmt/runesprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runesprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runevseprint.c
--- a/lib9/fmt/runevseprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runevseprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -32,6 +20,7 @@
         f.farg = nil;
         f.nfmt = 0;
         VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
         dofmt(&f, fmt);
         VA_END(f.args);
         *(Rune*)f.to = '\0';
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runevsmprint.c
--- a/lib9/fmt/runevsmprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runevsmprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 /*
  * Plan 9 port version must include libc.h in order to
  * get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@
 
         if(f->start == nil)
                 return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
         n *= 2;
         s = (Rune*)f->start;
         f->start = realloc(s, sizeof(Rune)*n);
@@ -47,7 +35,7 @@
                 free(s);
                 return 0;
         }
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
         f->to = (Rune*)f->start + ((Rune*)f->to - s);
         f->stop = (Rune*)f->start + n - 1;
         return 1;
@@ -67,8 +55,9 @@
         f->to = f->start;
         f->stop = (Rune*)f->start + n - 1;
         f->flush = runeFmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
         f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
         return 0;
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/runevsnprint.c
--- a/lib9/fmt/runevsnprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/runevsnprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
@@ -32,6 +20,7 @@
         f.farg = nil;
         f.nfmt = 0;
         VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
         dofmt(&f, fmt);
         VA_END(f.args);
         *(Rune*)f.to = '\0';
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/seprint.c
--- a/lib9/fmt/seprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/seprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/smprint.c
--- a/lib9/fmt/smprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/smprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/snprint.c
--- a/lib9/fmt/snprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/snprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/sprint.c
--- a/lib9/fmt/sprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/sprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include <fmt.h>
 #include "plan9.h"
@@ -28,9 +16,12 @@
         /*
          * on PowerPC, the stack is near the top of memory, so
          * we must be sure not to overflow a 32-bit pointer.
+ *
+ * careful! gcc-4.2 assumes buf+len < buf can never be true and
+ * optimizes the test away. casting to uintptr works around this bug.
          */
- if(buf+len < buf)
- len = -(uint)buf-1;
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uintptr)buf-1;
 
         va_start(args, fmt);
         n = vsnprint(buf, len, fmt, args);
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/strtod.c
--- a/lib9/fmt/strtod.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/strtod.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdlib.h>
 #include <math.h>
 #include <ctype.h>
@@ -67,7 +55,7 @@
         S4, /* _+#.# #S4 eS5 */
         S5, /* _+#.#e +S6 #S7 */
         S6, /* _+#.#e+ #S7 */
- S7, /* _+#.#e+# #S7 */
+ S7 /* _+#.#e+# #S7 */
 };
 
 static int xcmp(char*, char*);
@@ -239,7 +227,7 @@
         /* close approx by naive conversion */
         mid[0] = 0;
         mid[1] = 1;
- for(i=0; c=a[i]; i++) {
+ for(i=0; (c=a[i]) != '\0'; i++) {
                 mid[0] = mid[0]*10 + (c-'0');
                 mid[1] = mid[1]*10;
                 if(i >= 8)
@@ -521,7 +509,7 @@
 {
         int c1, c2;
 
- while(c1 = *b++) {
+ while((c1 = *b++) != '\0') {
                 c2 = *a++;
                 if(isupper(c2))
                         c2 = tolower(c2);
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/test.c
--- a/lib9/fmt/test.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/test.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
 #include <stdio.h>
 #include <stdarg.h>
 #include <utf.h>
@@ -40,5 +30,24 @@
         print("%d\n", 23);
         print("%i\n", 23);
         print("%0.10d\n", 12345);
+
+ /* test %4$d formats */
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+ print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+ print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+ /* test %'d formats */
+ print("%'d %'d %'d\n", 1, 2222, 33333333);
+ print("%'019d\n", 0);
+ print("%08d %08d %08d\n", 1, 2222, 33333333);
+ print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+ print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+ print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
         return 0;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/vfprint.c
--- a/lib9/fmt/vfprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/vfprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/vseprint.c
--- a/lib9/fmt/vseprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/vseprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdarg.h>
 #include "plan9.h"
 #include "fmt.h"
@@ -31,6 +19,7 @@
         f.farg = nil;
         f.nfmt = 0;
         VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
         dofmt(&f, fmt);
         VA_END(f.args);
         *(char*)f.to = '\0';
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/vsmprint.c
--- a/lib9/fmt/vsmprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/vsmprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 /*
  * Plan 9 port version must include libc.h in order to
  * get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@
 
         if(f->start == nil)
                 return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
         n *= 2;
         s = (char*)f->start;
         f->start = realloc(s, n);
@@ -47,7 +35,7 @@
                 free(s);
                 return 0;
         }
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
         f->to = (char*)f->start + ((char*)f->to - s);
         f->stop = (char*)f->start + n - 1;
         return 1;
@@ -67,8 +55,9 @@
         f->to = f->start;
         f->stop = (char*)f->start + n - 1;
         f->flush = fmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
         f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
         return 0;
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/fmt/vsnprint.c
--- a/lib9/fmt/vsnprint.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/fmt/vsnprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
 #include <stdlib.h>
 #include <stdarg.h>
 #include "plan9.h"
@@ -32,6 +20,7 @@
         f.farg = nil;
         f.nfmt = 0;
         VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
         dofmt(&f, fmt);
         VA_END(f.args);
         *(char*)f.to = '\0';
diff -r bb17f966e24a -r 1161d90df941 lib9/getcallerpc-arm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/getcallerpc-arm.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+ return ((ulong*)x)[-2];
+}
+
diff -r bb17f966e24a -r 1161d90df941 lib9/getnetconn.c
--- a/lib9/getnetconn.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/getnetconn.c Fri Jul 31 21:02:58 2009 +0100
@@ -91,12 +91,12 @@
         nci->spec = unknown;
         if(nci->dir == nil || nci->root == nil)
                 goto err;
- sn = sizeof sn;
+ sn = sizeof u;
         if(getsockname(fd, &u.sa, &sn) < 0)
                 goto err;
         if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0)
                 goto err;
- sn = sizeof sn;
+ sn = sizeof u;
         if(getpeername(fd, &u.sa, &sn) < 0)
                 goto err;
         if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0)
diff -r bb17f966e24a -r 1161d90df941 lib9/getns.c
--- a/lib9/getns.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/getns.c Fri Jul 31 21:02:58 2009 +0100
@@ -2,6 +2,17 @@
 #include <libc.h>
 #include <ctype.h>
 
+static int
+isme(char *uid)
+{
+ int n;
+ char *p;
+
+ n = strtol(uid, &p, 10);
+ if(*p == 0 && p > uid)
+ return n == getuid();
+ return strcmp(getuser(), uid) == 0;
+}
 /*
  * Absent other hints, it works reasonably well to use
  * the X11 display name as the name space identifier.
@@ -18,8 +29,15 @@
         char *disp, *p;
 
         if((disp = getenv("DISPLAY")) == nil){
+#ifdef __APPLE__
+ // Might be running native GUI on OS X.
+ disp = strdup(":0.0");
+ if(disp == nil)
+ return nil;
+#else
                 werrstr("$DISPLAY not set");
                 return nil;
+#endif
         }
 
         /* canonicalize: xxx:0.0 => xxx:0 */
@@ -31,6 +49,11 @@
                 if(strcmp(p, ".0") == 0)
                         *p = 0;
         }
+
+ /* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */
+ for(p=disp; *p; p++)
+ if(*p == '/')
+ *p = '_';
 
         p = smprint("/tmp/ns.%s.%s", getuser(), disp);
         free(disp);
@@ -48,7 +71,7 @@
                 free(p);
                 return nil;
         }
- if((d->mode&0777) != 0700 || strcmp(d->uid, getuser()) != 0){
+ if((d->mode&0777) != 0700 || !isme(d->uid)){
                 werrstr("bad name space dir %s", p);
                 free(p);
                 free(d);
diff -r bb17f966e24a -r 1161d90df941 lib9/lib9.h
--- a/lib9/lib9.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/lib9.h Fri Jul 31 21:02:58 2009 +0100
@@ -1,17 +1,2 @@
-#include <string.h>
-#include "utf.h"
-
-#define nil ((void*)0)
-
-#define uchar _fmtuchar
-#define ushort _fmtushort
-#define uint _fmtuint
-#define ulong _fmtulong
-#define vlong _fmtvlong
-#define uvlong _fmtuvlong
-
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-
+#include <u.h>
+#include <libc.h>
diff -r bb17f966e24a -r 1161d90df941 lib9/libc.h
--- a/lib9/libc.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/libc.h Fri Jul 31 21:02:58 2009 +0100
@@ -349,7 +349,7 @@
 enum
 {
         PNPROC = 1,
- PNGROUP = 2,
+ PNGROUP = 2
 };
 
 /* extern int abs(int); <stdlib.h> */
@@ -376,6 +376,7 @@
 extern int enc16(char*, int, uchar*, int);
 extern int encodefmt(Fmt*);
 extern int dirmodefmt(Fmt*);
+extern int exitcode(char*);
 extern void exits(char*);
 extern double frexp(double, int*);
 extern ulong getcallerpc(void*);
@@ -390,7 +391,7 @@
 /* extern double ldexp(double, int); <math.h> */
 extern void p9longjmp(p9jmp_buf, int);
 extern char* mktemp(char*);
-extern int opentemp(char*);
+extern int opentemp(char*, int);
 /* extern double modf(double, double*); <math.h> */
 extern void p9notejmp(void*, p9jmp_buf, int);
 extern void perror(const char*);
@@ -415,6 +416,9 @@
 /* extern int toupper(int); <ctype.h> */
 extern void needstack(int);
 extern char* readcons(char*, char*, int);
+
+extern void (*_pin)(void);
+extern void (*_unpin)(void);
 
 #ifndef NOPLAN9DEFINES
 #define atexit p9atexit
@@ -670,7 +674,7 @@
         RFNOWAIT = (1<<6),
         RFCNAMEG = (1<<10),
         RFCENVG = (1<<11),
- RFCFDG = (1<<12),
+ RFCFDG = (1<<12)
 /* RFREND = (1<<13), */
 /* RFNOMNT = (1<<14) */
 };
@@ -789,6 +793,7 @@
 extern long write(int, void*, long);
 extern long writev(int, IOchunk*, int);
 */
+extern long p9write(int, void*, long);
 /* extern int wstat(char*, uchar*, int); give up */
 extern ulong rendezvous(ulong, ulong);
 
@@ -809,6 +814,7 @@
 #define open p9open
 #define pipe p9pipe
 #define waitfor p9waitfor
+#define write p9write
 #endif
 
 extern Dir* dirstat(char*);
@@ -828,7 +834,8 @@
 extern char* unsharp(char*);
 extern int sendfd(int, int);
 extern int recvfd(int);
-extern int post9pservice(int, char*);
+extern int post9pservice(int, char*, char*);
+extern int chattyfuse;
 
 /* external names that we don't want to step on */
 #ifndef NOPLAN9DEFINES
@@ -900,7 +907,7 @@
 #ifdef __GNUC__
 # if __GNUC__ >= 3
 # undef USED
-# define USED(x) { ulong __y __attribute__ ((unused)); __y = (ulong)(x); }
+# define USED(x) ((void)(x))
 # endif
 #endif
 
diff -r bb17f966e24a -r 1161d90df941 lib9/malloctag.c
--- a/lib9/malloctag.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/malloctag.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,8 +1,4 @@
 #include <lib9.h>
-
-extern long p9lrand(void);
-#define USED(x) if(x){}else{}
-#define lrand p9lrand
 
 void
 setmalloctag(void *v, ulong t)
diff -r bb17f966e24a -r 1161d90df941 lib9/nan.c
--- a/lib9/nan.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/nan.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,6 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include "nan.h"
+#include "fmt/nan.h"
 
 double
 NaN(void)
diff -r bb17f966e24a -r 1161d90df941 lib9/netcrypt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/netcrypt.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+
+int
+netcrypt(void *key, void *chal)
+{
+ uchar buf[8], *p;
+
+ strncpy((char*)buf, chal, 7);
+ buf[7] = '\0';
+ for(p = buf; *p && *p != '\n'; p++)
+ ;
+ *p = '\0';
+ encrypt(key, buf, 8);
+ sprint(chal, "%.2ux%.2ux%.2ux%.2ux", buf[0], buf[1], buf[2], buf[3]);
+ return 1;
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/netmkaddr.c
--- a/lib9/netmkaddr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/netmkaddr.c Fri Jul 31 21:02:58 2009 +0100
@@ -16,21 +16,25 @@
          */
         cp = strchr(linear, '!');
         if(cp == 0){
- if(defnet==0){
- if(defsrv)
- snprint(addr, sizeof(addr), "net!%s!%s",
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "net!%s", linear);
+ if(defnet == 0)
+ defnet = "net";
+ /* allow unix sockets to omit unix! prefix */
+ if(access(linear, 0) >= 0){
+ snprint(addr, sizeof(addr), "unix!%s", linear);
+ return addr;
                 }
- else {
- if(defsrv)
- snprint(addr, sizeof(addr), "%s!%s!%s", defnet,
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "%s!%s", defnet,
- linear);
+ /* allow host:service in deference to Unix convention */
+ if((cp = strchr(linear, ':')) != nil){
+ snprint(addr, sizeof(addr), "%s!%.*s!%s",
+ defnet, utfnlen(linear, cp-linear),
+ linear, cp+1);
+ return addr;
                 }
+ if(defsrv)
+ snprint(addr, sizeof(addr), "%s!%s!%s",
+ defnet, linear, defsrv);
+ else
+ snprint(addr, sizeof(addr), "%s!%s", defnet, linear);
                 return addr;
         }
 
@@ -42,11 +46,17 @@
                 return linear;
 
         /*
+ * if the network is unix, no service
+ */
+ if(strncmp(linear, "unix!", 5) == 0)
+ return linear;
+
+ /*
          * add default service
          */
         if(defsrv == 0)
                 return linear;
+
         snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
-
         return addr;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/notify.c
--- a/lib9/notify.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/notify.c Fri Jul 31 21:02:58 2009 +0100
@@ -38,6 +38,7 @@
 {
         Restart = 1<<0,
         Ignore = 1<<1,
+ NoNotify = 1<<2,
 };
 
 static Sig sigs[] = {
@@ -58,7 +59,7 @@
         SIGPIPE, Ignore,
         SIGALRM, 0,
         SIGTERM, 0,
- SIGTSTP, Restart|Ignore,
+ SIGTSTP, Restart|Ignore|NoNotify,
 /* SIGTTIN, Restart|Ignore, */
 /* SIGTTOU, Restart|Ignore, */
         SIGXCPU, 0,
@@ -67,10 +68,10 @@
         SIGUSR1, 0,
         SIGUSR2, 0,
 #ifdef SIGWINCH
- SIGWINCH, Restart|Ignore,
+ SIGWINCH, Restart|Ignore|NoNotify,
 #endif
 #ifdef SIGINFO
- SIGINFO, Restart|Ignore,
+ SIGINFO, Restart|Ignore|NoNotify,
 #endif
 };
 
@@ -266,7 +267,7 @@
                  */
                 if(handler(sig->sig) != SIG_DFL)
                         continue;
- notifyseton(sig->sig, 1);
+ notifyseton(sig->sig, !(sig->flags&NoNotify));
         }
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/nrand.c
--- a/lib9/nrand.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/nrand.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,7 +1,5 @@
 #include <lib9.h>
 
-extern long p9lrand(void);
-#define lrand p9lrand
 #define MASK 0x7fffffffL
 
 int
diff -r bb17f966e24a -r 1161d90df941 lib9/nulldir.c
--- a/lib9/nulldir.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/nulldir.c Fri Jul 31 21:02:58 2009 +0100
@@ -5,5 +5,5 @@
 nulldir(Dir *d)
 {
         memset(d, ~0, sizeof(Dir));
- d->name = d->uid = d->gid = d->muid = "";
+ d->name = d->uid = d->gid = d->muid = d->ext = "";
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/opentemp.c
--- a/lib9/opentemp.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/opentemp.c Fri Jul 31 21:02:58 2009 +0100
@@ -2,14 +2,19 @@
 #include <libc.h>
 
 int
-opentemp(char *template)
+opentemp(char *template, int mode)
 {
- int fd;
+ int fd, fd1;
 
         fd = mkstemp(template);
         if(fd < 0)
                 return -1;
- remove(template);
- return fd;
+ if((fd1 = open(template, mode)) < 0){
+ remove(template);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return fd1;
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/pin.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/pin.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,11 @@
+#include <u.h>
+#include <libc.h>
+
+static void
+nop(void)
+{
+}
+
+void (*_pin)(void) = nop;
+void (*_unpin)(void) = nop;
+
diff -r bb17f966e24a -r 1161d90df941 lib9/portdate
--- a/lib9/portdate Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/portdate Fri Jul 31 21:02:58 2009 +0100
@@ -1,30 +1,55 @@
-dofmt.c 2004/1225
-dorfmt.c 2004/1225
-errfmt.c 2004/1225
-fltfmt.c 2004/1225
-fmt.c 2004/1225
-fmtfd.c 2004/1225
-fmtlock.c 2004/1225
-fmtprint.c 2004/1225
-fmtquote.c 2004/1225
-fmtrune.c 2004/1225
-fmtstr.c 2004/1225
-fmtvprint.c 2004/1225
-fprint.c 2004/1225
-print.c 2004/1225
-runefmtstr.c 2004/1225
-runeseprint.c 2004/1225
-runesmprint.c 2004/1225
-runesnprint.c 2004/1225
-runesprint.c 2004/1225
-runevseprint.c 2004/1225
-runevsmprint.c 2004/1225
-runevsnprint.c 2004/1225
-seprint.c 2004/1225
-smprint.c 2004/1225
-snprint.c 2004/1225
-sprint.c 2004/1225
-vfprint.c 2004/1225
-vseprint.c 2004/1225
-vsmprint.c 2004/1225
-vsnprint.c 2004/1225
+announce.c 2004/1225
+atexit.c 2004/1225
+atnotify.c 2004/1225
+atol.c 2004/1225
+atoll.c 2004/1225
+cistrcmp.c 2004/1225
+cistrncmp.c 2004/1225
+cistrstr.c 2004/1225
+cleanname.c 2004/1225
+convD2M.c 2004/1225
+convM2D.c 2004/1225
+convM2S.c 2004/1225
+convS2M.c 2004/1225
+ctime.c 2004/1225
+dial.c 2004/1225
+dirfstat.c 2004/1225
+dirfwstat.c 2004/1225
+dirmodefmt.c 2004/1225
+dirread.c 2004/1225
+dirstat.c 2004/1225
+dirwstat.c 2004/1225
+encodefmt.c 2004/1225
+fcallfmt.c 2004/1225
+fork.c 2004/1225
+getenv.c 2004/1225
+getfields.c 2004/1225
+getuser.c 2004/1225
+getwd.c 2004/1225
+lnrand.c 2004/1225
+lock.c 2004/1225
+lrand.c 2004/1225
+malloc.c 2004/1225
+nan.c 2004/1225
+needsrcquote.c 2004/1225
+netmkaddr.c 2004/1225
+nrand.c 2004/1225
+nulldir.c 2004/1225
+postnote.c 2004/1225
+qlock.c 2004/1225
+quote.c 2004/1225
+rand.c 2004/1225
+read9pmsg.c 2004/1225
+readn.c 2004/1225
+strdup.c 2004/1225
+strecpy.c 2004/1225
+sysfatal.c 2004/1225
+sysname.c 2004/1225
+time.c 2004/1225
+tokenize.c 2004/1225
+truerand.c 2004/1225
+u16.c 2004/1225
+u32.c 2004/1225
+u64.c 2004/1225
+wait.c 2004/1225
+waitpid.c 2004/1225
diff -r bb17f966e24a -r 1161d90df941 lib9/post9p.c
--- a/lib9/post9p.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/post9p.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,46 +1,83 @@
 #include <u.h>
 #include <libc.h>
 
+int chattyfuse;
+
 int
-post9pservice(int fd, char *name)
+post9pservice(int fd, char *name, char *mtpt)
 {
- int i;
- char *ns, *s;
+ int i, pid;
+ char *ns, *addr;
         Waitmsg *w;
 
- if(strchr(name, '!')) /* assume is already network address */
- s = strdup(name);
- else{
- if((ns = getns()) == nil)
+ if(name == nil && mtpt == nil){
+ close(fd);
+ werrstr("nothing to do");
+ return -1;
+ }
+
+ if(name){
+ if(strchr(name, '!')) /* assume is already network address */
+ addr = strdup(name);
+ else{
+ if((ns = getns()) == nil)
+ return -1;
+ addr = smprint("unix!%s/%s", ns, name);
+ free(ns);
+ }
+ if(addr == nil)
                         return -1;
- s = smprint("unix!%s/%s", ns, name);
- free(ns);
- }
- if(s == nil)
- return -1;
- switch(fork()){
- case -1:
- return -1;
- case 0:
- dup(fd, 0);
- dup(fd, 1);
- for(i=3; i<20; i++)
- close(i);
- execlp("9pserve", "9pserve", "-u", s, (char*)0);
- fprint(2, "exec 9pserve: %r\n");
- _exits("exec");
- default:
- w = wait();
+ switch(pid = fork()){
+ case -1:
+ return -1;
+ case 0:
+ dup(fd, 0);
+ dup(fd, 1);
+ for(i=3; i<20; i++)
+ close(i);
+ execlp("9pserve", "9pserve", "-u", addr, (char*)0);
+ fprint(2, "exec 9pserve: %r\n");
+ _exits("exec");
+ }
+ close(fd);
+ w = waitfor(pid);
                 if(w == nil)
                         return -1;
- close(fd);
- free(s);
                 if(w->msg && w->msg[0]){
                         free(w);
                         werrstr("9pserve failed");
                         return -1;
                 }
                 free(w);
- return 0;
+ if(mtpt){
+ /* reopen */
+ if((fd = dial(addr, nil, nil, nil)) < 0){
+ werrstr("cannot reopen for mount: %r");
+ return -1;
+ }
+ }
+ free(addr);
         }
+ if(mtpt){
+ switch(pid = rfork(RFFDG|RFPROC|RFNOWAIT)){
+ case -1:
+ return -1;
+ case 0:
+ dup(fd, 0);
+ for(i=3; i<20; i++)
+ close(i);
+
+ /* Try v9fs on Linux, which will mount 9P directly. */
+ execlp("mount9p", "mount9p", "-", mtpt, (char*)0);
+
+ if(chattyfuse)
+ execlp("9pfuse", "9pfuse", "-D", "-", mtpt, (char*)0);
+ else
+ execlp("9pfuse", "9pfuse", "-", mtpt, (char*)0);
+ fprint(2, "exec 9pfuse: %r\n");
+ _exits("exec");
+ }
+ close(fd);
+ }
+ return 0;
 }
diff -r bb17f966e24a -r 1161d90df941 lib9/rand.c
--- a/lib9/rand.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/rand.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,7 +1,4 @@
 #include <lib9.h>
-
-extern long p9lrand(void);
-#define lrand p9lrand
 
 int
 p9rand(void)
diff -r bb17f966e24a -r 1161d90df941 lib9/readn.c
--- a/lib9/readn.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/readn.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,5 +1,4 @@
 #include <lib9.h>
-#include <unistd.h>
 
 long
 readn(int f, void *av, long n)
diff -r bb17f966e24a -r 1161d90df941 lib9/regex/regcomp.c
--- a/lib9/regex/regcomp.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/regex/regcomp.c Fri Jul 31 21:02:58 2009 +0100
@@ -261,18 +261,18 @@
                 case STAR:
                 case PLUS:
                 case QUEST:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
                         break;
                 case CCLASS:
                 case NCCLASS:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
                         cl = inst->u1.cp;
- *(char **)&cl->end += diff;
+ cl->end = (void*)((char*)cl->end + diff);
                         break;
                 }
- *(char **)&inst->u2.left += diff;
+ inst->u2.left = (void*)((char*)inst->u2.left + diff);
         }
- *(char **)&npp->startinst += diff;
+ npp->startinst = (void*)((char*)npp->startinst + diff);
         return npp;
 }
 
diff -r bb17f966e24a -r 1161d90df941 lib9/regex/regexec.c
--- a/lib9/regex/regexec.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/regex/regexec.c Fri Jul 31 21:02:58 2009 +0100
@@ -58,7 +58,7 @@
                                 p = utfrune(s, '\n');
                                 if(p == 0 || s == j->eol)
                                         return match;
- s = p;
+ s = p+1;
                                 break;
                         }
                 }
diff -r bb17f966e24a -r 1161d90df941 lib9/regex/rregexec.c
--- a/lib9/regex/rregexec.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/regex/rregexec.c Fri Jul 31 21:02:58 2009 +0100
@@ -25,6 +25,7 @@
         Relist* tle; /* ends of this and next list */
         Relist* nle;
         int match;
+ Rune *p;
 
         match = 0;
         checkstart = j->startchar;
@@ -44,20 +45,18 @@
                 if(checkstart) {
                         switch(j->starttype) {
                         case RUNE:
- while(*s != j->startchar) {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, j->startchar);
+ if(p == 0 || p == j->reol)
+ return match;
+ s = p;
                                 break;
                         case BOL:
                                 if(s == bol)
                                         break;
- while(*s != '\n') {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, '\n');
+ if(p == 0 || s == j->reol)
+ return match;
+ s = p+1;
                                 break;
                         }
                 }
diff -r bb17f966e24a -r 1161d90df941 lib9/rfork.c
--- a/lib9/rfork.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/rfork.c Fri Jul 31 21:02:58 2009 +0100
@@ -17,11 +17,12 @@
         int p[2];
         int n;
         char buf[128], *q;
+ extern char **environ;
 
         if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
                 /* check other flags before we commit */
- flags &= ~(RFPROC|RFFDG);
- n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
                 if(n){
                         werrstr("unknown flags %08ux in rfork", n);
                         return -1;
@@ -99,9 +100,12 @@
                 }
                 if(pid != 0)
                         return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
         }
         if(flags&RFPROC){
- werrstr("cannot use rfork for shared memory -- use ffork");
+ werrstr("cannot use rfork for shared memory -- use libthread");
                 return -1;
         }
         if(flags&RFNAMEG){
diff -r bb17f966e24a -r 1161d90df941 lib9/sendfd.c
--- a/lib9/sendfd.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/sendfd.c Fri Jul 31 21:02:58 2009 +0100
@@ -78,7 +78,10 @@
 
         if((n=recvmsg(s, &msg, 0)) < 0)
                 return -1;
-
+ if(n == 0){
+ werrstr("unexpected EOF");
+ return -1;
+ }
         cmsg = CMSG_FIRSTHDR(&msg);
         fd = *(int*)CMSG_DATA(cmsg);
         return fd;
diff -r bb17f966e24a -r 1161d90df941 lib9/sleep.c
--- a/lib9/sleep.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/sleep.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,8 +1,20 @@
 #include <u.h>
 #define NOPLAN9DEFINES
+#include <sys/param.h>
 #include <sys/time.h>
 #include <sched.h>
 #include <libc.h>
+
+#if defined(__NetBSD__) || (defined(__OpenBSD__) && OpenBSD <= 200611)
+#if !defined(sched_yield)
+# define sched_yield() \
+ do{ struct timespec ts; \
+ ts.tv_sec = 0; \
+ ts.tv_nsec = 0; \
+ nanosleep(&ts, 0); \
+ }while(0)
+#endif
+#endif
 
 int
 p9sleep(long milli)
diff -r bb17f966e24a -r 1161d90df941 lib9/sysfatal.c
--- a/lib9/sysfatal.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/sysfatal.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,10 +1,5 @@
 #include <lib9.h>
-#include <stdarg.h>
-#include "fmt.h"
 
-extern char *argv0;
-extern void __fixargv0(void);
-extern void exits(char*);
 void (*_sysfatal)(char*, ...);
 
 void
diff -r bb17f966e24a -r 1161d90df941 lib9/test.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/test.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+int
+main(int argc, char **argv)
+{
+ werrstr("hello world");
+ print("%r\n");
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/testfltfmt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/testfltfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,183 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+/*
+ * try all combination of flags and float conversions
+ * with some different widths & precisions
+ */
+
+#define Njust 2
+#define Nplus 3
+#define Nalt 2
+#define Nzero 2
+#define Nspec 5
+#define Nwidth 5
+#define Nprec 5
+
+static double fmtvals[] = {
+ 3.1415925535897932e15,
+ 3.1415925535897932e14,
+ 3.1415925535897932e13,
+ 3.1415925535897932e12,
+ 3.1415925535897932e11,
+ 3.1415925535897932e10,
+ 3.1415925535897932e9,
+ 3.1415925535897932e8,
+ 3.1415925535897932e7,
+ 3.1415925535897932e6,
+ 3.1415925535897932e5,
+ 3.1415925535897932e4,
+ 3.1415925535897932e3,
+ 3.1415925535897932e2,
+ 3.1415925535897932e1,
+ 3.1415925535897932e0,
+ 3.1415925535897932e-1,
+ 3.1415925535897932e-2,
+ 3.1415925535897932e-3,
+ 3.1415925535897932e-4,
+ 3.1415925535897932e-5,
+ 3.1415925535897932e-6,
+ 3.1415925535897932e-7,
+ 3.1415925535897932e-8,
+ 3.1415925535897932e-9,
+ 3.1415925535897932e-10,
+ 3.1415925535897932e-11,
+ 3.1415925535897932e-12,
+ 3.1415925535897932e-13,
+ 3.1415925535897932e-14,
+ 3.1415925535897932e-15,
+};
+
+/*
+ * are the numbers close?
+ * used to compare long numbers where the last few digits are garbage
+ * due to precision problems
+ */
+static int
+numclose(char *num1, char *num2)
+{
+ int ndig;
+ double d1, d2;
+ enum { MAXDIG = 15 };
+
+ d1 = fmtstrtod(num1, 0);
+ d2 = fmtstrtod(num2, 0);
+ if(d1 != d2)
+ return 0;
+
+ ndig = 0;
+ while (*num1) {
+ if (*num1 >= '0' && *num1 <= '9') {
+ ndig++;
+ if (ndig > MAXDIG) {
+ if (!(*num2 >= '0' && *num2 <= '9')) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ } else if (*num1 == 'e' || *num1 == 'E') {
+ ndig = 0;
+ }
+ num1++;
+ num2++;
+ }
+ if (*num1 || !num2)
+ return 0;
+ return 1;
+}
+
+static void
+doit(int just, int plus, int alt, int zero, int width, int prec, int spec)
+{
+ char format[256];
+ char *p;
+ const char *s;
+ int i;
+
+ p = format;
+ *p++ = '%';
+ if (just > 0)
+ *p++ = "-"[just - 1];
+ if (plus > 0)
+ *p++ = "+ "[plus - 1];
+ if (alt > 0)
+ *p++ = "#"[alt - 1];
+ if (zero > 0)
+ *p++ = "0"[zero - 1];
+
+ s = "";
+ switch (width) {
+ case 1: s = "1"; break;
+ case 2: s = "5"; break;
+ case 3: s = "10"; break;
+ case 4: s = "15"; break;
+ }
+ strcpy(p, s);
+
+ s = "";
+ switch (prec) {
+ case 1: s = ".0"; break;
+ case 2: s = ".2"; break;
+ case 3: s = ".5"; break;
+ case 4: s = ".15"; break;
+ }
+ strcat(p, s);
+
+ p = strchr(p, '\0');
+ *p++ = "efgEG"[spec];
+ *p = '\0';
+
+ for (i = 0; i < sizeof(fmtvals) / sizeof(fmtvals[0]); i++) {
+ char ref[1024], buf[1024];
+ Rune rbuf[1024];
+ double d1, d2;
+
+ sprintf(ref, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), format, fmtvals[i]);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)",
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)");
+ // exits("oops");
+ }
+
+ /* Check again with output to rune string */
+ runesnprint(rbuf, 1024, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), "%S", rbuf);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)",
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)");
+ // exits("oops");
+ }
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ int just, plus, alt, zero, width, prec, spec;
+
+ for (just = 0; just < Njust; just++)
+ for (plus = 0; plus < Nplus; plus++)
+ for (alt = 0; alt < Nalt; alt++)
+ for (zero = 0; zero < Nzero; zero++)
+ for (width = 0; width < Nwidth; width++)
+ for (prec = 0; prec < Nprec; prec++)
+ for (spec = 0; spec < Nspec; spec++)
+ doit(just, plus, alt, zero, width, prec, spec);
+
+ exits(0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/testfmt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/testfmt.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,148 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+int failed;
+
+/* Consume argument and ignore it */
+int
+Zflag(Fmt* f)
+{
+ if(va_arg(f->args, int))
+ ;
+ return 1; /* it's a flag */
+}
+
+void
+verify(char *s, char *t)
+{
+ if(strcmp(s, t) != 0){
+ failed = 1;
+ fprintf(stderr, "error: (%s) != (%s)\n", s, t);
+ }
+ free(s);
+}
+
+Rune lightsmiley = 0x263a;
+Rune darksmiley = 0x263b;
+
+/* Test printer that loads unusual decimal point and separator */
+char*
+mysmprint(char *fmt, ...)
+{
+ Fmt f;
+
+ if(fmtstrinit(&f) < 0)
+ return 0;
+ va_start(f.args, fmt);
+ f.decimal = smprint("%C", lightsmiley);
+ f.thousands = smprint("%C", darksmiley);
+ f.grouping = "\1\2\3\4";
+ if(dofmt(&f, fmt) < 0)
+ return 0;
+ va_end(f.args);
+ return fmtstrflush(&f);
+}
+
+double near1[] = {
+ 0.5,
+ 0.95,
+ 0.995,
+ 0.9995,
+ 0.99995,
+ 0.999995,
+ 0.9999995,
+ 0.99999995,
+ 0.999999995,
+};
+
+void
+main(int argc, char **argv)
+{
+ int i, j;
+
+ quotefmtinstall();
+ fmtinstall('Z', Zflag);
+ fmtinstall(L'\x263a', Zflag);
+#ifdef PLAN9PORT
+{ extern int __ifmt(Fmt*);
+ fmtinstall('i', __ifmt);
+}
+#endif
+
+ verify(smprint("hello world"), "hello world");
+#ifdef PLAN9PORT
+ verify(smprint("x: %ux", 0x87654321), "x: 87654321");
+#else
+ verify(smprint("x: %x", 0x87654321), "x: 87654321");
+#endif
+ verify(smprint("d: %d", 0x87654321), "d: -2023406815");
+ verify(smprint("s: %s", "hi there"), "s: hi there");
+ verify(smprint("q: %q", "hi i'm here"), "q: 'hi i''m here'");
+ verify(smprint("c: %c", '!'), "c: !");
+ verify(smprint("g: %g %g %g", 3.14159, 3.14159e10, 3.14159e-10), "g: 3.14159 3.14159e+10 3.14159e-10");
+ verify(smprint("e: %e %e %e", 3.14159, 3.14159e10, 3.14159e-10), "e: 3.141590e+00 3.141590e+10 3.141590e-10");
+ verify(smprint("f: %f %f %f", 3.14159, 3.14159e10, 3.14159e-10), "f: 3.141590 31415900000.000000 0.000000");
+ verify(smprint("smiley: %C", (Rune)0x263a), "smiley: \xe2\x98\xba");
+ verify(smprint("%g %.18g", 2e25, 2e25), "2e+25 2e+25");
+ verify(smprint("%2.18g", 1.0), " 1");
+ verify(smprint("%f", 3.1415927/4), "0.785398");
+ verify(smprint("%d", 23), "23");
+ verify(smprint("%i", 23), "23");
+ verify(smprint("%Zi", 1234, 23), "23");
+
+ /* ANSI and their wacky corner cases */
+ verify(smprint("%.0d", 0), "");
+ verify(smprint("%.0o", 0), "");
+ verify(smprint("%.0x", 0), "");
+ verify(smprint("%#.0o", 0), "0");
+ verify(smprint("%#.0x", 0), "");
+
+ /* difficult floating point tests that many libraries get wrong */
+ verify(smprint("%.100f", 1.0), "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ verify(smprint("%.100g", 1.0), "1");
+ verify(smprint("%0100f", 1.0), "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000");
+ for(i=1; i<9; i++)
+ for(j=0; j<=i; j++)
+ verify(smprint("%.*g", j, near1[i]), "1");
+
+ /* test $ reorderings */
+ verify(smprint("%3$d %4$06d %2$d %1$d", 444, 333, 111, 222), "111 000222 333 444");
+ verify(smprint("%3$Zd %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444");
+ verify(smprint("%3$d %4$*5$06d %2$d %1$d", 444, 333, 111, 222, 20), "111 000222 333 444");
+ verify(smprint("%3$hd %4$*5$06d %2$d %1$d", 444, 333, (short)111, 222, 20), "111 000222 333 444");
+ verify(smprint("%3$\xe2\x98\xba""d %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444");
+
+ /* test %'d formats */
+ verify(smprint("%'d %'d %'d", 1, 2222, 33333333), "1 2,222 33,333,333");
+ verify(smprint("%'019d", 0), "000,000,000,000,000");
+ verify(smprint("%'08d %'08d %'08d", 1, 2222, 33333333), "0,000,001 0,002,222 33,333,333");
+#ifdef PLAN9PORT
+ verify(smprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#else
+ verify(smprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#endif
+ verify(smprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222,222,222 3,333,333,333,333");
+ verify(smprint("%'019lld %'019lld %'019lld", 1LL, 222222222LL, 3333333333333LL), "000,000,000,000,001 000,000,222,222,222 003,333,333,333,333");
+#ifdef PLAN9PORT
+ verify(smprint("%'llux %'lluX %'llub", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+#else
+ verify(smprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+#endif
+
+ /* test %'d with custom (utf-8!) separators */
+ /* x and b still use : */
+ verify(mysmprint("%'d %'d %'d", 1, 2222, 33333333), "1 2\xe2\x98\xbb""22\xe2\x98\xbb""2 33\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3");
+#ifdef PLAN9PORT
+ verify(mysmprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#else
+ verify(mysmprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#endif
+ verify(mysmprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222\xe2\x98\xbb""222\xe2\x98\xbb""22\xe2\x98\xbb""2 333\xe2\x98\xbb""3333\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3");
+ verify(mysmprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+ verify(mysmprint("%.4f", 3.14159), "3\xe2\x98\xba""1416");
+
+ if(failed)
+ sysfatal("tests failed");
+ exits(0);
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/testprint.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/testprint.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,14 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(int argc, char **argv)
+{
+ char c;
+
+ c = argv[1][strlen(argv[1])-1];
+ if(c == 'f' || c == 'e' || c == 'g' || c == 'F' || c == 'E' || c == 'G')
+ print(argv[1], atof(argv[2]));
+ else if(c == 'x' || c == 'u' || c == 'd' || c == 'c' || c == 'C' || c == 'X')
+ print(argv[1], atoi(argv[2]));
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/tm2sec.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/tm2sec.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+
+#include "zoneinfo.h"
+
+#define SEC2MIN 60L
+#define SEC2HOUR (60L*SEC2MIN)
+#define SEC2DAY (24L*SEC2HOUR)
+
+/*
+ * days per month plus days/year
+ */
+static int dmsize[] =
+{
+ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+static int ldmsize[] =
+{
+ 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * return the days/month for the given year
+ */
+static int *
+yrsize(int y)
+{
+ if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
+ return ldmsize;
+ else
+ return dmsize;
+}
+
+/*
+ * compute seconds since Jan 1 1970 GMT
+ * and convert to our timezone.
+ */
+long
+tm2sec(Tm *tm)
+{
+ Tinfo ti0, ti1, *ti;
+ long secs;
+ int i, yday, year, *d2m;
+
+ secs = 0;
+
+ /*
+ * seconds per year
+ */
+ year = tm->year + 1900;
+ for(i = 1970; i < year; i++){
+ d2m = yrsize(i);
+ secs += d2m[0] * SEC2DAY;
+ }
+
+ /*
+ * if mday is set, use mon and mday to compute yday
+ */
+ if(tm->mday){
+ yday = 0;
+ d2m = yrsize(year);
+ for(i=0; i<tm->mon; i++)
+ yday += d2m[i+1];
+ yday += tm->mday-1;
+ }else{
+ yday = tm->yday;
+ }
+ secs += yday * SEC2DAY;
+
+ /*
+ * hours, minutes, seconds
+ */
+ secs += tm->hour * SEC2HOUR;
+ secs += tm->min * SEC2MIN;
+ secs += tm->sec;
+
+ /*
+ * Assume the local time zone if zone is not GMT
+ */
+ if(strcmp(tm->zone, "GMT") != 0) {
+ i = zonelookuptinfo(&ti0, secs);
+ ti = &ti0;
+ if (i != -1)
+ if (ti->tzoff!=0) {
+ /*
+ * to what local time period `secs' belongs?
+ */
+ if (ti->tzoff>0) {
+ /*
+ * east of GMT; check previous local time transition
+ */
+ if (ti->t+ti->tzoff > secs)
+ if (zonetinfo(&ti1, i-1)!=-1)
+ ti = &ti1;
+ } else
+ /*
+ * west of GMT; check next local time transition
+ */
+ if (zonetinfo(&ti1, i+1))
+ if (ti1.t+ti->tzoff < secs)
+ ti = &ti1;
+// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff, (long)secs);
+ secs -= ti->tzoff;
+ }
+ }
+
+ if(secs < 0)
+ secs = 0;
+ return secs;
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/truerand.c
--- a/lib9/truerand.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/truerand.c Fri Jul 31 21:02:58 2009 +0100
@@ -15,7 +15,7 @@
                 if(randfd < 0 || read(randfd, buf, 1) != 1)
                         randfd = open(randfile="/dev/srandom", OREAD); /* OpenBSD */
                 if(randfd < 0)
- sysfatal("can't open /dev/random: %r");
+ sysfatal("can't open %s: %r", randfile);
                 fcntl(randfd, F_SETFD, FD_CLOEXEC);
         }
         for(i=0; i<sizeof(buf); i += n)
diff -r bb17f966e24a -r 1161d90df941 lib9/u.h
--- a/lib9/u.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/u.h Fri Jul 31 21:02:58 2009 +0100
@@ -7,9 +7,10 @@
 #define __BSD_VISIBLE 1 /* FreeBSD 5.x */
 #if defined(__sun__)
 # define __EXTENSIONS__ 1 /* SunOS */
-# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__)
+# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)
                 /* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
 # else
+ /* What's left? */
 # define __MAKECONTEXT_V2_SOURCE 1
 # endif
 #endif
@@ -19,6 +20,17 @@
 #if !defined(__APPLE__) && !defined(__OpenBSD__)
 # define _XOPEN_SOURCE 1000
 # define _XOPEN_SOURCE_EXTENDED 1
+#endif
+#if defined(__FreeBSD__)
+# include <sys/cdefs.h>
+ /* for strtoll */
+# undef __ISO_C_VISIBLE
+# define __ISO_C_VISIBLE 1999
+# undef __LONG_LONG_SUPPORTED
+# define __LONG_LONG_SUPPORTED
+#endif
+#if defined(__AIX__)
+# define _XOPEN_SOURCE 1
 #endif
 #define _LARGEFILE64_SOURCE 1
 #define _FILE_OFFSET_BITS 64
@@ -33,8 +45,6 @@
 #include <assert.h>
 #include <setjmp.h>
 #include <stddef.h>
-#include <utf.h>
-#include <fmt.h>
 #include <math.h>
 #include <ctype.h> /* for tolower */
 
@@ -138,6 +148,7 @@
 typedef uint16_t u16int;
 typedef int16_t s16int;
 typedef uintptr_t uintptr;
+typedef intptr_t intptr;
 typedef uint32_t u32int;
 typedef int32_t s32int;
 
@@ -150,17 +161,23 @@
  * Funny-named symbols to tip off 9l to autolink.
  */
 #define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
+#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
 
 /*
  * Gcc is too smart for its own good.
  */
 #if defined(__GNUC__)
+# undef strcmp /* causes way too many warnings */
 # if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__))
 # undef AUTOLIB
 # define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
 # else
 # undef AUTOLIB
 # define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
 # endif
 #endif
 
diff -r bb17f966e24a -r 1161d90df941 lib9/utf.h
--- a/lib9/utf.h Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/utf.h Fri Jul 31 21:02:58 2009 +0100
@@ -11,7 +11,7 @@
         UTFmax = 3, /* 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 */
+ Runeerror = 0xFFFD /* decoding error in UTF */
 };
 
 /* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
diff -r bb17f966e24a -r 1161d90df941 lib9/utf/NOTICE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/utf/NOTICE Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff -r bb17f966e24a -r 1161d90df941 lib9/utf/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/utf/README Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff -r bb17f966e24a -r 1161d90df941 lib9/utf/lib9.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/utf/lib9.h Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,17 @@
+#include <string.h>
+#include "utf.h"
+
+#define nil ((void*)0)
+
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
diff -r bb17f966e24a -r 1161d90df941 lib9/utf/rune.c
--- a/lib9/utf/rune.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/utf/rune.c Fri Jul 31 21:02:58 2009 +0100
@@ -37,7 +37,7 @@
         Maskx = (1<<Bitx)-1, /* 0011 1111 */
         Testx = Maskx ^ 0xFF, /* 1100 0000 */
 
- Bad = Runeerror,
+ Bad = Runeerror
 };
 
 int
diff -r bb17f966e24a -r 1161d90df941 lib9/utf/utfecpy.c
--- a/lib9/utf/utfecpy.c Thu Feb 09 13:39:50 2006 +0100
+++ b/lib9/utf/utfecpy.c Fri Jul 31 21:02:58 2009 +0100
@@ -11,6 +11,7 @@
  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  */
+#define _BSD_SOURCE 1 /* memccpy */
 #include <stdarg.h>
 #include <string.h>
 #include "plan9.h"
diff -r bb17f966e24a -r 1161d90df941 lib9/write.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/write.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,23 @@
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+long
+p9write(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = write(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/zoneinfo.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/zoneinfo.c Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,215 @@
+#include <u.h>
+#include <libc.h>
+
+/*
+ * Access local time entries of zoneinfo files.
+ * Formats 0 and 2 are supported, and 4-byte timestamps
+ *
+ * Copyright © 2008 M. Teichgräber
+ * Contributed under the terms of the Lucent Public License 1.02.
+ */
+#include "zoneinfo.h"
+
+static
+struct Zoneinfo
+{
+ int timecnt; /* # of transition times */
+ int typecnt; /* # of local time types */
+ int charcnt; /* # of characters of time zone abbreviation strings */
+
+ uchar *ptime;
+ uchar *ptype;
+ uchar *ptt;
+ uchar *pzone;
+} z;
+
+static uchar *tzdata;
+
+static
+uchar*
+readtzfile(char *file)
+{
+ uchar *p;
+ int fd;
+ Dir *d;
+
+ fd = open(file, OREAD);
+ if (fd<0)
+ return nil;
+ d = dirfstat(fd);
+ if (d==nil)
+ return nil;
+ p = malloc(d->length);
+ if (p!=nil)
+ readn(fd, p, d->length);
+ free(d);
+ close(fd);
+ return p;
+}
+static char *zonefile;
+void
+tzfile(char *f)
+{
+ if (tzdata!=nil) {
+ free(tzdata);
+ tzdata = nil;
+ }
+ z.timecnt = 0;
+ zonefile = f;
+}
+
+static
+long
+get4(uchar *p)
+{
+ return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
+}
+
+enum {
+ TTinfosz = 4+1+1,
+};
+
+static
+int
+parsehead(void)
+{
+ uchar *p;
+ int ver;
+
+ ver = tzdata[4];
+ if (ver!=0)
+ if (ver!='2')
+ return -1;
+
+ p = tzdata + 4 + 1 + 15;
+
+ z.timecnt = get4(p+3*4);
+ z.typecnt = get4(p+4*4);
+ if (z.typecnt==0)
+ return -1;
+ z.charcnt = get4(p+5*4);
+ z.ptime = p+6*4;
+ z.ptype = z.ptime + z.timecnt*4;
+ z.ptt = z.ptype + z.timecnt;
+ z.pzone = z.ptt + z.typecnt*TTinfosz;
+ return 0;
+}
+
+static
+void
+ttinfo(Tinfo *ti, int tti)
+{
+ uchar *p;
+ int i;
+
+ i = z.ptype[tti];
+ assert(i<z.typecnt);
+ p = z.ptt + i*TTinfosz;
+ ti->tzoff = get4(p);
+ ti->dlflag = p[4];
+ assert(p[5]<z.charcnt);
+ ti->zone = (char*)z.pzone + p[5];
+}
+
+static
+void
+readtimezone(void)
+{
+ char *tmp;
+
+ z.timecnt = 0;
+ switch (zonefile==nil) {
+ default:
+ if ((tmp=getenv("timezone"))!=nil) {
+ tzdata = readtzfile(tmp);
+ free(tmp);
+ break;
+ }
+ zonefile = "/etc/localtime";
+ /* fall through */
+ case 0:
+ tzdata = readtzfile(zonefile);
+ }
+ if (tzdata==nil)
+ return;
+
+ if (strncmp("TZif", (char*)tzdata, 4)!=0)
+ goto errfree;
+
+ if (parsehead()==-1) {
+ errfree:
+ free(tzdata);
+ tzdata = nil;
+ z.timecnt = 0;
+ return;
+ }
+}
+
+static
+tlong
+gett4(uchar *p)
+{
+ long l;
+
+ l = get4(p);
+ if (l<0)
+ return 0;
+ return l;
+}
+int
+zonetinfo(Tinfo *ti, int i)
+{
+ if (tzdata==nil)
+ readtimezone();
+ if (i<0 || i>=z.timecnt)
+ return -1;
+ ti->t = gett4(z.ptime + 4*i);
+ ttinfo(ti, i);
+ return i;
+}
+
+int
+zonelookuptinfo(Tinfo *ti, tlong t)
+{
+ uchar *p;
+ int i;
+ tlong oldtt, tt;
+
+ if (tzdata==nil)
+ readtimezone();
+ oldtt = 0;
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ tt = gett4(p);
+ if (t<tt)
+ break;
+ oldtt = tt;
+ p += 4;
+ }
+ if (i>0) {
+ ttinfo(ti, i-1);
+ ti->t = oldtt;
+// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
+ return i-1;
+ }
+ return -1;
+}
+
+void
+zonedump(int fd)
+{
+ int i;
+ uchar *p;
+ tlong t;
+ Tinfo ti;
+
+ if (tzdata==nil)
+ readtimezone();
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ t = gett4(p);
+ ttinfo(&ti, i);
+ fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
+ p += 4;
+ }
+}
diff -r bb17f966e24a -r 1161d90df941 lib9/zoneinfo.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib9/zoneinfo.h Fri Jul 31 21:02:58 2009 +0100
@@ -0,0 +1,19 @@
+#define zonetinfo _p9zonetinfo
+#define zonedump _p9zonedump
+#define zonelookuptinfo _p9zonelookuptinfo
+
+typedef long tlong;
+
+typedef
+struct Tinfo
+{
+ long t;
+ int tzoff;
+ int dlflag;
+ char *zone;
+} Tinfo;
+
+extern int zonelookuptinfo(Tinfo*, tlong);
+extern int zonetinfo(Tinfo*, int);
+extern void zonedump(int fd);
+
diff -r bb17f966e24a -r 1161d90df941 ls/ls.c
--- a/ls/ls.c Thu Feb 09 13:39:50 2006 +0100
+++ b/ls/ls.c Fri Jul 31 21:02:58 2009 +0100
@@ -227,17 +227,16 @@
                         db->qid.type);
         if(lflag)
                 Bprint(&bin,
- Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*ud %*s %s %*llud %s %q\n",
+ "%M %C %*ud %*s %s %*llud %s ",
                         db->mode, db->type,
                         vwidth, db->dev,
                         -uwidth, db->uid,
                         db->gid,
                         (int)(glwidth-strlen(db->gid)), db->length,
- asciitime(uflag? db->atime : db->mtime), name);
- else
- Bprint(&bin,
- Qflag? "%s%s\n" : "%q%s\n",
- name, fileflag(db));
+ asciitime(uflag? db->atime : db->mtime));
+ Bprint(&bin,
+ Qflag? "%s%s\n" : "%q%s\n",
+ name, fileflag(db));
 }
 
 void
diff -r bb17f966e24a -r 1161d90df941 mk/Makefile
--- a/mk/Makefile Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-# basename - basename unix port from plan9
-# Depends on ../lib9
-
-TARG = mk
-OFILES = arc.o archive.o bufblock.o env.o file.o graph.o job.o\
- lex.o main.o match.o mk.o parse.o recipe.o rc.o rule.o\
- run.o sh.o shell.o shprint.o symtab.o var.o varsub.o\
- word.o unix.o
-MANFILES = ${TARG}.1
-
-include ../config.mk
-
-all: ${TARG}
- @echo built ${TARG}
-
-install: ${TARG}
- @mkdir -p ${DESTDIR}${PREFIX}/bin
- @cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
- @chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
- @mkdir -p ${DESTDIR}${MANPREFIX}/man1
- @cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
- @chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
-
-uninstall:
- rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
- rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
-
-.c.o:
- @echo CC $*.c
- @${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
-
-clean:
- rm -f ${OFILES} ${TARG}
-
-${TARG}: ${OFILES}
- @echo LD ${TARG}
- @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
diff -r bb17f966e24a -r 1161d90df941 mk/NOTICE
--- a/mk/NOTICE Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-Portions Copyright © 1995-1997 C H Forsyth (forsyth_AT_caldo.demon.co.uk). All rights reserved.
-Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved.
-Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-
-Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000,
-Vita Nuova Holdings Limited has the right to determine (within a specified scope)
-the form and content of sublicences for this software.
-
-Vita Nuova Holdings Limited now makes this software available as Free
-Software under the terms of the `GNU General Public LIcense, Version 2'
-(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for
-the full terms and conditions). One of the conditions of that licence
-is that you must keep intact all notices that refer to that licence and to the absence of
-of any warranty: for this software, note that includes this NOTICE file in particular.
-
-This suite of programs 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.
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices above.
diff -r bb17f966e24a -r 1161d90df941 mk/README
--- a/mk/README Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-This is a Unix port of mk,
-originally done for the Inferno operating system.
-
-Russ Cox repackaged this to build as a standalone
-Unix program. Send comments about packaging to
-Russ Cox <rsc_AT_post.harvard.edu>
-
diff -r bb17f966e24a -r 1161d90df941 mk/arc.c
--- a/mk/arc.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-#include "mk.h"
-
-Arc *
-newarc(Node *n, Rule *r, char *stem, Resub *match)
-{
- Arc *a;
-
- a = (Arc *)Malloc(sizeof(Arc));
- a->n = n;
- a->r = r;
- a->stem = strdup(stem);
- rcopy(a->match, match, NREGEXP);
- a->next = 0;
- a->flag = 0;
- a->prog = r->prog;
- return(a);
-}
-
-void
-dumpa(char *s, Arc *a)
-{
- char buf[1024];
-
- Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'",
- s, a, a->n, a->r, a->flag, a->stem);
- if(a->prog)
- Bprint(&bout, " prog='%s'", a->prog);
- Bprint(&bout, "\n");
-
- if(a->n){
- snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:"");
- dumpn(buf, a->n);
- }
-}
-
-void
-nrep(void)
-{
- Symtab *sym;
- Word *w;
-
- sym = symlook("NREP", S_VAR, 0);
- if(sym){
- w = (Word *) sym->value;
- if (w && w->s && *w->s)
- nreps = atoi(w->s);
- }
- if(nreps < 1)
- nreps = 1;
- if(DEBUG(D_GRAPH))
- Bprint(&bout, "nreps = %d\n", nreps);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/archive.c
--- a/mk/archive.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-#include "mk.h"
-#define ARMAG "!<arch>\n"
-#define SARMAG 8
-
-#define ARFMAG "`\n"
-#define SARNAME 16
-
-struct ar_hdr
-{
- char name[SARNAME];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char fmag[2];
-};
-#define SAR_HDR (SARNAME+44)
-
-static int dolong = 1;
-
-static void atimes(char *);
-static char *split(char*, char**);
-
-long
-readn(int f, void *av, long n)
-{
- char *a;
- long m, t;
-
- a = av;
- t = 0;
- while(t < n){
- m = read(f, a+t, n-t);
- if(m <= 0){
- if(t == 0)
- return m;
- break;
- }
- t += m;
- }
- return t;
-}
-long
-atimeof(int force, char *name)
-{
- Symtab *sym;
- long t;
- char *archive, *member, buf[512];
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- t = mtime(archive);
- sym = symlook(archive, S_AGG, 0);
- if(sym){
- if(force || (t > (long)sym->value)){
- atimes(archive);
- sym->value = (void *)t;
- }
- }
- else{
- atimes(archive);
- /* mark the aggegate as having been done */
- symlook(strdup(archive), S_AGG, "")->value = (void *)t;
- }
- /* truncate long member name to sizeof of name field in archive header */
- if(dolong)
- snprint(buf, sizeof(buf), "%s(%s)", archive, member);
- else
- snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
- sym = symlook(buf, S_TIME, 0);
- if (sym)
- return (long)sym->value; /* uggh */
- return 0;
-}
-
-void
-atouch(char *name)
-{
- char *archive, *member;
- int fd, i;
- struct ar_hdr h;
- long t;
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- fd = open(archive, ORDWR);
- if(fd < 0){
- fd = create(archive, OWRITE, 0666);
- if(fd < 0){
- fprint(2, "create %s: %r\n", archive);
- Exit();
- }
- write(fd, ARMAG, SARMAG);
- }
- if(symlook(name, S_TIME, 0)){
- /* hoon off and change it in situ */
- LSEEK(fd, SARMAG, 0);
- while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
- ;
- h.name[i+1]=0;
- if(strcmp(member, h.name) == 0){
- t = SARNAME-sizeof(h); /* ughgghh */
- LSEEK(fd, t, 1);
- fprint(fd, "%-12ld", time(0));
- break;
- }
- t = atol(h.size);
- if(t&01) t++;
- LSEEK(fd, t, 1);
- }
- }
- close(fd);
-}
-
-static void
-atimes(char *ar)
-{
- struct ar_hdr h;
- long t;
- int fd, i, namelen;
- char buf[2048], *p, *strings;
- char name[1024];
- Symtab *sym;
-
- strings = nil;
- fd = open(ar, OREAD);
- if(fd < 0)
- return;
-
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return;
- }
- while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- t = atol(h.date);
- if(t == 0) /* as it sometimes happens; thanks ken */
- t = 1;
- namelen = 0;
- if(memcmp(h.name, "#1/", 3) == 0){ /* BSD */
- namelen = atoi(h.name+3);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- if(readn(fd, name, namelen) != namelen)
- break;
- name[namelen] = 0;
- }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
- /* date, uid, gid, mode all ' ' */
- for(i=2; i<16+12+6+6+8; i++)
- if(h.name[i] != ' ')
- goto skip;
- t = atol(h.size);
- if(t&01)
- t++;
- free(strings);
- strings = malloc(t+1);
- if(strings){
- if(readn(fd, strings, t) != t){
- free(strings);
- strings = nil;
- break;
- }
- strings[t] = 0;
- continue;
- }
- goto skip;
- }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){
- i = strtol(h.name+1, &p, 10);
- if(*p != ' ' || i >= strlen(strings))
- goto skip;
- p = strings+i;
- for(; *p && *p != '/'; p++)
- ;
- namelen = p-(strings+i);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- memmove(name, strings+i, namelen);
- name[namelen] = 0;
- namelen = 0;
- }else{
- strncpy(name, h.name, sizeof(h.name));
- for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
- ;
- if(name[i] == '/') /* system V bug */
- i--;
- name[i+1]=0;
- }
- snprint(buf, sizeof buf, "%s(%s)", ar, name);
- sym = symlook(strdup(buf), S_TIME, (void *)t);
- sym->value = (void *)t;
- skip:
- t = atol(h.size);
- if(t&01) t++;
- t -= namelen;
- LSEEK(fd, t, 1);
- }
- close(fd);
- free(strings);
-}
-
-static int
-type(char *file)
-{
- int fd;
- char buf[SARMAG];
-
- fd = open(file, OREAD);
- if(fd < 0){
- if(symlook(file, S_BITCH, 0) == 0){
- if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0)
- Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
- symlook(file, S_BITCH, (void *)file);
- }
- return 1;
- }
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return 0;
- }
- close(fd);
- return !strncmp(ARMAG, buf, SARMAG);
-}
-
-static char*
-split(char *name, char **member)
-{
- char *p, *q;
-
- p = strdup(name);
- q = utfrune(p, '(');
- if(q){
- *q++ = 0;
- if(member)
- *member = q;
- q = utfrune(q, ')');
- if (q)
- *q = 0;
- if(type(p))
- return p;
- free(p);
- fprint(2, "mk: '%s' is not an archive\n", name);
- }
- return 0;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/bufblock.c
--- a/mk/bufblock.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-#include "mk.h"
-
-static Bufblock *freelist;
-#define QUANTA 4096
-
-Bufblock *
-newbuf(void)
-{
- Bufblock *p;
-
- if (freelist) {
- p = freelist;
- freelist = freelist->next;
- } else {
- p = (Bufblock *) Malloc(sizeof(Bufblock));
- p->start = Malloc(QUANTA*sizeof(*p->start));
- p->end = p->start+QUANTA;
- }
- p->current = p->start;
- *p->start = 0;
- p->next = 0;
- return p;
-}
-
-void
-freebuf(Bufblock *p)
-{
- p->next = freelist;
- freelist = p;
-}
-
-void
-growbuf(Bufblock *p)
-{
- int n;
- Bufblock *f;
- char *cp;
-
- n = p->end-p->start+QUANTA;
- /* search the free list for a big buffer */
- for (f = freelist; f; f = f->next) {
- if (f->end-f->start >= n) {
- memcpy(f->start, p->start, p->end-p->start);
- cp = f->start;
- f->start = p->start;
- p->start = cp;
- cp = f->end;
- f->end = p->end;
- p->end = cp;
- f->current = f->start;
- break;
- }
- }
- if (!f) { /* not found - grow it */
- p->start = Realloc(p->start, n);
- p->end = p->start+n;
- }
- p->current = p->start+n-QUANTA;
-}
-
-void
-bufcpy(Bufblock *buf, char *cp, int n)
-{
-
- while (n--)
- insert(buf, *cp++);
-}
-
-void
-insert(Bufblock *buf, int c)
-{
-
- if (buf->current >= buf->end)
- growbuf(buf);
- *buf->current++ = c;
-}
-
-void
-rinsert(Bufblock *buf, Rune r)
-{
- int n;
-
- n = runelen(r);
- if (buf->current+n > buf->end)
- growbuf(buf);
- runetochar(buf->current, &r);
- buf->current += n;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/env.c
--- a/mk/env.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-#include "mk.h"
-
-enum {
- ENVQUANTA=10
-};
-
-Envy *envy;
-static int nextv;
-
-static char *myenv[] =
-{
- "target",
- "stem",
- "prereq",
- "pid",
- "nproc",
- "newprereq",
- "alltarget",
- "newmember",
- "stem0", /* must be in order from here */
- "stem1",
- "stem2",
- "stem3",
- "stem4",
- "stem5",
- "stem6",
- "stem7",
- "stem8",
- "stem9",
- 0,
-};
-
-void
-initenv(void)
-{
- char **p;
-
- for(p = myenv; *p; p++)
- symlook(*p, S_INTERNAL, (void *)"");
- readenv(); /* o.s. dependent */
-}
-
-static void
-envinsert(char *name, Word *value)
-{
- static int envsize;
-
- if (nextv >= envsize) {
- envsize += ENVQUANTA;
- envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy));
- }
- envy[nextv].name = name;
- envy[nextv++].values = value;
-}
-
-static void
-envupd(char *name, Word *value)
-{
- Envy *e;
-
- for(e = envy; e->name; e++)
- if(strcmp(name, e->name) == 0){
- delword(e->values);
- e->values = value;
- return;
- }
- e->name = name;
- e->values = value;
- envinsert(0,0);
-}
-
-static void
-ecopy(Symtab *s)
-{
- char **p;
-
- if(symlook(s->name, S_NOEXPORT, 0))
- return;
- for(p = myenv; *p; p++)
- if(strcmp(*p, s->name) == 0)
- return;
- envinsert(s->name, (Word *) s->value);
-}
-
-void
-execinit(void)
-{
- char **p;
-
- nextv = 0;
- for(p = myenv; *p; p++)
- envinsert(*p, stow(""));
-
- symtraverse(S_VAR, ecopy);
- envinsert(0, 0);
-}
-
-Envy*
-buildenv(Job *j, int slot)
-{
- char **p, *cp, *qp;
- Word *w, *v, **l;
- int i;
- char buf[256];
-
- envupd("target", wdup(j->t));
- if(j->r->attr&REGEXP)
- envupd("stem",newword(""));
- else
- envupd("stem", newword(j->stem));
- envupd("prereq", wdup(j->p));
- sprint(buf, "%d", getpid());
- envupd("pid", newword(buf));
- sprint(buf, "%d", slot);
- envupd("nproc", newword(buf));
- envupd("newprereq", wdup(j->np));
- envupd("alltarget", wdup(j->at));
- l = &v;
- v = w = wdup(j->np);
- while(w){
- cp = strchr(w->s, '(');
- if(cp){
- qp = strchr(cp+1, ')');
- if(qp){
- *qp = 0;
- strcpy(w->s, cp+1);
- l = &w->next;
- w = w->next;
- continue;
- }
- }
- *l = w->next;
- free(w->s);
- free(w);
- w = *l;
- }
- envupd("newmember", v);
- /* update stem0 -> stem9 */
- for(p = myenv; *p; p++)
- if(strcmp(*p, "stem0") == 0)
- break;
- for(i = 0; *p; i++, p++){
- if((j->r->attr&REGEXP) && j->match[i])
- envupd(*p, newword(j->match[i]));
- else
- envupd(*p, newword(""));
- }
- return envy;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/file.c
--- a/mk/file.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-#include "mk.h"
-
-/* table-driven version in bootes dump of 12/31/96 */
-
-long
-mtime(char *name)
-{
- return mkmtime(name);
-}
-
-long
-timeof(char *name, int force)
-{
- Symtab *sym;
- long t;
-
- if(utfrune(name, '('))
- return atimeof(force, name); /* archive */
-
- if(force)
- return mtime(name);
-
-
- sym = symlook(name, S_TIME, 0);
- if (sym)
- return (long) sym->value; /* uggh */
-
- t = mtime(name);
- if(t == 0)
- return 0;
-
- symlook(name, S_TIME, (void*)t); /* install time in cache */
- return t;
-}
-
-void
-touch(char *name)
-{
- Bprint(&bout, "touch(%s)\n", name);
- if(nflag)
- return;
-
- if(utfrune(name, '('))
- atouch(name); /* archive */
- else if(chgtime(name) < 0) {
- fprint(2, "%s: %r\n", name);
- Exit();
- }
-}
-
-void
-delete(char *name)
-{
- if(utfrune(name, '(') == 0) { /* file */
- if(remove(name) < 0)
- fprint(2, "remove %s: %r\n", name);
- } else
- fprint(2, "hoon off; mk can'tdelete archive members\n");
-}
-
-void
-timeinit(char *s)
-{
- long t;
- char *cp;
- Rune r;
- int c, n;
-
- t = time(0);
- while (*s) {
- cp = s;
- do{
- n = chartorune(&r, s);
- if (r == ' ' || r == ',' || r == '\n')
- break;
- s += n;
- } while(*s);
- c = *s;
- *s = 0;
- symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t;
- if (c)
- *s++ = c;
- while(*s){
- n = chartorune(&r, s);
- if(r != ' ' && r != ',' && r != '\n')
- break;
- s += n;
- }
- }
-}
diff -r bb17f966e24a -r 1161d90df941 mk/fns.h
--- a/mk/fns.h Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-#undef waitfor
-#define waitfor mkwaitfor
-
-void addrule(char*, Word*, char*, Word*, int, int, char*);
-void addrules(Word*, Word*, char*, int, int, char*);
-void addw(Word*, char*);
-void assert(char*, int);
-int assline(Biobuf *, Bufblock *);
-long atimeof(int,char*);
-void atouch(char*);
-void bufcpy(Bufblock *, char *, int);
-Envy *buildenv(Job*, int);
-void catchnotes(void);
-int chgtime(char*);
-void clrmade(Node*);
-void delete(char*);
-void delword(Word*);
-int dorecipe(Node*);
-void dumpa(char*, Arc*);
-void dumpj(char*, Job*, int);
-void dumpn(char*, Node*);
-void dumpr(char*, Rule*);
-void dumpv(char*);
-void dumpw(char*, Word*);
-void execinit(void);
-int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*);
-void Exit(void);
-void expunge(int, char*);
-void freebuf(Bufblock*);
-void front(char*);
-Node *graph(char*);
-void growbuf(Bufblock *);
-void initenv(void);
-void initshell(void);
-void insert(Bufblock *, int);
-void ipop(void);
-void ipush(void);
-void killchildren(char*);
-void *Malloc(int);
-char *maketmp(int*);
-int match(char*, char*, char*, Shell*);
-char *membername(char*, int, char*);
-void mk(char*);
-unsigned long mkmtime(char*);
-long mtime(char*);
-Arc *newarc(Node*, Rule*, char*, Resub*);
-Bufblock *newbuf(void);
-Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*);
-Word *newword(char*);
-int nextrune(Biobuf*, int);
-int nextslot(void);
-void nproc(void);
-void nrep(void);
-int outofdate(Node*, Arc*, int);
-void parse(char*, int, int);
-int pipecmd(char*, Envy*, int*, Shell*, Word*);
-void popshell(void);
-void prusage(void);
-void pushshell(void);
-void rcopy(char**, Resub*, int);
-void readenv(void);
-void *Realloc(void*, int);
-void rinsert(Bufblock *, Rune);
-char *rulecnt(void);
-void run(Job*);
-char *setshell(Word*);
-void setvar(char*, void*);
-int shargv(Word*, int, char***);
-char *shname(char*);
-void shprint(char*, Envy*, Bufblock*, Shell*);
-Word *stow(char*);
-void subst(char*, char*, char*);
-void symdel(char*, int);
-void syminit(void);
-Symtab *symlook(char*, int, void*);
-void symstat(void);
-void symtraverse(int, void(*)(Symtab*));
-void timeinit(char*);
-long timeof(char*, int);
-void touch(char*);
-void update(int, Node*);
-void usage(void);
-Word *varsub(char**);
-int waitfor(char*);
-int waitup(int, int*);
-Word *wdup(Word*);
-int work(Node*, Node*, Arc*);
-char *wtos(Word*, int);
diff -r bb17f966e24a -r 1161d90df941 mk/graph.c
--- a/mk/graph.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,279 +0,0 @@
-#include "mk.h"
-
-static Node *applyrules(char *, char *);
-static void togo(Node *);
-static int vacuous(Node *);
-static Node *newnode(char *);
-static void trace(char *, Arc *);
-static void cyclechk(Node *);
-static void ambiguous(Node *);
-static void attribute(Node *);
-
-Node *
-graph(char *target)
-{
- Node *node;
- char *cnt;
-
- cnt = rulecnt();
- node = applyrules(target, cnt);
- free(cnt);
- cyclechk(node);
- node->flags |= PROBABLE; /* make sure it doesn't get deleted */
- vacuous(node);
- ambiguous(node);
- attribute(node);
- return(node);
-}
-
-static Node *
-applyrules(char *target, char *cnt)
-{
- Symtab *sym;
- Node *node;
- Rule *r;
- Arc head, *a = &head;
- Word *w;
- char stem[NAMEBLOCK], buf[NAMEBLOCK];
- Resub rmatch[NREGEXP];
-
-/* print("applyrules(%lux='%s')\n", target, target);*//**/
- sym = symlook(target, S_NODE, 0);
- if(sym)
- return (Node *)(sym->value);
- target = strdup(target);
- node = newnode(target);
- head.n = 0;
- head.next = 0;
- sym = symlook(target, S_TARGET, 0);
- memset((char*)rmatch, 0, sizeof(rmatch));
- for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){
- if(r->attr&META) continue;
- if(strcmp(target, r->target)) continue;
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
- node->flags |= PROBABLE;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, "", rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
- a = a->next;
- }
- cnt[r->rule]--;
- head.n = node;
- }
- for(r = metarules; r; r = r->next){
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
- if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
- continue;
- if(r->attr&REGEXP){
- stem[0] = 0;
- patrule = r;
- memset((char*)rmatch, 0, sizeof(rmatch));
- if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
- continue;
- } else {
- if(!match(node->name, r->target, stem, r->shellt)) continue;
- }
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
-
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, stem, rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- if(r->attr&REGEXP)
- regsub(w->s, buf, sizeof buf, rmatch, NREGEXP);
- else
- subst(stem, w->s, buf);
- a->next = newarc(applyrules(buf, cnt), r, stem, rmatch);
- a = a->next;
- }
- cnt[r->rule]--;
- }
- a->next = node->prereqs;
- node->prereqs = head.next;
- return(node);
-}
-
-static void
-togo(Node *node)
-{
- Arc *la, *a;
-
- /* delete them now */
- la = 0;
- for(a = node->prereqs; a; la = a, a = a->next)
- if(a->flag&TOGO){
- if(a == node->prereqs)
- node->prereqs = a->next;
- else
- la->next = a->next, a = la;
- }
-}
-
-static int
-vacuous(Node *node)
-{
- Arc *la, *a;
- int vac = !(node->flags&PROBABLE);
-
- if(node->flags&READY)
- return(node->flags&VACUOUS);
- node->flags |= READY;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && vacuous(a->n) && (a->r->attr&META))
- a->flag |= TOGO;
- else
- vac = 0;
- /* if a rule generated arcs that DON'T go; no others from that rule go */
- for(a = node->prereqs; a; a = a->next)
- if((a->flag&TOGO) == 0)
- for(la = node->prereqs; la; la = la->next)
- if((la->flag&TOGO) && (la->r == a->r)){
- la->flag &= ~TOGO;
- }
- togo(node);
- if(vac)
- node->flags |= VACUOUS;
- return(vac);
-}
-
-static Node *
-newnode(char *name)
-{
- register Node *node;
-
- node = (Node *)Malloc(sizeof(Node));
- symlook(name, S_NODE, (void *)node);
- node->name = name;
- node->time = timeof(name, 0);
- node->prereqs = 0;
- node->flags = node->time? PROBABLE : 0;
- node->next = 0;
- return(node);
-}
-
-void
-dumpn(char *s, Node *n)
-{
- char buf[1024];
- Arc *a;
-
- snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:"");
- Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n",
- s, n->name, n, n->time, n->flags, n->next);
- for(a = n->prereqs; a; a = a->next)
- dumpa(buf, a);
-}
-
-static void
-trace(char *s, Arc *a)
-{
- fprint(2, "\t%s", s);
- while(a){
- fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
- a->n? a->n->name:"");
- if(a->n){
- for(a = a->n->prereqs; a; a = a->next)
- if(*a->r->recipe) break;
- } else
- a = 0;
- }
- fprint(2, "\n");
-}
-
-static void
-cyclechk(Node *n)
-{
- Arc *a;
-
- if((n->flags&CYCLE) && n->prereqs){
- fprint(2, "mk: cycle in graph detected at target %s\n", n->name);
- Exit();
- }
- n->flags |= CYCLE;
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- cyclechk(a->n);
- n->flags &= ~CYCLE;
-}
-
-static void
-ambiguous(Node *n)
-{
- Arc *a;
- Rule *r = 0;
- Arc *la;
- int bad = 0;
-
- la = 0;
- for(a = n->prereqs; a; a = a->next){
- if(a->n)
- ambiguous(a->n);
- if(*a->r->recipe == 0) continue;
- if(r == 0)
- r = a->r, la = a;
- else{
- if(r->recipe != a->r->recipe){
- if((r->attr&META) && !(a->r->attr&META)){
- la->flag |= TOGO;
- r = a->r, la = a;
- } else if(!(r->attr&META) && (a->r->attr&META)){
- a->flag |= TOGO;
- continue;
- }
- }
- if(r->recipe != a->r->recipe){
- if(bad == 0){
- fprint(2, "mk: ambiguous recipes for %s:\n", n->name);
- bad = 1;
- trace(n->name, la);
- }
- trace(n->name, a);
- }
- }
- }
- if(bad)
- Exit();
- togo(n);
-}
-
-static void
-attribute(Node *n)
-{
- register Arc *a;
-
- for(a = n->prereqs; a; a = a->next){
- if(a->r->attr&VIR)
- n->flags |= VIRTUAL;
- if(a->r->attr&NOREC)
- n->flags |= NORECIPE;
- if(a->r->attr&DEL)
- n->flags |= DELETE;
- if(a->n)
- attribute(a->n);
- }
- if(n->flags&VIRTUAL)
- n->time = 0;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/job.c
--- a/mk/job.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#include "mk.h"
-
-Job *
-newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar)
-{
- register Job *j;
-
- j = (Job *)Malloc(sizeof(Job));
- j->r = r;
- j->n = nlist;
- j->stem = stem;
- j->match = match;
- j->p = pre;
- j->np = npre;
- j->t = tar;
- j->at = atar;
- j->nproc = -1;
- j->next = 0;
- return(j);
-}
-
-void
-dumpj(char *s, Job *j, int all)
-{
- Bprint(&bout, "%s\n", s);
- while(j){
- Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n",
- j, j->r, j->n, j->stem, j->nproc);
- Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n",
- wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' '));
- j = all? j->next : 0;
- }
-}
diff -r bb17f966e24a -r 1161d90df941 mk/lex.c
--- a/mk/lex.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-#include "mk.h"
-
-static int bquote(Biobuf*, Bufblock*);
-
-/*
- * Assemble a line skipping blank lines, comments, and eliding
- * escaped newlines
- */
-int
-assline(Biobuf *bp, Bufblock *buf)
-{
- int c;
- int lastc;
-
- buf->current=buf->start;
- while ((c = nextrune(bp, 1)) >= 0){
- switch(c)
- {
- case '\r': /* consumes CRs for Win95 */
- continue;
- case '\n':
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break; /* skip empty lines */
- case '\\':
- case '\'':
- case '"':
- rinsert(buf, c);
- if (shellt->escapetoken(bp, buf, 1, c) == 0)
- Exit();
- break;
- case '`':
- if (bquote(bp, buf) == 0)
- Exit();
- break;
- case '#':
- lastc = '#';
- while ((c = Bgetc(bp)) != '\n') {
- if (c < 0)
- goto eof;
- if(c != '\r')
- lastc = c;
- }
- mkinline++;
- if (lastc == '\\')
- break; /* propagate escaped newlines??*/
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break;
- default:
- rinsert(buf, c);
- break;
- }
- }
-eof:
- insert(buf, 0);
- return *buf->start != 0;
-}
-
-/*
- * assemble a back-quoted shell command into a buffer
- */
-static int
-bquote(Biobuf *bp, Bufblock *buf)
-{
- int c, line, term;
- int start;
-
- line = mkinline;
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- if(c == '{'){
- term = '}'; /* rc style */
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- } else
- term = '`'; /* sh style */
-
- start = buf->current-buf->start;
- for(;c > 0; c = nextrune(bp, 0)){
- if(c == term){
- insert(buf, '\n');
- insert(buf,0);
- buf->current = buf->start+start;
- execinit();
- execsh(0, buf->current, buf, envy, shellt, shellcmd);
- return 1;
- }
- if(c == '\n')
- break;
- if(c == '\'' || c == '"' || c == '\\'){
- insert(buf, c);
- if(!shellt->escapetoken(bp, buf, 1, c))
- return 0;
- continue;
- }
- rinsert(buf, c);
- }
- SYNERR(line);
- fprint(2, "missing closing %c after `\n", term);
- return 0;
-}
-
-/*
- * get next character stripping escaped newlines
- * the flag specifies whether escaped newlines are to be elided or
- * replaced with a blank.
- */
-int
-nextrune(Biobuf *bp, int elide)
-{
- int c, c2;
- static int savec;
-
- if(savec){
- c = savec;
- savec = 0;
- return c;
- }
-
- for (;;) {
- c = Bgetrune(bp);
- if (c == '\\') {
- c2 = Bgetrune(bp);
- if(c2 == '\r'){
- savec = c2;
- c2 = Bgetrune(bp);
- }
- if (c2 == '\n') {
- savec = 0;
- mkinline++;
- if (elide)
- continue;
- return ' ';
- }
- Bungetrune(bp);
- }
- if (c == '\n')
- mkinline++;
- return c;
- }
-}
diff -r bb17f966e24a -r 1161d90df941 mk/main.c
--- a/mk/main.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-#include "mk.h"
-
-#define MKFILE "mkfile"
-
-int debug;
-Rule *rules, *metarules;
-int nflag = 0;
-int tflag = 0;
-int iflag = 0;
-int kflag = 0;
-int aflag = 0;
-int uflag = 0;
-char *explain = 0;
-Word *target1;
-int nreps = 1;
-Job *jobs;
-Biobuf bout;
-Rule *patrule;
-void badusage(void);
-#ifdef PROF
-short buf[10000];
-#endif
-
-int
-main(int argc, char **argv)
-{
- Word *w;
- char *s, *temp;
- char *files[256], **f = files, **ff;
- int sflag = 0;
- int i;
- int tfd = -1;
- Biobuf tb;
- Bufblock *buf;
- Bufblock *whatif;
-
- /*
- * start with a copy of the current environment variables
- * instead of sharing them
- */
-
- Binit(&bout, 1, OWRITE);
- buf = newbuf();
- whatif = 0;
- USED(argc);
- for(argv++; *argv && (**argv == '-'); argv++)
- {
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- switch(argv[0][1])
- {
- case 'a':
- aflag = 1;
- break;
- case 'd':
- if(*(s = &argv[0][2]))
- while(*s) switch(*s++)
- {
- case 'p': debug |= D_PARSE; break;
- case 'g': debug |= D_GRAPH; break;
- case 'e': debug |= D_EXEC; break;
- }
- else
- debug = 0xFFFF;
- break;
- case 'e':
- explain = &argv[0][2];
- break;
- case 'f':
- if(*++argv == 0)
- badusage();
- *f++ = *argv;
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- break;
- case 'i':
- iflag = 1;
- break;
- case 'k':
- kflag = 1;
- break;
- case 'n':
- nflag = 1;
- break;
- case 's':
- sflag = 1;
- break;
- case 't':
- tflag = 1;
- break;
- case 'u':
- uflag = 1;
- break;
- case 'w':
- if(whatif == 0)
- whatif = newbuf();
- else
- insert(whatif, ' ');
- if(argv[0][2])
- bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]));
- else {
- if(*++argv == 0)
- badusage();
- bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]));
- }
- break;
- default:
- badusage();
- }
- }
-#ifdef PROF
- {
- extern etext();
- monitor(main, etext, buf, sizeof buf, 300);
- }
-#endif
-
- if(aflag)
- iflag = 1;
- usage();
- syminit();
- initshell();
- initenv();
- usage();
-
- /*
- assignment args become null strings
- */
- temp = 0;
- for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
- bufcpy(buf, argv[i], strlen(argv[i]));
- insert(buf, ' ');
- if(tfd < 0){
- temp = maketmp(&tfd);
- if(temp == 0) {
- fprint(2, "temp file: %r\n");
- Exit();
- }
- Binit(&tb, tfd, OWRITE);
- }
- Bprint(&tb, "%s\n", argv[i]);
- *argv[i] = 0;
- }
- if(tfd >= 0){
- Bflush(&tb);
- LSEEK(tfd, 0L, 0);
- parse("command line args", tfd, 1);
- remove(temp);
- }
-
- if (buf->current != buf->start) {
- buf->current--;
- insert(buf, 0);
- }
- symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
- buf->current = buf->start;
- for(i = 0; argv[i]; i++){
- if(*argv[i] == 0) continue;
- if(i)
- insert(buf, ' ');
- bufcpy(buf, argv[i], strlen(argv[i]));
- }
- insert(buf, 0);
- symlook("MKARGS", S_VAR, (void *) stow(buf->start));
- freebuf(buf);
-
- if(f == files){
- if(access(MKFILE, 4) == 0)
- parse(MKFILE, open(MKFILE, 0), 0);
- } else
- for(ff = files; ff < f; ff++)
- parse(*ff, open(*ff, 0), 0);
- if(DEBUG(D_PARSE)){
- dumpw("default targets", target1);
- dumpr("rules", rules);
- dumpr("metarules", metarules);
- dumpv("variables");
- }
- if(whatif){
- insert(whatif, 0);
- timeinit(whatif->start);
- freebuf(whatif);
- }
- execinit();
- /* skip assignment args */
- while(*argv && (**argv == 0))
- argv++;
-
- catchnotes();
- if(*argv == 0){
- if(target1)
- for(w = target1; w; w = w->next)
- mk(w->s);
- else {
- fprint(2, "mk: nothing to mk\n");
- Exit();
- }
- } else {
- if(sflag){
- for(; *argv; argv++)
- if(**argv)
- mk(*argv);
- } else {
- Word *head, *tail, *t;
-
- /* fake a new rule with all the args as prereqs */
- tail = 0;
- t = 0;
- for(; *argv; argv++)
- if(**argv){
- if(tail == 0)
- tail = t = newword(*argv);
- else {
- t->next = newword(*argv);
- t = t->next;
- }
- }
- if(tail->next == 0)
- mk(tail->s);
- else {
- head = newword("command line arguments");
- addrules(head, tail, strdup(""), VIR, mkinline, 0);
- mk(head->s);
- }
- }
- }
- if(uflag)
- prusage();
- exits(0);
- return 0;
-}
-
-void
-badusage(void)
-{
-
- fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n");
- Exit();
-}
-
-void *
-Malloc(int n)
-{
- register void *s;
-
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void *
-Realloc(void *s, int n)
-{
- if(s)
- s = realloc(s, n);
- else
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void
-assert(char *s, int n)
-{
- if(!n){
- fprint(2, "mk: Assertion ``%s'' failed.\n", s);
- Exit();
- }
-}
-
-void
-regerror(char *s)
-{
- if(patrule)
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- patrule->file, patrule->line, s);
- else
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- infile, mkinline, s);
- Exit();
-}
diff -r bb17f966e24a -r 1161d90df941 mk/match.c
--- a/mk/match.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-#include "mk.h"
-
-int
-match(char *name, char *template, char *stem, Shell *sh)
-{
- Rune r;
- int n;
-
- while(*name && *template){
- n = chartorune(&r, template);
- if (PERCENT(r))
- break;
- while (n--)
- if(*name++ != *template++)
- return 0;
- }
- if(!PERCENT(*template))
- return 0;
- n = strlen(name)-strlen(template+1);
- if (n < 0)
- return 0;
- if (strcmp(template+1, name+n))
- return 0;
- strncpy(stem, name, n);
- stem[n] = 0;
- if(*template == '&')
- return !sh->charin(stem, "./");
- return 1;
-}
-
-void
-subst(char *stem, char *template, char *dest)
-{
- Rune r;
- char *s;
- int n;
-
- while(*template){
- n = chartorune(&r, template);
- if (PERCENT(r)) {
- template += n;
- for (s = stem; *s; s++)
- *dest++ = *s;
- } else
- while (n--)
- *dest++ = *template++;
- }
- *dest = 0;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/mk.1
--- a/mk/mk.1 Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,691 +0,0 @@
-.TH MK 1
-.SH NAME
-mk \- maintain (make) related files
-.SH SYNOPSIS
-.B mk
-[
-.B -f
-.I mkfile
-] ...
-[
-.I option ...
-]
-[
-.I target ...
-]
-.SH DESCRIPTION
-.I Mk
-uses the dependency rules specified in
-.I mkfile
-to control the update (usually by compilation) of
-.I targets
-(usually files)
-from the source files upon which they depend.
-The
-.I mkfile
-(default
-.LR mkfile )
-contains a
-.I rule
-for each target that identifies the files and other
-targets upon which it depends and an
-.IR sh (1)
-script, a
-.IR recipe ,
-to update the target.
-The script is run if the target does not exist
-or if it is older than any of the files it depends on.
-.I Mkfile
-may also contain
-.I meta-rules
-that define actions for updating implicit targets.
-If no
-.I target
-is specified, the target of the first rule (not meta-rule) in
-.I mkfile
-is updated.
-.PP
-The environment variable
-.B $NPROC
-determines how many targets may be updated simultaneously;
-Some operating systems, e.g., Plan 9, set
-.B $NPROC
-automatically to the number of CPUs on the current machine.
-.PP
-Options are:
-.TP \w'\fL-d[egp]\ 'u
-.B -a
-Assume all targets to be out of date.
-Thus, everything is updated.
-.PD 0
-.TP
-.BR -d [ egp ]
-Produce debugging output
-.RB ( p
-is for parsing,
-.B g
-for graph building,
-.B e
-for execution).
-.TP
-.B -e
-Explain why each target is made.
-.TP
-.B -i
-Force any missing intermediate targets to be made.
-.TP
-.B -k
-Do as much work as possible in the face of errors.
-.TP
-.B -n
-Print, but do not execute, the commands
-needed to update the targets.
-.TP
-.B -s
-Make the command line arguments sequentially rather than in parallel.
-.TP
-.B -t
-Touch (update the modified date of) file targets, without
-executing any recipes.
-.TP
-.BI -w target1 , target2,...
-Pretend the modify time for each
-.I target
-is the current time; useful in conjunction with
-.B -n
-to learn what updates would be triggered by
-modifying the
-.IR targets .
-.PD
-.SS The \fLmkfile\fP
-A
-.I mkfile
-consists of
-.I assignments
-(described under `Environment') and
-.IR rules .
-A rule contains
-.I targets
-and a
-.IR tail .
-A target is a literal string
-and is normally a file name.
-The tail contains zero or more
-.I prerequisites
-and an optional
-.IR recipe ,
-which is an
-.B shell
-script.
-Each line of the recipe must begin with white space.
-A rule takes the form
-.IP
-.EX
-target: prereq1 prereq2
- \f2recipe using\fP prereq1, prereq2 \f2to build\fP target
-.EE
-.PP
-When the recipe is executed,
-the first character on every line is elided.
-.PP
-After the colon on the target line, a rule may specify
-.IR attributes ,
-described below.
-.PP
-A
-.I meta-rule
-has a target of the form
-.IB A % B
-where
-.I A
-and
-.I B
-are (possibly empty) strings.
-A meta-rule acts as a rule for any potential target whose
-name matches
-.IB A % B
-with
-.B %
-replaced by an arbitrary string, called the
-.IR stem .
-In interpreting a meta-rule,
-the stem is substituted for all occurrences of
-.B %
-in the prerequisite names.
-In the recipe of a meta-rule, the environment variable
-.B $stem
-contains the string matched by the
-.BR % .
-For example, a meta-rule to compile a C program using
-.IR 9c (1)
-might be:
-.IP
-.EX
-%: %.c
- 9c -c $stem.c
- 9l -o $stem $stem.o
-.EE
-.PP
-Meta-rules may contain an ampersand
-.B &
-rather than a percent sign
-.BR % .
-A
-.B %
-matches a maximal length string of any characters;
-an
-.B &
-matches a maximal length string of any characters except period
-or slash.
-.PP
-The text of the
-.I mkfile
-is processed as follows.
-Lines beginning with
-.B <
-followed by a file name are replaced by the contents of the named
-file.
-Lines beginning with
-.B "<|"
-followed by a file name are replaced by the output
-of the execution of the named
-file.
-Blank lines and comments, which run from unquoted
-.B #
-characters to the following newline, are deleted.
-The character sequence backslash-newline is deleted,
-so long lines in
-.I mkfile
-may be folded.
-Non-recipe lines are processed by substituting for
-.BI `{ command }
-the output of the
-.I command
-when run by
-.IR sh .
-References to variables are replaced by the variables' values.
-Special characters may be quoted using single quotes
-.BR \&''
-as in
-.IR sh (1).
-.PP
-Assignments and rules are distinguished by
-the first unquoted occurrence of
-.B :
-(rule)
-or
-.B =
-(assignment).
-.PP
-A later rule may modify or override an existing rule under the
-following conditions:
-.TP
-\-
-If the targets of the rules exactly match and one rule
-contains only a prerequisite clause and no recipe, the
-clause is added to the prerequisites of the other rule.
-If either or both targets are virtual, the recipe is
-always executed.
-.TP
-\-
-If the targets of the rules match exactly and the
-prerequisites do not match and both rules
-contain recipes,
-.I mk
-reports an ``ambiguous recipe'' error.
-.TP
-\-
-If the target and prerequisites of both rules match exactly,
-the second rule overrides the first.
-.SS Environment
-Rules may make use of
-shell
-environment variables.
-A legal reference of the form
-.B $OBJ
-or
-.B ${name}
-is expanded as in
-.IR sh (1).
-A reference of the form
-.BI ${name: A % B = C\fL%\fID\fL}\fR,
-where
-.I A, B, C, D
-are (possibly empty) strings,
-has the value formed by expanding
-.B $name
-and substituting
-.I C
-for
-.I A
-and
-.I D
-for
-.I B
-in each word in
-.B $name
-that matches pattern
-.IB A % B\f1.
-.PP
-Variables can be set by
-assignments of the form
-.I
- var\fL=\fR[\fIattr\fL=\fR]\fIvalue\fR
-.br
-Blanks in the
-.I value
-break it into words.
-Such variables are exported
-to the environment of
-recipes as they are executed, unless
-.BR U ,
-the only legal attribute
-.IR attr ,
-is present.
-The initial value of a variable is
-taken from (in increasing order of precedence)
-the default values below,
-.I mk's
-environment, the
-.IR mkfiles ,
-and any command line assignment as an argument to
-.IR mk .
-A variable assignment argument overrides the first (but not any subsequent)
-assignment to that variable.
-.PP
-The variable
-.B MKFLAGS
-contains all the option arguments (arguments starting with
-.L -
-or containing
-.LR = )
-and
-.B MKARGS
-contains all the targets in the call to
-.IR mk .
-.PP
-The variable
-.B MKSHELL
-contains the shell command line
-.I mk
-uses to run recipes.
-If the first word of the command ends in
-.B rc
-or
-.BR rcsh ,
-.I mk
-uses
-.IR rc (1)'s
-quoting rules; otherwise it uses
-.IR sh (1)'s.
-The
-.B MKSHELL
-variable is consulted when the mkfile is read, not when it is executed,
-so that different shells can be used within a single mkfile:
-.IP
-.EX
-MKSHELL=$PLAN9/bin/rc
-use-rc:V:
- for(i in a b c) echo $i
-
-MKSHELL=sh
-use-sh:V:
- for i in a b c; do echo $i; done
-.EE
-.LP
-Mkfiles included via
-.B <
-or
-.B <|
-.RI ( q.v. )
-see their own private copy of
-.BR MKSHELL ,
-which always starts set to
-.B sh .
-.PP
-Dynamic information may be included in the mkfile by using a line of the form
-.IP
-\fR<|\fIcommand\fR \fIargs\fR
-.LP
-This runs the command
-.I command
-with the given arguments
-.I args
-and pipes its standard output to
-.I mk
-to be included as part of the mkfile. For instance, the Inferno kernels
-use this technique
-to run a shell command with an awk script and a configuration
-file as arguments in order for
-the
-.I awk
-script to process the file and output a set of variables and their values.
-.SS Execution
-.PP
-During execution,
-.I mk
-determines which targets must be updated, and in what order,
-to build the
-.I names
-specified on the command line.
-It then runs the associated recipes.
-.PP
-A target is considered up to date if it has no prerequisites or
-if all its prerequisites are up to date and it is newer
-than all its prerequisites.
-Once the recipe for a target has executed, the target is
-considered up to date.
-.PP
-The date stamp
-used to determine if a target is up to date is computed
-differently for different types of targets.
-If a target is
-.I virtual
-(the target of a rule with the
-.B V
-attribute),
-its date stamp is initially zero; when the target is
-updated the date stamp is set to
-the most recent date stamp of its prerequisites.
-Otherwise, if a target does not exist as a file,
-its date stamp is set to the most recent date stamp of its prerequisites,
-or zero if it has no prerequisites.
-Otherwise, the target is the name of a file and
-the target's date stamp is always that file's modification date.
-The date stamp is computed when the target is needed in
-the execution of a rule; it is not a static value.
-.PP
-Nonexistent targets that have prerequisites
-and are themselves prerequisites are treated specially.
-Such a target
-.I t
-is given the date stamp of its most recent prerequisite
-and if this causes all the targets which have
-.I t
-as a prerequisite to be up to date,
-.I t
-is considered up to date.
-Otherwise,
-.I t
-is made in the normal fashion.
-The
-.B -i
-flag overrides this special treatment.
-.PP
-Files may be made in any order that respects
-the preceding restrictions.
-.PP
-A recipe is executed by supplying the recipe as standard input to
-the command
-.BR /bin/sh .
-(Note that unlike
-.IR make ,
-.I mk
-feeds the entire recipe to the shell rather than running each line
-of the recipe separately.)
-The environment is augmented by the following variables:
-.TP 14
-.B $alltarget
-all the targets of this rule.
-.TP
-.B $newprereq
-the prerequisites that caused this rule to execute.
-.TP
-.B $newmember
-the prerequisites that are members of an aggregate
-that caused this rule to execute.
-When the prerequisites of a rule are members of an
-aggregate,
-.B $newprereq
-contains the name of the aggregate and out of date
-members, while
-.B $newmember
-contains only the name of the members.
-.TP
-.B $nproc
-the process slot for this recipe.
-It satisfies
-.RB 0≤ $nproc < $NPROC .
-.TP
-.B $pid
-the process id for the
-.I mk
-executing the recipe.
-.TP
-.B $prereq
-all the prerequisites for this rule.
-.TP
-.B $stem
-if this is a meta-rule,
-.B $stem
-is the string that matched
-.B %
-or
-.BR & .
-Otherwise, it is empty.
-For regular expression meta-rules (see below), the variables
-.LR stem0 ", ...,"
-.L stem9
-are set to the corresponding subexpressions.
-.TP
-.B $target
-the targets for this rule that need to be remade.
-.PP
-These variables are available only during the execution of a recipe,
-not while evaluating the
-.IR mkfile .
-.PP
-Unless the rule has the
-.B Q
-attribute,
-the recipe is printed prior to execution
-with recognizable environment variables expanded.
-Commands returning error status
-cause
-.I mk
-to terminate.
-.PP
-Recipes and backquoted
-.B rc
-commands in places such as assignments
-execute in a copy of
-.I mk's
-environment; changes they make to
-environment variables are not visible from
-.IR mk .
-.PP
-Variable substitution in a rule is done when
-the rule is read; variable substitution in the recipe is done
-when the recipe is executed. For example:
-.IP
-.EX
-bar=a.c
-foo: $bar
- $CC -o foo $bar
-bar=b.c
-.EE
-.PP
-will compile
-.B b.c
-into
-.BR foo ,
-if
-.B a.c
-is newer than
-.BR foo .
-.SS Aggregates
-Names of the form
-.IR a ( b )
-refer to member
-.I b
-of the aggregate
-.IR a .
-Currently, the only aggregates supported are
-.I 9ar
-(see
-.IR 9c (1))
-archives.
-.SS Attributes
-The colon separating the target from the prerequisites
-may be
-immediately followed by
-.I attributes
-and another colon.
-The attributes are:
-.TP
-.B D
-If the recipe exits with a non-null status, the target is deleted.
-.TP
-.B E
-Continue execution if the recipe draws errors.
-.TP
-.B N
-If there is no recipe, the target has its time updated.
-.TP
-.B n
-The rule is a meta-rule that cannot be a target of a virtual rule.
-Only files match the pattern in the target.
-.TP
-.B P
-The characters after the
-.B P
-until the terminating
-.B :
-are taken as a program name.
-It will be invoked as
-.B "sh -c prog 'arg1' 'arg2'"
-and should return a zero exit status
-if and only if arg1 is up to date with respect to arg2.
-Date stamps are still propagated in the normal way.
-.TP
-.B Q
-The recipe is not printed prior to execution.
-.TP
-.B R
-The rule is a meta-rule using regular expressions.
-In the rule,
-.B %
-has no special meaning.
-The target is interpreted as a regular expression as defined in
-.IR regexp (7).
-The prerequisites may contain references
-to subexpressions in form
-.BI \e n\f1,
-as in the substitute command of
-.IR sed (1).
-.TP
-.B U
-The targets are considered to have been updated
-even if the recipe did not do so.
-.TP
-.B V
-The targets of this rule are marked as virtual.
-They are distinct from files of the same name.
-.PD
-.SH EXAMPLES
-A simple mkfile to compile a program:
-.IP
-.EX
-.ta 8n +8n +8n +8n +8n +8n +8n
-</$objtype/mkfile
-
-prog: a.$O b.$O c.$O
- $LD $LDFLAGS -o $target $prereq
-
-%.$O: %.c
- $CC $CFLAGS $stem.c
-.EE
-.PP
-Override flag settings in the mkfile:
-.IP
-.EX
-% mk target 'CFLAGS=-S -w'
-.EE
-.PP
-Maintain a library:
-.IP
-.EX
-libc.a(%.$O):N: %.$O
-libc.a: libc.a(abs.$O) libc.a(access.$O) libc.a(alarm.$O) ...
- ar r libc.a $newmember
-.EE
-.PP
-String expression variables to derive names from a master list:
-.IP
-.EX
-NAMES=alloc arc bquote builtins expand main match mk var word
-OBJ=${NAMES:%=%.$O}
-.EE
-.PP
-Regular expression meta-rules:
-.IP
-.EX
-([^/]*)/(.*)\e.$O:R: \e1/\e2.c
- cd $stem1; $CC $CFLAGS $stem2.c
-.EE
-.PP
-A correct way to deal with
-.IR yacc (1)
-grammars.
-The file
-.B lex.c
-includes the file
-.B x.tab.h
-rather than
-.B y.tab.h
-in order to reflect changes in content, not just modification time.
-.IP
-.EX
-lex.$O: x.tab.h
-x.tab.h: y.tab.h
- cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
-y.tab.c y.tab.h: gram.y
- $YACC -d gram.y
-.EE
-.PP
-The above example could also use the
-.B P
-attribute for the
-.B x.tab.h
-rule:
-.IP
-.EX
-x.tab.h:Pcmp -s: y.tab.h
- cp y.tab.h x.tab.h
-.EE
-.SH SOURCE
-.B \*9/src/cmd/mk
-.SH SEE ALSO
-.IR sh (1),
-.IR regexp (7)
-.PP
-A. Hume,
-``Mk: a Successor to Make''
-(Tenth Edition Research Unix Manuals).
-.PP
-Andrew G. Hume and Bob Flandrena,
-``Maintaining Files on Plan 9 with Mk''.
-DOCPREFIX/doc/mk.pdf
-.SH HISTORY
-Andrew Hume wrote
-.I mk
-for Tenth Edition Research Unix.
-It was later ported to Plan 9.
-This software is a port of the Plan 9 version back to Unix.
-.SH BUGS
-Identical recipes for regular expression meta-rules only have one target.
-.PP
-Seemingly appropriate input like
-.B CFLAGS=-DHZ=60
-is parsed as an erroneous attribute; correct it by inserting
-a space after the first
-.LR = .
-.PP
-The recipes printed by
-.I mk
-before being passed to
-the shell
-for execution are sometimes erroneously expanded
-for printing. Don't trust what's printed; rely
-on what the shell
-does.
diff -r bb17f966e24a -r 1161d90df941 mk/mk.c
--- a/mk/mk.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,234 +0,0 @@
-#include "mk.h"
-
-int runerrs;
-
-void
-mk(char *target)
-{
- Node *node;
- int did = 0;
-
- nproc(); /* it can be updated dynamically */
- nrep(); /* it can be updated dynamically */
- runerrs = 0;
- node = graph(target);
- if(DEBUG(D_GRAPH)){
- dumpn("new target\n", node);
- Bflush(&bout);
- }
- clrmade(node);
- while(node->flags&NOTMADE){
- if(work(node, (Node *)0, (Arc *)0))
- did = 1; /* found something to do */
- else {
- if(waitup(1, (int *)0) > 0){
- if(node->flags&(NOTMADE|BEINGMADE)){
- assert("must be run errors", runerrs);
- break; /* nothing more waiting */
- }
- }
- }
- }
- if(node->flags&BEINGMADE)
- waitup(-1, (int *)0);
- while(jobs)
- waitup(-2, (int *)0);
- assert("target didn't get done", runerrs || (node->flags&MADE));
- if(did == 0)
- Bprint(&bout, "mk: '%s' is up to date\n", node->name);
-}
-
-void
-clrmade(Node *n)
-{
- Arc *a;
-
- n->flags &= ~(CANPRETEND|PRETENDING);
- if(strchr(n->name, '(') ==0 || n->time)
- n->flags |= CANPRETEND;
- MADESET(n, NOTMADE);
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- clrmade(a->n);
-}
-
-static void
-unpretend(Node *n)
-{
- MADESET(n, NOTMADE);
- n->flags &= ~(CANPRETEND|PRETENDING);
- n->time = 0;
-}
-
-static char*
-dir(void)
-{
- static char buf[1024];
-
- return getcwd(buf, sizeof buf);
-}
-
-int
-work(Node *node, Node *p, Arc *parc)
-{
- Arc *a, *ra;
- int weoutofdate;
- int ready;
- int did = 0;
-
- /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);*//**/
- if(node->flags&BEINGMADE)
- return(did);
- if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){
- if(explain)
- fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n",
- node->name, node->time, p->name, p->time);
- unpretend(node);
- }
- /*
- have a look if we are pretending in case
- someone has been unpretended out from underneath us
- */
- if(node->flags&MADE){
- if(node->flags&PRETENDING){
- node->time = 0;
- }else
- return(did);
- }
- /* consider no prerequsite case */
- if(node->prereqs == 0){
- if(node->time == 0){
- fprint(2, "mk: don't know how to make '%s' in %s\n", node->name, dir());
- if(kflag){
- node->flags |= BEINGMADE;
- runerrs++;
- } else
- Exit();
- } else
- MADESET(node, MADE);
- return(did);
- }
- /*
- now see if we are out of date or what
- */
- ready = 1;
- weoutofdate = aflag;
- ra = 0;
- for(a = node->prereqs; a; a = a->next)
- if(a->n){
- did = work(a->n, node, a) || did;
- if(a->n->flags&(NOTMADE|BEINGMADE))
- ready = 0;
- if(outofdate(node, a, 0)){
- weoutofdate = 1;
- if((ra == 0) || (ra->n == 0)
- || (ra->n->time < a->n->time))
- ra = a;
- }
- } else {
- if(node->time == 0){
- if(ra == 0)
- ra = a;
- weoutofdate = 1;
- }
- }
- if(ready == 0) /* can't do anything now */
- return(did);
- if(weoutofdate == 0){
- MADESET(node, MADE);
- return(did);
- }
- /*
- can we pretend to be made?
- */
- if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND))
- && p && ra->n && !outofdate(p, ra, 0)){
- node->flags &= ~CANPRETEND;
- MADESET(node, MADE);
- if(explain && ((node->flags&PRETENDING) == 0))
- fprint(1, "pretending %s has time %ld\n", node->name, node->time);
- node->flags |= PRETENDING;
- return(did);
- }
- /*
- node is out of date and we REALLY do have to do something.
- quickly rescan for pretenders
- */
- for(a = node->prereqs; a; a = a->next)
- if(a->n && (a->n->flags&PRETENDING)){
- if(explain)
- Bprint(&bout, "unpretending %s because of %s because of %s\n",
- a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites");
-
- unpretend(a->n);
- did = work(a->n, node, a) || did;
- ready = 0;
- }
- if(ready == 0) /* try later unless nothing has happened for -k's sake */
- return(did || work(node, p, parc));
- did = dorecipe(node) || did;
- return(did);
-}
-
-void
-update(int fake, Node *node)
-{
- Arc *a;
-
- MADESET(node, fake? BEINGMADE : MADE);
- if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
- node->time = timeof(node->name, 1);
- node->flags &= ~(CANPRETEND|PRETENDING);
- for(a = node->prereqs; a; a = a->next)
- if(a->prog)
- outofdate(node, a, 1);
- } else {
- node->time = 1;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && outofdate(node, a, 1))
- node->time = a->n->time;
- }
-/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);*//**/
-}
-
-static int
-pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd)
-{
- char buf[3*NAMEBLOCK];
- int pid;
-
- Bflush(&bout);
- snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
- pid = pipecmd(buf, 0, 0, sh, shcmd);
- while(waitup(-3, &pid) >= 0)
- ;
- return(pid? 2:1);
-}
-
-int
-outofdate(Node *node, Arc *arc, int eval)
-{
- char buf[3*NAMEBLOCK], *str;
- Symtab *sym;
- int ret;
-
- str = 0;
- if(arc->prog){
- snprint(buf, sizeof buf, "%s%c%s", node->name, 0377, arc->n->name);
- sym = symlook(buf, S_OUTOFDATE, 0);
- if(sym == 0 || eval){
- if(sym == 0)
- str = strdup(buf);
- ret = pcmp(arc->prog, node->name, arc->n->name, arc->r->shellt, arc->r->shellcmd);
- if(sym)
- sym->value = (void *)ret;
- else
- symlook(str, S_OUTOFDATE, (void *)ret);
- } else
- ret = (int)sym->value;
- return(ret-1);
- } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */
- return 1;
- else
- return node->time <= arc->n->time;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/mk.h
--- a/mk/mk.h Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-#include "sys.h"
-
-#undef assert
-#define assert mkassert
-extern Biobuf bout;
-
-typedef struct Bufblock
-{
- struct Bufblock *next;
- char *start;
- char *end;
- char *current;
-} Bufblock;
-
-typedef struct Word
-{
- char *s;
- struct Word *next;
-} Word;
-
-typedef struct Envy
-{
- char *name;
- Word *values;
-} Envy;
-
-extern Envy *envy;
-
-typedef struct Shell
-{
- char *name;
- char *termchars; /* used in parse.c to isolate assignment attribute */
- int iws; /* inter-word separator in environment */
- char *(*charin)(char*, char*); /* search for unescaped characters */
- char *(*expandquote)(char*, Rune, Bufblock*); /* extract escaped token */
- int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* input escaped token */
- char *(*copyq)(char*, Rune, Bufblock*); /* check for quoted strings */
- int (*matchname)(char*); /* does name match */
-} Shell;
-
-typedef struct Rule
-{
- char *target; /* one target */
- Word *tail; /* constituents of targets */
- char *recipe; /* do it ! */
- short attr; /* attributes */
- short line; /* source line */
- char *file; /* source file */
- Word *alltargets; /* all the targets */
- int rule; /* rule number */
- Reprog *pat; /* reg exp goo */
- char *prog; /* to use in out of date */
- struct Rule *chain; /* hashed per target */
- struct Rule *next;
- Shell *shellt; /* shell to use with this rule */
- Word *shellcmd;
-} Rule;
-
-extern Rule *rules, *metarules, *patrule;
-
-/* Rule.attr */
-#define META 0x0001
-#define UNUSED 0x0002
-#define UPD 0x0004
-#define QUIET 0x0008
-#define VIR 0x0010
-#define REGEXP 0x0020
-#define NOREC 0x0040
-#define DEL 0x0080
-#define NOVIRT 0x0100
-
-#define NREGEXP 10
-
-typedef struct Arc
-{
- short flag;
- struct Node *n;
- Rule *r;
- char *stem;
- char *prog;
- char *match[NREGEXP];
- struct Arc *next;
-} Arc;
-
- /* Arc.flag */
-#define TOGO 1
-
-typedef struct Node
-{
- char *name;
- long time;
- unsigned short flags;
- Arc *prereqs;
- struct Node *next; /* list for a rule */
-} Node;
-
- /* Node.flags */
-#define VIRTUAL 0x0001
-#define CYCLE 0x0002
-#define READY 0x0004
-#define CANPRETEND 0x0008
-#define PRETENDING 0x0010
-#define NOTMADE 0x0020
-#define BEINGMADE 0x0040
-#define MADE 0x0080
-#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEINGMADE|MADE))|(m)
-#define PROBABLE 0x0100
-#define VACUOUS 0x0200
-#define NORECIPE 0x0400
-#define DELETE 0x0800
-#define NOMINUSE 0x1000
-
-typedef struct Job
-{
- Rule *r; /* master rule for job */
- Node *n; /* list of node targets */
- char *stem;
- char **match;
- Word *p; /* prerequistes */
- Word *np; /* new prerequistes */
- Word *t; /* targets */
- Word *at; /* all targets */
- int nproc; /* slot number */
- struct Job *next;
-} Job;
-extern Job *jobs;
-
-typedef struct Symtab
-{
- short space;
- char *name;
- void *value;
- struct Symtab *next;
-} Symtab;
-
-enum {
- S_VAR, /* variable -> value */
- S_TARGET, /* target -> rule */
- S_TIME, /* file -> time */
- S_PID, /* pid -> products */
- S_NODE, /* target name -> node */
- S_AGG, /* aggregate -> time */
- S_BITCH, /* bitched about aggregate not there */
- S_NOEXPORT, /* var -> noexport */
- S_OVERRIDE, /* can't override */
- S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */
- S_MAKEFILE, /* target -> node */
- S_MAKEVAR, /* dumpable mk variable */
- S_EXPORTED, /* var -> current exported value */
- S_WESET, /* variable; we set in the mkfile */
- S_INTERNAL /* an internal mk variable (e.g., stem, target) */
-};
-
-extern int debug;
-extern int nflag, tflag, iflag, kflag, aflag, mflag;
-extern int mkinline;
-extern char *infile;
-extern int nreps;
-extern char *explain;
-extern Shell *shellt;
-extern Word *shellcmd;
-
-extern Shell shshell, rcshell;
-
-#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline))
-#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line))
-#define NAMEBLOCK 1000
-#define BIGBLOCK 20000
-
-#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
-#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", (r)))
-
-#define DEBUG(x) (debug&(x))
-#define D_PARSE 0x01
-#define D_GRAPH 0x02
-#define D_EXEC 0x04
-
-#define LSEEK(f,o,p) seek(f,o,p)
-
-#define PERCENT(ch) (((ch) == '%') || ((ch) == '&'))
-
-#include "fns.h"
diff -r bb17f966e24a -r 1161d90df941 mk/parse.c
--- a/mk/parse.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
-#include "mk.h"
-
-char *infile;
-int mkinline;
-static int rhead(char *, Word **, Word **, int *, char **);
-static char *rbody(Biobuf*);
-extern Word *target1;
-
-void
-parse(char *f, int fd, int varoverride)
-{
- int hline;
- char *body;
- Word *head, *tail;
- int attr, set, pid;
- char *prog, *p;
- int newfd;
- Biobuf in;
- Bufblock *buf;
- char *err;
-
- if(fd < 0){
- fprint(2, "open %s: %r\n", f);
- Exit();
- }
- pushshell();
- ipush();
- infile = strdup(f);
- mkinline = 1;
- Binit(&in, fd, OREAD);
- buf = newbuf();
- while(assline(&in, buf)){
- hline = mkinline;
- switch(rhead(buf->start, &head, &tail, &attr, &prog))
- {
- case '<':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include file name\n");
- Exit();
- }
- newfd = open(p, OREAD);
- if(newfd < 0){
- fprint(2, "warning: skipping missing include file %s: %r\n", p);
- } else
- parse(p, newfd, 0);
- break;
- case '|':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include program name\n");
- Exit();
- }
- execinit();
- pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
- if(newfd < 0){
- fprint(2, "warning: skipping missing program file %s: %r\n", p);
- } else
- parse(p, newfd, 0);
- while(waitup(-3, &pid) >= 0)
- ;
- if(pid != 0){
- fprint(2, "bad include program status\n");
- Exit();
- }
- break;
- case ':':
- body = rbody(&in);
- addrules(head, tail, body, attr, hline, prog);
- break;
- case '=':
- if(head->next){
- SYNERR(-1);
- fprint(2, "multiple vars on left side of assignment\n");
- Exit();
- }
- if(symlook(head->s, S_OVERRIDE, 0)){
- set = varoverride;
- } else {
- set = 1;
- if(varoverride)
- symlook(head->s, S_OVERRIDE, (void *)"");
- }
- if(set){
-/*
-char *cp;
-dumpw("tail", tail);
-cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
-*/
- setvar(head->s, (void *) tail);
- symlook(head->s, S_WESET, (void *)"");
- if(strcmp(head->s, "MKSHELL") == 0){
- if((err = setshell(tail)) != nil){
- SYNERR(hline);
- fprint(2, "%s\n", err);
- Exit();
- break;
- }
- }
- }
- if(attr)
- symlook(head->s, S_NOEXPORT, (void *)"");
- break;
- default:
- SYNERR(hline);
- fprint(2, "expected one of :<=\n");
- Exit();
- break;
- }
- }
- close(fd);
- freebuf(buf);
- ipop();
- popshell();
-}
-
-void
-addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
-{
- Word *w;
-
- assert("addrules args", head && body);
- /* tuck away first non-meta rule as default target*/
- if(target1 == 0 && !(attr&REGEXP)){
- for(w = head; w; w = w->next)
- if(shellt->charin(w->s, "%&"))
- break;
- if(w == 0)
- target1 = wdup(head);
- }
- for(w = head; w; w = w->next)
- addrule(w->s, tail, body, head, attr, hline, prog);
-}
-
-static int
-rhead(char *line, Word **h, Word **t, int *attr, char **prog)
-{
- char *p;
- char *pp;
- int sep;
- Rune r;
- int n;
- Word *w;
-
- p = shellt->charin(line,":=<");
- if(p == 0)
- return('?');
- sep = *p;
- *p++ = 0;
- if(sep == '<' && *p == '|'){
- sep = '|';
- p++;
- }
- *attr = 0;
- *prog = 0;
- if(sep == '='){
- pp = shellt->charin(p, shellt->termchars); /* termchars is shell-dependent */
- if (pp && *pp == '=') {
- while (p != pp) {
- n = chartorune(&r, p);
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n",*p);
- Exit();
- case 'U':
- *attr = 1;
- break;
- }
- p += n;
- }
- p++; /* skip trailing '=' */
- }
- }
- if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
- while (*p) {
- n = chartorune(&r, p);
- if (r == ':')
- break;
- p += n;
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n", p[-1]);
- Exit();
- case 'D':
- *attr |= DEL;
- break;
- case 'E':
- *attr |= NOMINUSE;
- break;
- case 'n':
- *attr |= NOVIRT;
- break;
- case 'N':
- *attr |= NOREC;
- break;
- case 'P':
- pp = utfrune(p, ':');
- if (pp == 0 || *pp == 0)
- goto eos;
- *pp = 0;
- *prog = strdup(p);
- *pp = ':';
- p = pp;
- break;
- case 'Q':
- *attr |= QUIET;
- break;
- case 'R':
- *attr |= REGEXP;
- break;
- case 'U':
- *attr |= UPD;
- break;
- case 'V':
- *attr |= VIR;
- break;
- }
- }
- if (*p++ != ':') {
- eos:
- SYNERR(-1);
- fprint(2, "missing trailing :\n");
- Exit();
- }
- }
- *h = w = stow(line);
- if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
- SYNERR(mkinline-1);
- fprint(2, "no var on left side of assignment/rule\n");
- Exit();
- }
- *t = stow(p);
- return(sep);
-}
-
-static char *
-rbody(Biobuf *in)
-{
- Bufblock *buf;
- int r, lastr;
- char *p;
-
- lastr = '\n';
- buf = newbuf();
- for(;;){
- r = Bgetrune(in);
- if (r < 0)
- break;
- if (lastr == '\n') {
- if (r == '#')
- rinsert(buf, r);
- else if (r != ' ' && r != '\t') {
- Bungetrune(in);
- break;
- }
- } else
- rinsert(buf, r);
- lastr = r;
- if (r == '\n')
- mkinline++;
- }
- insert(buf, 0);
- p = strdup(buf->start);
- freebuf(buf);
- return p;
-}
-
-struct input
-{
- char *file;
- int line;
- struct input *next;
-};
-static struct input *inputs = 0;
-
-void
-ipush(void)
-{
- struct input *in, *me;
-
- me = (struct input *)Malloc(sizeof(*me));
- me->file = infile;
- me->line = mkinline;
- me->next = 0;
- if(inputs == 0)
- inputs = me;
- else {
- for(in = inputs; in->next; )
- in = in->next;
- in->next = me;
- }
-}
-
-void
-ipop(void)
-{
- struct input *in, *me;
-
- assert("pop input list", inputs != 0);
- if(inputs->next == 0){
- me = inputs;
- inputs = 0;
- } else {
- for(in = inputs; in->next->next; )
- in = in->next;
- me = in->next;
- in->next = 0;
- }
- infile = me->file;
- mkinline = me->line;
- free((char *)me);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/rc.c
--- a/mk/rc.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on rc's syntax. Most
- * of the routines extract strings observing rc's escape conventions
- */
-
-
-/*
- * skip a token in single quotes.
- */
-static char *
-squote(char *cp)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == '\'') {
- n += chartorune(&r, cp+n);
- if(r != '\'')
- return(cp);
- }
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-
-/*
- * search a string for characters in a pattern set
- * characters in quotes and variable generators are escaped
- */
-char *
-rccharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\'': /* skip quoted string */
- cp = squote(cp+1); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash. Only the first is valid for rc. the
- * others are just inserted into the receiving buffer.
- */
-char*
-rcexpandquote(char *s, Rune r, Bufblock *b)
-{
- if (r != '\'') {
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == '\'') {
- if(*s == '\'')
- s++;
- else
- return s;
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash. Only the first is a valid escape for
- * rc; the others are just inserted into the receiving buffer.
- */
-int
-rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc != '\'')
- return 1;
-
- line = mkinline;
- while((c = nextrune(bp, 0)) > 0){
- if(c == '\''){
- if(preserve)
- rinsert(buf, c);
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if(c != '\''){
- Bungetrune(bp);
- return 1;
- }
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a single-quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == '\'')
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quotes above.
- * s points to char after opening quote, q.
- */
-char *
-rccopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'') /* copy quoted string */
- return copysingle(s, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '}')
- break;
- if(q == '\'')
- s = copysingle(s, buf); /* copy quoted string */
- }
- return s;
-}
-
-static int
-rcmatchname(char *name)
-{
- char *p;
-
- if((p = strchr(name, '/')) != nil)
- name = p+1;
- if(name[0] == 'r' && name[1] == 'c')
- return 1;
- return 0;
-}
-
-Shell rcshell = {
- "rc",
- "'= \t",
- '\1',
- rccharin,
- rcexpandquote,
- rcescapetoken,
- rccopyq,
- rcmatchname,
-};
diff -r bb17f966e24a -r 1161d90df941 mk/recipe.c
--- a/mk/recipe.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-#include "mk.h"
-
-int
-dorecipe(Node *node)
-{
- char buf[BIGBLOCK];
- register Node *n;
- Rule *r = 0;
- Arc *a, *aa;
- Word head, ahead, lp, ln, *w, *ww, *aw;
- Symtab *s;
- int did = 0;
-
- aa = 0;
- /*
- pick up the rule
- */
- for(a = node->prereqs; a; a = a->next)
- if(*a->r->recipe)
- r = (aa = a)->r;
- /*
- no recipe? go to buggery!
- */
- if(r == 0){
- if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){
- fprint(2, "mk: no recipe to make '%s'\n", node->name);
- Exit();
- }
- if(strchr(node->name, '(') && node->time == 0)
- MADESET(node, MADE);
- else
- update(0, node);
- if(tflag){
- if(!(node->flags&VIRTUAL))
- touch(node->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s'\n", node->name);
- }
- return(did);
- }
- /*
- build the node list
- */
- node->next = 0;
- head.next = 0;
- ww = &head;
- ahead.next = 0;
- aw = &ahead;
- if(r->attr&REGEXP){
- ww->next = newword(node->name);
- aw->next = newword(node->name);
- } else {
- for(w = r->alltargets; w; w = w->next){
- if(r->attr&META)
- subst(aa->stem, w->s, buf);
- else
- strcpy(buf, w->s);
- aw->next = newword(buf);
- aw = aw->next;
- if((s = symlook(buf, S_NODE, 0)) == 0)
- continue; /* not a node we are interested in */
- n = (Node *)s->value;
- if(aflag == 0 && n->time) {
- for(a = n->prereqs; a; a = a->next)
- if(a->n && outofdate(n, a, 0))
- break;
- if(a == 0)
- continue;
- }
- ww->next = newword(buf);
- ww = ww->next;
- if(n == node) continue;
- n->next = node->next;
- node->next = n;
- }
- }
- for(n = node; n; n = n->next)
- if((n->flags&READY) == 0)
- return(did);
- /*
- gather the params for the job
- */
- lp.next = ln.next = 0;
- for(n = node; n; n = n->next){
- for(a = n->prereqs; a; a = a->next){
- if(a->n){
- addw(&lp, a->n->name);
- if(outofdate(n, a, 0)){
- addw(&ln, a->n->name);
- if(explain)
- fprint(1, "%s(%ld) < %s(%ld)\n",
- n->name, n->time, a->n->name, a->n->time);
- }
- } else {
- if(explain)
- fprint(1, "%s has no prerequisites\n",
- n->name);
- }
- }
- MADESET(n, BEINGMADE);
- }
- /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));*//**/
- run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next));
- return(1);
-}
-
-void
-addw(Word *w, char *s)
-{
- Word *lw;
-
- for(lw = w; w = w->next; lw = w){
- if(strcmp(s, w->s) == 0)
- return;
- }
- lw->next = newword(s);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/rule.c
--- a/mk/rule.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-#include "mk.h"
-
-static Rule *lr, *lmr;
-static int rcmp(Rule *r, char *target, Word *tail);
-static int nrules = 0;
-
-void
-addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog)
-{
- Rule *r;
- Rule *rr;
- Symtab *sym;
- int reuse;
-
- r = 0;
- reuse = 0;
- if(sym = symlook(head, S_TARGET, 0)){
- for(r = (Rule *)sym->value; r; r = r->chain)
- if(rcmp(r, head, tail) == 0){
- reuse = 1;
- break;
- }
- }
- if(r == 0)
- r = (Rule *)Malloc(sizeof(Rule));
- r->shellt = shellt;
- r->shellcmd = shellcmd;
- r->target = head;
- r->tail = tail;
- r->recipe = body;
- r->line = hline;
- r->file = infile;
- r->attr = attr;
- r->alltargets = ahead;
- r->prog = prog;
- r->rule = nrules++;
- if(!reuse){
- rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value;
- if(rr != r){
- r->chain = rr->chain;
- rr->chain = r;
- } else
- r->chain = 0;
- }
- if(!reuse)
- r->next = 0;
- if((attr&REGEXP) || shellt->charin(head, "%&")){
- r->attr |= META;
- if(reuse)
- return;
- if(attr&REGEXP){
- patrule = r;
- r->pat = regcomp(head);
- }
- if(metarules == 0)
- metarules = lmr = r;
- else {
- lmr->next = r;
- lmr = r;
- }
- } else {
- if(reuse)
- return;
- r->pat = 0;
- if(rules == 0)
- rules = lr = r;
- else {
- lr->next = r;
- lr = r;
- }
- }
-}
-
-void
-dumpr(char *s, Rule *r)
-{
- Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n",
- s, r, r->shellt->name, wtos(r->shellcmd, ' '));
- for(; r; r = r->next){
- Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'",
- r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));
- if(r->prog)
- Bprint(&bout, " prog='%s'", r->prog);
- Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, ' '));
- Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe);
- }
-}
-
-static int
-rcmp(Rule *r, char *target, Word *tail)
-{
- Word *w;
-
- if(strcmp(r->target, target))
- return 1;
- for(w = r->tail; w && tail; w = w->next, tail = tail->next)
- if(strcmp(w->s, tail->s))
- return 1;
- return(w || tail);
-}
-
-char *
-rulecnt(void)
-{
- char *s;
-
- s = Malloc(nrules);
- memset(s, 0, nrules);
- return(s);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/run.c
--- a/mk/run.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-#include "mk.h"
-
-typedef struct Event
-{
- int pid;
- Job *job;
-} Event;
-static Event *events;
-static int nevents, nrunning, nproclimit;
-
-typedef struct Process
-{
- int pid;
- int status;
- struct Process *b, *f;
-} Process;
-static Process *phead, *pfree;
-static void sched(void);
-static void pnew(int, int), pdelete(Process *);
-
-int pidslot(int);
-
-void
-run(Job *j)
-{
- Job *jj;
-
- if(jobs){
- for(jj = jobs; jj->next; jj = jj->next)
- ;
- jj->next = j;
- } else
- jobs = j;
- j->next = 0;
- /* this code also in waitup after parse redirect */
- if(nrunning < nproclimit)
- sched();
-}
-
-static void
-sched(void)
-{
- char *flags;
- Job *j;
- Bufblock *buf;
- int slot;
- Node *n;
- Envy *e;
-
- if(jobs == 0){
- usage();
- return;
- }
- j = jobs;
- jobs = j->next;
- if(DEBUG(D_EXEC))
- fprint(1, "firing up job for target %s\n", wtos(j->t, ' '));
- slot = nextslot();
- events[slot].job = j;
- buf = newbuf();
- e = buildenv(j, slot);
- shprint(j->r->recipe, e, buf, j->r->shellt);
- if(!tflag && (nflag || !(j->r->attr&QUIET)))
- Bwrite(&bout, buf->start, (long)strlen(buf->start));
- freebuf(buf);
- if(nflag||tflag){
- for(n = j->n; n; n = n->next){
- if(tflag){
- if(!(n->flags&VIRTUAL))
- touch(n->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s'\n", n->name);
- }
- n->time = time((long *)0);
- MADESET(n, MADE);
- }
- } else {
- if(DEBUG(D_EXEC))
- fprint(1, "recipe='%s'", j->r->recipe);/**/
- Bflush(&bout);
- if(j->r->attr&NOMINUSE)
- flags = 0;
- else
- flags = "-e";
- events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd);
- usage();
- nrunning++;
- if(DEBUG(D_EXEC))
- fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid);
- }
-}
-
-int
-waitup(int echildok, int *retstatus)
-{
- Envy *e;
- int pid;
- int slot;
- Symtab *s;
- Word *w;
- Job *j;
- char buf[ERRMAX];
- Bufblock *bp;
- int uarg = 0;
- int done;
- Node *n;
- Process *p;
- extern int runerrs;
-
- /* first check against the proces slist */
- if(retstatus)
- for(p = phead; p; p = p->f)
- if(p->pid == *retstatus){
- *retstatus = p->status;
- pdelete(p);
- return(-1);
- }
-again: /* rogue processes */
- pid = waitfor(buf);
- if(pid == -1){
- if(echildok > 0)
- return(1);
- else {
- fprint(2, "mk: (waitup %d): %r\n", echildok);
- Exit();
- }
- }
- if(DEBUG(D_EXEC))
- fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf);
- if(retstatus && pid == *retstatus){
- *retstatus = buf[0]? 1:0;
- return(-1);
- }
- slot = pidslot(pid);
- if(slot < 0){
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n", pid);
- pnew(pid, buf[0]? 1:0);
- goto again;
- }
- j = events[slot].job;
- usage();
- nrunning--;
- events[slot].pid = -1;
- if(buf[0]){
- e = buildenv(j, slot);
- bp = newbuf();
- shprint(j->r->recipe, e, bp, j->r->shellt);
- front(bp->start);
- fprint(2, "mk: %s: exit status=%s", bp->start, buf);
- freebuf(bp);
- for(n = j->n, done = 0; n; n = n->next)
- if(n->flags&DELETE){
- if(done++ == 0)
- fprint(2, ", deleting");
- fprint(2, " '%s'", n->name);
- delete(n->name);
- }
- fprint(2, "\n");
- if(kflag){
- runerrs++;
- uarg = 1;
- } else {
- jobs = 0;
- Exit();
- }
- }
- for(w = j->t; w; w = w->next){
- if((s = symlook(w->s, S_NODE, 0)) == 0)
- continue; /* not interested in this node */
- update(uarg, (Node *)s->value);
- }
- if(nrunning < nproclimit)
- sched();
- return(0);
-}
-
-void
-nproc(void)
-{
- Symtab *sym;
- Word *w;
-
- if(sym = symlook("NPROC", S_VAR, 0)) {
- w = (Word *) sym->value;
- if (w && w->s && w->s[0])
- nproclimit = atoi(w->s);
- }
- if(nproclimit < 1)
- nproclimit = 1;
- if(DEBUG(D_EXEC))
- fprint(1, "nprocs = %d\n", nproclimit);
- if(nproclimit > nevents){
- if(nevents)
- events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event));
- else
- events = (Event *)Malloc(nproclimit*sizeof(Event));
- while(nevents < nproclimit)
- events[nevents++].pid = 0;
- }
-}
-
-int
-nextslot(void)
-{
- int i;
-
- for(i = 0; i < nproclimit; i++)
- if(events[i].pid <= 0) return i;
- assert("out of slots!!", 0);
- return 0; /* cyntax */
-}
-
-int
-pidslot(int pid)
-{
- int i;
-
- for(i = 0; i < nevents; i++)
- if(events[i].pid == pid) return(i);
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n", pid);
- return(-1);
-}
-
-
-static void
-pnew(int pid, int status)
-{
- Process *p;
-
- if(pfree){
- p = pfree;
- pfree = p->f;
- } else
- p = (Process *)Malloc(sizeof(Process));
- p->pid = pid;
- p->status = status;
- p->f = phead;
- phead = p;
- if(p->f)
- p->f->b = p;
- p->b = 0;
-}
-
-static void
-pdelete(Process *p)
-{
- if(p->f)
- p->f->b = p->b;
- if(p->b)
- p->b->f = p->f;
- else
- phead = p->f;
- p->f = pfree;
- pfree = p;
-}
-
-void
-killchildren(char *msg)
-{
- Process *p;
-
- kflag = 1; /* to make sure waitup doesn't exit */
- jobs = 0; /* make sure no more get scheduled */
- for(p = phead; p; p = p->f)
- expunge(p->pid, msg);
- while(waitup(1, (int *)0) == 0)
- ;
- Bprint(&bout, "mk: %s\n", msg);
- Exit();
-}
-
-static long tslot[1000];
-static long tick;
-
-void
-usage(void)
-{
- long t;
-
- time(&t);
- if(tick)
- tslot[nrunning] += (t-tick);
- tick = t;
-}
-
-void
-prusage(void)
-{
- int i;
-
- usage();
- for(i = 0; i <= nevents; i++)
- fprint(1, "%d: %ld\n", i, tslot[i]);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/sh.c
--- a/mk/sh.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on the shell's syntax. Most
- * of the routines extract strings observing the shell's escape conventions.
- */
-
-
-/*
- * skip a token in quotes.
- */
-static char *
-squote(char *cp, int c)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == c)
- return cp;
- if(r == '\\')
- n += chartorune(&r, cp+n);
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-/*
- * search a string for unescaped characters in a pattern set
- */
-static char *
-shcharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\\': /* skip escaped char */
- cp += n;
- n = chartorune(&r, cp);
- break;
- case '\'': /* skip quoted string */
- case '"':
- cp = squote(cp+1, r); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash.
- */
-static char*
-shexpandquote(char *s, Rune esc, Bufblock *b)
-{
- Rune r;
-
- if (esc == '\\') {
- s += chartorune(&r, s);
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == esc)
- return s;
- if (r == '\\') {
- rinsert(b, r);
- s += chartorune(&r, s);
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash.
- */
-static int
-shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc == '\\') {
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c == '\n')
- mkinline++;
- rinsert(buf, c);
- return 1;
- }
-
- line = mkinline;
- while((c = nextrune(bp, 0)) >= 0){
- if(c == esc){
- if(preserve)
- rinsert(buf, c);
- return 1;
- }
- if(c == '\\') {
- rinsert(buf, c);
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if (c == '\n')
- mkinline++;
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Rune q, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == q)
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quotes above.
- * s points to char after opening quote, q.
- */
-static char *
-shcopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'' || q == '"') /* copy quoted string */
- return copysingle(s, q, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '`')
- break;
- if(q == '\'' || q == '"')
- s = copysingle(s, q, buf); /* copy quoted string */
- }
- return s;
-}
-
-static int
-shmatchname(char *name)
-{
- USED(name);
-
- return 1;
-}
-
-
-Shell shshell = {
- "sh",
- "\"'= \t", /*used in parse.c to isolate assignment attribute*/
- ' ', /* inter-word separator in env */
- shcharin,
- shexpandquote,
- shescapetoken,
- shcopyq,
- shmatchname,
-};
-
diff -r bb17f966e24a -r 1161d90df941 mk/shell.c
--- a/mk/shell.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-#include "mk.h"
-
-static Shell *shells[] = {
- &rcshell,
- &shshell,
-};
-
-Shell *shelldefault = &shshell;
-
-Shell *shellt;
-Word *shellcmd;
-
-typedef struct Shellstack Shellstack;
-struct Shellstack
-{
- Shell *t;
- Word *w;
- Shellstack *next;
-};
-
-Shellstack *shellstack;
-
-char*
-setshell(Word *w)
-{
- int i;
-
- if(w->s == nil)
- return "shell name not found on line";
-
- for(i=0; i<nelem(shells); i++)
- if(shells[i]->matchname(w->s))
- break;
- if(i == nelem(shells))
- return "cannot determine shell type";
- shellt = shells[i];
- shellcmd = w;
- return nil;
-}
-
-void
-initshell(void)
-{
- shellcmd = stow(shelldefault->name);
- shellt = shelldefault;
- setvar("MKSHELL", shellcmd);
-}
-
-void
-pushshell(void)
-{
- Shellstack *s;
-
- /* save */
- s = Malloc(sizeof *s);
- s->t = shellt;
- s->w = shellcmd;
- s->next = shellstack;
- shellstack = s;
-
- initshell(); /* reset to defaults */
-}
-
-void
-popshell(void)
-{
- Shellstack *s;
-
- if(shellstack == nil){
- fprint(2, "internal shellstack error\n");
- Exit();
- }
-
- s = shellstack;
- shellstack = s->next;
- shellt = s->t;
- shellcmd = s->w;
- setvar("MKSHELL", shellcmd);
- free(s);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/shprint.c
--- a/mk/shprint.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-#include "mk.h"
-
-static char *vexpand(char*, Envy*, Bufblock*);
-
-#define getfields mkgetfields
-
-static int
-getfields(char *str, char **args, int max, int mflag, char *set)
-{
- Rune r;
- int nr, intok, narg;
-
- if(max <= 0)
- return 0;
-
- narg = 0;
- args[narg] = str;
- if(!mflag)
- narg++;
- intok = 0;
- for(;; str += nr) {
- nr = chartorune(&r, str);
- if(r == 0)
- break;
- if(utfrune(set, r)) {
- if(narg >= max)
- break;
- *str = 0;
- intok = 0;
- args[narg] = str + nr;
- if(!mflag)
- narg++;
- } else {
- if(!intok && mflag)
- narg++;
- intok = 1;
- }
- }
- return narg;
-}
-
-void
-shprint(char *s, Envy *env, Bufblock *buf, Shell *sh)
-{
- int n;
- Rune r;
-
- while(*s) {
- n = chartorune(&r, s);
- if (r == '$')
- s = vexpand(s, env, buf);
- else {
- rinsert(buf, r);
- s += n;
- s = sh->copyq(s, r, buf); /*handle quoted strings*/
- }
- }
- insert(buf, 0);
-}
-
-static char *
-mygetenv(char *name, Envy *env)
-{
- if (!env)
- return 0;
- if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0)
- return 0;
- /* only resolve internal variables and variables we've set */
- for(; env->name; env++){
- if (strcmp(env->name, name) == 0)
- return wtos(env->values, ' ');
- }
- return 0;
-}
-
-static char *
-vexpand(char *w, Envy *env, Bufblock *buf)
-{
- char *s, carry, *p, *q;
-
- assert("vexpand no $", *w == '$');
- p = w+1; /* skip dollar sign */
- if(*p == '{') {
- p++;
- q = utfrune(p, '}');
- if (!q)
- q = strchr(p, 0);
- } else
- q = shname(p);
- carry = *q;
- *q = 0;
- s = mygetenv(p, env);
- *q = carry;
- if (carry == '}')
- q++;
- if (s) {
- bufcpy(buf, s, strlen(s));
- free(s);
- } else /* copy name intact*/
- bufcpy(buf, w, q-w);
- return(q);
-}
-
-void
-front(char *s)
-{
- char *t, *q;
- int i, j;
- char *flds[512];
-
- q = strdup(s);
- i = getfields(q, flds, 512, 0, " \t\n");
- if(i > 5){
- flds[4] = flds[i-1];
- flds[3] = "...";
- i = 5;
- }
- t = s;
- for(j = 0; j < i; j++){
- for(s = flds[j]; *s; *t++ = *s++);
- *t++ = ' ';
- }
- *t = 0;
- free(q);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/symtab.c
--- a/mk/symtab.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-#include "mk.h"
-
-#define NHASH 4099
-#define HASHMUL 79L /* this is a good value */
-static Symtab *hash[NHASH];
-
-void
-syminit(void)
-{
- Symtab **s, *ss, *next;
-
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s; ss; ss = next){
- next = ss->next;
- free((char *)ss);
- }
- *s = 0;
- }
-}
-
-Symtab *
-symlook(char *sym, int space, void *install)
-{
- long h;
- char *p;
- Symtab *s;
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h]; s; s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0))
- return(s);
- if(install == 0)
- return(0);
- s = (Symtab *)Malloc(sizeof(Symtab));
- s->space = space;
- s->name = sym;
- s->value = install;
- s->next = hash[h];
- hash[h] = s;
- return(s);
-}
-
-void
-symdel(char *sym, int space)
-{
- long h;
- char *p;
- Symtab *s, *ls;
-
- /* multiple memory leaks */
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h], ls = 0; s; ls = s, s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0)){
- if(ls)
- ls->next = s->next;
- else
- hash[h] = s->next;
- free((char *)s);
- }
-}
-
-void
-symtraverse(int space, void (*fn)(Symtab*))
-{
- Symtab **s, *ss;
-
- for(s = hash; s < &hash[NHASH]; s++)
- for(ss = *s; ss; ss = ss->next)
- if(ss->space == space)
- (*fn)(ss);
-}
-
-void
-symstat(void)
-{
- Symtab **s, *ss;
- int n;
- int l[1000];
-
- memset((char *)l, 0, sizeof(l));
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s, n = 0; ss; ss = ss->next)
- n++;
- l[n]++;
- }
- for(n = 0; n < 1000; n++)
- if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n);
-}
diff -r bb17f966e24a -r 1161d90df941 mk/sys.h
--- a/mk/sys.h Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <regexp.h>
-
diff -r bb17f966e24a -r 1161d90df941 mk/sys.std.h
--- a/mk/sys.std.h Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#include <utf.h>
-#include <fmt.h>
-#include <bio.h>
-#include <regexp9.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#define OREAD O_RDONLY
-#define OWRITE O_WRONLY
-#define ORDWR O_RDWR
-#define nil 0
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define seek lseek
-#define remove unlink
-#define exits(x) exit(x && *(char*)x ? 1 : 0)
-#define USED(x) if(x){}else
-#define create(name, mode, perm) open(name, mode|O_CREAT, perm)
-#define ERRMAX 256
diff -r bb17f966e24a -r 1161d90df941 mk/unix.c
--- a/mk/unix.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-#define NOPLAN9DEFINES
-#include "mk.h"
-#include <sys/wait.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-char *shell = "/bin/sh";
-char *shellname = "sh";
-
-extern char **environ;
-
-static void
-mkperror(char *s)
-{
- fprint(2, "%s: %r\n", s);
-}
-
-void
-readenv(void)
-{
- char **p, *s;
- Word *w;
-
- for(p = environ; *p; p++){
-/* rsc 5/5/2004 -- This misparses fn#cd={whatever}
- s = shname(*p);
- if(*s == '=') {
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
-*/
- s = strchr(*p, '=');
- if(s){
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
- if (symlook(*p, S_INTERNAL, 0))
- continue;
- s = strdup(*p);
- setvar(s, (void *)w);
- symlook(s, S_EXPORTED, (void*)"")->value = (void*)"";
- }
-}
-
-/*
- * done on child side of fork, so parent's env is not affected
- * and we don't care about freeing memory because we're going
- * to exec immediately after this.
- */
-void
-exportenv(Envy *e, Shell *sh)
-{
- int i;
- char **p;
- static char buf[16384];
-
- p = 0;
- for(i = 0; e->name; e++, i++) {
- p = (char**) Realloc(p, (i+2)*sizeof(char*));
- if(e->values)
- snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, sh->iws));
- else
- snprint(buf, sizeof buf, "%s=", e->name);
- p[i] = strdup(buf);
- }
- p[i] = 0;
- environ = p;
-}
-
-int
-waitfor(char *msg)
-{
- int status;
- int pid;
-
- *msg = 0;
- pid = wait(&status);
- if(pid > 0) {
- if(status&0x7f) {
- if(status&0x80)
- snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f);
- else
- snprint(msg, ERRMAX, "signal %d", status&0x7f);
- } else if(status&0xff00)
- snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff);
- }
- return pid;
-}
-
-void
-expunge(int pid, char *msg)
-{
- if(strcmp(msg, "interrupt"))
- kill(pid, SIGINT);
- else
- kill(pid, SIGHUP);
-}
-
-int mypid;
-
-int
-shargv(Word *cmd, int extra, char ***pargv)
-{
- char **argv;
- int i, n;
- Word *w;
-
- n = 0;
- for(w=cmd; w; w=w->next)
- n++;
-
- argv = Malloc((n+extra+1)*sizeof(argv[0]));
- i = 0;
- for(w=cmd; w; w=w->next)
- argv[i++] = w->s;
- argv[n] = 0;
- *pargv = argv;
- return n;
-}
-
-int
-execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd)
-{
- char *p, **argv;
- int tot, n, pid, in[2], out[2];
-
- if(buf && pipe(out) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- mypid = getpid();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(buf)
- close(out[0]);
- if(pipe(in) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid != 0){
- dup2(in[0], 0);
- if(buf){
- dup2(out[1], 1);
- close(out[1]);
- }
- close(in[0]);
- close(in[1]);
- if (e)
- exportenv(e, sh);
- n = shargv(shellcmd, 1, &argv);
- argv[n++] = args;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- close(out[1]);
- close(in[0]);
- if(DEBUG(D_EXEC))
- fprint(1, "starting: %s\n", cmd);
- p = cmd+strlen(cmd);
- while(cmd < p){
- n = write(in[1], cmd, p-cmd);
- if(n < 0)
- break;
- cmd += n;
- }
- close(in[1]);
- _exit(0);
- }
- if(buf){
- close(out[1]);
- tot = 0;
- for(;;){
- if (buf->current >= buf->end)
- growbuf(buf);
- n = read(out[0], buf->current, buf->end-buf->current);
- if(n <= 0)
- break;
- buf->current += n;
- tot += n;
- }
- if (tot && buf->current[-1] == '\n')
- buf->current--;
- close(out[0]);
- }
- return pid;
-}
-
-int
-pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd)
-{
- int pid, pfd[2];
- int n;
- char **argv;
-
- if(DEBUG(D_EXEC))
- fprint(1, "pipecmd='%s'\n", cmd);/**/
-
- if(fd && pipe(pfd) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(fd){
- close(pfd[0]);
- dup2(pfd[1], 1);
- close(pfd[1]);
- }
- if(e)
- exportenv(e, sh);
- n = shargv(shellcmd, 2, &argv);
- argv[n++] = "-c";
- argv[n++] = cmd;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- if(fd){
- close(pfd[1]);
- *fd = pfd[0];
- }
- return pid;
-}
-
-void
-Exit(void)
-{
- while(wait(0) >= 0)
- ;
- exits("error");
-}
-
-static struct
-{
- int sig;
- char *msg;
-} sigmsgs[] =
-{
- SIGALRM, "alarm",
- SIGFPE, "sys: fp: fptrap",
- SIGPIPE, "sys: write on closed pipe",
- SIGILL, "sys: trap: illegal instruction",
-// SIGSEGV, "sys: segmentation violation",
- 0, 0
-};
-
-static void
-notifyf(int sig)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- if(sigmsgs[i].sig == sig)
- killchildren(sigmsgs[i].msg);
-
- /* should never happen */
- signal(sig, SIG_DFL);
- kill(getpid(), sig);
-}
-
-void
-catchnotes(void)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- signal(sigmsgs[i].sig, notifyf);
-}
-
-char*
-maketmp(int *pfd)
-{
- static char temp[] = "/tmp/mkargXXXXXX";
- static char buf[100];
- int fd;
-
- strcpy(buf, temp);
- fd = mkstemp(buf);
- if(fd < 0)
- return 0;
- *pfd = fd;
- return buf;
-}
-
-int
-chgtime(char *name)
-{
- if(access(name, 0) >= 0)
- return utimes(name, 0);
- return close(creat(name, 0666));
-}
-
-void
-rcopy(char **to, Resub *match, int n)
-{
- int c;
- char *p;
-
- *to = match->s.sp; /* stem0 matches complete target */
- for(to++, match++; --n > 0; to++, match++){
- if(match->s.sp && match->e.ep){
- p = match->e.ep;
- c = *p;
- *p = 0;
- *to = strdup(match->s.sp);
- *p = c;
- }
- else
- *to = 0;
- }
-}
-
-unsigned long
-mkmtime(char *name)
-{
- struct stat st;
-
- if(stat(name, &st) < 0)
- return 0;
-
- return st.st_mtime;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/var.c
--- a/mk/var.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#include "mk.h"
-
-void
-setvar(char *name, void *value)
-{
- symlook(name, S_VAR, value)->value = value;
- symlook(name, S_MAKEVAR, (void*)"");
-}
-
-static void
-print1(Symtab *s)
-{
- Word *w;
-
- Bprint(&bout, "\t%s=", s->name);
- for (w = (Word *) s->value; w; w = w->next)
- Bprint(&bout, "'%s'", w->s);
- Bprint(&bout, "\n");
-}
-
-void
-dumpv(char *s)
-{
- Bprint(&bout, "%s:\n", s);
- symtraverse(S_VAR, print1);
-}
-
-char *
-shname(char *a)
-{
- Rune r;
- int n;
-
- while (*a) {
- n = chartorune(&r, a);
- if (!WORDCHR(r))
- break;
- a += n;
- }
- return a;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/varsub.c
--- a/mk/varsub.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-#include "mk.h"
-
-static Word *subsub(Word*, char*, char*);
-static Word *expandvar(char**);
-static Bufblock *varname(char**);
-static Word *extractpat(char*, char**, char*, char*);
-static int submatch(char*, Word*, Word*, int*, char**);
-static Word *varmatch(char *, char**);
-
-Word *
-varsub(char **s)
-{
- Bufblock *b;
- Word *w;
-
- if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
- return expandvar(s);
-
- b = varname(s);
- if(b == 0)
- return 0;
-
- w = varmatch(b->start, s);
- freebuf(b);
- return w;
-}
-
-/*
- * extract a variable name
- */
-static Bufblock*
-varname(char **s)
-{
- Bufblock *b;
- char *cp;
- Rune r;
- int n;
-
- b = newbuf();
- cp = *s;
- for(;;){
- n = chartorune(&r, cp);
- if (!WORDCHR(r))
- break;
- rinsert(b, r);
- cp += n;
- }
- if (b->current == b->start){
- SYNERR(-1);
- fprint(2, "missing variable name <%s>\n", *s);
- freebuf(b);
- return 0;
- }
- *s = cp;
- insert(b, 0);
- return b;
-}
-
-static Word*
-varmatch(char *name, char **s)
-{
- Word *w;
- Symtab *sym;
- char *cp;
-
- sym = symlook(name, S_VAR, 0);
- if(sym){
- /* check for at least one non-NULL value */
- for (w = (Word*)sym->value; w; w = w->next)
- if(w->s && *w->s)
- return wdup(w);
- }
- for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */
- ;
- *s = cp;
- return 0;
-}
-
-static Word*
-expandvar(char **s)
-{
- Word *w;
- Bufblock *buf;
- Symtab *sym;
- char *cp, *begin, *end;
-
- begin = *s;
- (*s)++; /* skip the '{' */
- buf = varname(s);
- if (buf == 0)
- return 0;
- cp = *s;
- if (*cp == '}') { /* ${name} variant*/
- (*s)++; /* skip the '}' */
- w = varmatch(buf->start, s);
- freebuf(buf);
- return w;
- }
- if (*cp != ':') {
- SYNERR(-1);
- fprint(2, "bad variable name <%s>\n", buf->start);
- freebuf(buf);
- return 0;
- }
- cp++;
- end = shellt->charin(cp , "}");
- if(end == 0){
- SYNERR(-1);
- fprint(2, "missing '}': %s\n", begin);
- Exit();
- }
- *end = 0;
- *s = end+1;
-
- sym = symlook(buf->start, S_VAR, 0);
- if(sym == 0 || sym->value == 0)
- w = newword(buf->start);
- else
- w = subsub((Word*) sym->value, cp, end);
- freebuf(buf);
- return w;
-}
-
-static Word*
-extractpat(char *s, char **r, char *term, char *end)
-{
- int save;
- char *cp;
- Word *w;
-
- cp = shellt->charin(s, term);
- if(cp){
- *r = cp;
- if(cp == s)
- return 0;
- save = *cp;
- *cp = 0;
- w = stow(s);
- *cp = save;
- } else {
- *r = end;
- w = stow(s);
- }
- return w;
-}
-
-static Word*
-subsub(Word *v, char *s, char *end)
-{
- int nmid;
- Word *head, *tail, *w, *h;
- Word *a, *b, *c, *d;
- Bufblock *buf;
- char *cp, *enda;
-
- a = extractpat(s, &cp, "=%&", end);
- b = c = d = 0;
- if(PERCENT(*cp))
- b = extractpat(cp+1, &cp, "=", end);
- if(*cp == '=')
- c = extractpat(cp+1, &cp, "&%", end);
- if(PERCENT(*cp))
- d = stow(cp+1);
- else if(*cp)
- d = stow(cp);
-
- head = tail = 0;
- buf = newbuf();
- for(; v; v = v->next){
- h = w = 0;
- if(submatch(v->s, a, b, &nmid, &enda)){
- /* enda points to end of A match in source;
- * nmid = number of chars between end of A and start of B
- */
- if(c){
- h = w = wdup(c);
- while(w->next)
- w = w->next;
- }
- if(PERCENT(*cp) && nmid > 0){
- if(w){
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- } else {
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- h = w = newword(buf->start);
- }
- buf->current = buf->start;
- }
- if(d && *d->s){
- if(w){
-
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, d->s, strlen(d->s));
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- w->next = wdup(d->next);
- while(w->next)
- w = w->next;
- buf->current = buf->start;
- } else
- h = w = wdup(d);
- }
- }
- if(w == 0)
- h = w = newword(v->s);
-
- if(head == 0)
- head = h;
- else
- tail->next = h;
- tail = w;
- }
- freebuf(buf);
- delword(a);
- delword(b);
- delword(c);
- delword(d);
- return head;
-}
-
-static int
-submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
-{
- Word *w;
- int n;
- char *end;
-
- n = 0;
- for(w = a; w; w = w->next){
- n = strlen(w->s);
- if(strncmp(s, w->s, n) == 0)
- break;
- }
- if(a && w == 0) /* a == NULL matches everything*/
- return 0;
-
- *enda = s+n; /* pointer to end a A part match */
- *nmid = strlen(s)-n; /* size of remainder of source */
- end = *enda+*nmid;
- for(w = b; w; w = w->next){
- n = strlen(w->s);
- if(strcmp(w->s, end-n) == 0){
- *nmid -= n;
- break;
- }
- }
- if(b && w == 0) /* b == NULL matches everything */
- return 0;
- return 1;
-}
diff -r bb17f966e24a -r 1161d90df941 mk/word.c
--- a/mk/word.c Thu Feb 09 13:39:50 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-#include "mk.h"
-
-static Word *nextword(char**);
-
-Word*
-newword(char *s)
-{
- Word *w;
-
- w = (Word *)Malloc(sizeof(Word));
- w->s = strdup(s);
- w->next = 0;
- return(w);
-}
-
-Word *
-stow(char *s)
-{
- Word *head, *w, *new;
-
- w = head = 0;
- while(*s){
- new = nextword(&s);
- if(new == 0)
- break;
- if (w)
- w->next = new;
- else
- head = w = new;
- while(w->next)
- w = w->next;
-
- }
- if (!head)
- head = newword("");
- return(head);
-}
-
-char *
-wtos(Word *w, int sep)
-{
- Bufblock *buf;
- char *cp;
-
- buf = newbuf();
- for(; w; w = w->next){
- for(cp = w->s; *cp; cp++)
- insert(buf, *cp);
- if(w->next)
- insert(buf, sep);
- }
- insert(buf, 0);
- cp = strdup(buf->start);
- freebuf(buf);
- return(cp);
-}
-
-Word*
-wdup(Word *w)
-{
- Word *v, *new, *base;
-
- v = base = 0;
- while(w){
- new = newword(w->s);
- if(v)
- v->next = new;
- else
- base = new;
- v = new;
- w = w->next;
- }
- return base;
-}
-
-void
-delword(Word *w)
-{
- Word *v;
-
- while(v = w){
- w = w->next;
- if(v->s)
- free(v->s);
- free(v);
- }
-}
-
-/*
- * break out a word from a string handling quotes, executions,
- * and variable expansions.
- */
-static Word*
-nextword(char **s)
-{
- Bufblock *b;
- Word *head, *tail, *w;
- Rune r;
- char *cp;
-
- cp = *s;
- b = newbuf();
- head = tail = 0;
- while(*cp == ' ' || *cp == '\t') /* leading white space */
- cp++;
- while(*cp){
- cp += chartorune(&r, cp);
- switch(r)
- {
- case ' ':
- case '\t':
- case '\n':
- goto out;
- case '\\':
- case '\'':
- case '"':
- cp = shellt->expandquote(cp, r, b);
- if(cp == 0){
- fprint(2, "missing closing quote: %s\n", *s);
- Exit();
- }
- break;
- case '$':
- w = varsub(&cp);
- if(w == 0)
- break;
- if(b->current != b->start){
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(w->s);
- w->s = strdup(b->start);
- b->current = b->start;
- }
- if(head){
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(b->start);
- tail->next = w->next;
- free(w->s);
- free(w);
- b->current = b->start;
- } else
- tail = head = w;
- while(tail->next)
- tail = tail->next;
- break;
- default:
- rinsert(b, r);
- break;
- }
- }
-out:
- *s = cp;
- if(b->current != b->start){
- if(head){
- cp = b->current;
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, b->start, cp-b->start);
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(cp);
- } else {
- insert(b, 0);
- head = newword(b->start);
- }
- }
- freebuf(b);
- return head;
-}
-
-void
-dumpw(char *s, Word *w)
-{
- Bprint(&bout, "%s", s);
- for(; w; w = w->next)
- Bprint(&bout, " '%s'", w->s);
- Bputc(&bout, '\n');
-}
diff -r bb17f966e24a -r 1161d90df941 rc/Makefile
--- a/rc/Makefile Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/Makefile Fri Jul 31 21:02:58 2009 +0100
@@ -4,7 +4,7 @@
 TARG = rc
 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 unixcrap.o \
- var.o y.tab.o plan9ish.o
+ var.o y.tab.o plan9ish.o havefork.o
 YFILES = syn.y
 MANFILES = rc.1
 
@@ -23,6 +23,7 @@
 depend:
         @echo YACC ${YFILES}
         @${YACC} -d ${YFILES}
+ @cp y.tab.h x.tab.h
 
 install: ${TARG}
         @mkdir -p ${DESTDIR}${PREFIX}/bin
diff -r bb17f966e24a -r 1161d90df941 rc/code.c
--- a/rc/code.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/code.c Fri Jul 31 21:02:58 2009 +0100
@@ -7,9 +7,9 @@
 #define c1 t->child[1]
 #define c2 t->child[2]
 int codep, ncode;
-#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
-#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
-#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
+#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
+#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
+#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
 void stuffdot(int);
 char *fnstr(tree*);
 void outcode(tree*, int);
@@ -17,22 +17,33 @@
 int iscase(tree*);
 code *codecopy(code*);
 void codefree(code*);
-int morecode(void){
+
+int
+morecode(void)
+{
         ncode+=100;
- codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
- if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
+ codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
                                 ncode*sizeof codebuf[0]);
+ memset(codebuf+ncode-100, 0, 100*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;
+
+void
+stuffdot(int a)
+{
+ if(a<0 || codep<=a)
+ panic("Bad address %d in stuffdot", a);
+ codebuf[a].i = codep;
 }
-int compile(tree *t)
+
+int
+compile(tree *t)
 {
- ncode=100;
- codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
- codep=0;
+ ncode = 100;
+ codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+ codep = 0;
         emiti(0); /* reference count */
         outcode(t, flag['e']?1:0);
         if(nerror){
@@ -44,31 +55,39 @@
         emitf(0);
         return 1;
 }
-void cleanhere(char *f)
+
+void
+cleanhere(char *f)
 {
         emitf(Xdelhere);
         emits(strdup(f));
 }
-char *fnstr(tree *t)
+
+char*
+fnstr(tree *t)
 {
- io *f=openstr();
+ io *f = openstr();
         char *v;
         extern char nl;
- char svnl=nl;
+ char svnl = nl;
         nl=';';
         pfmt(f, "%t", t);
- nl=svnl;
- v=f->strp;
- f->strp=0;
+ nl = svnl;
+ v = f->strp;
+ f->strp = 0;
         closeio(f);
         return v;
 }
-void outcode(tree *t, int eflag)
+
+void
+outcode(tree *t, int eflag)
 {
         int p, q;
         tree *tt;
- if(t==0) return;
- if(t->type!=NOT && t->type!=';') runq->iflast=0;
+ if(t==0)
+ return;
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast = 0;
         switch(t->type){
         default:
                 pfmt(err, "bad type %d in outcode\n", t->type);
@@ -92,10 +111,13 @@
                 break;
         case '&':
                 emitf(Xasync);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
                 break;
         case ';':
                 outcode(c0, eflag);
@@ -110,15 +132,18 @@
                 break;
         case '`':
                 emitf(Xbackq);
- p=emiti(0);
- outcode(c0, 0);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
                 break;
         case ANDAND:
                 outcode(c0, 0);
                 emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
                 outcode(c1, eflag);
                 stuffdot(p);
                 break;
@@ -144,7 +169,7 @@
                 outcode(c0, eflag);
                 if(c1){
                         emitf(Xfn);
- p=emiti(0);
+ p = emiti(0);
                         emits(fnstr(c1));
                         outcode(c1, eflag);
                         emitf(Xunlocal); /* get rid of $* */
@@ -157,22 +182,23 @@
         case IF:
                 outcode(c0, 0);
                 emitf(Xif);
- p=emiti(0);
+ p = emiti(0);
                 outcode(c1, eflag);
                 emitf(Xwastrue);
                 stuffdot(p);
                 break;
         case NOT:
- if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
+ if(!runq->iflast)
+ yyerror("`if not' does not follow `if(...)'");
                 emitf(Xifnot);
- p=emiti(0);
+ p = emiti(0);
                 outcode(c0, eflag);
                 stuffdot(p);
                 break;
         case OROR:
                 outcode(c0, 0);
                 emitf(Xfalse);
- p=emiti(0);
+ p = emiti(0);
                 outcode(c1, eflag);
                 stuffdot(p);
                 break;
@@ -183,15 +209,20 @@
                 emitf(Xmark);
                 outcode(c0, eflag);
                 emitf(Xsimple);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
                 break;
         case SUBSHELL:
                 emitf(Xsubshell);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- if(eflag) emitf(Xeflag);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
+ if(eflag)
+ emitf(Xeflag);
                 break;
         case SWITCH:
                 codeswitch(t, eflag);
@@ -202,14 +233,16 @@
                 emitf(Xmark);
                 outcode(c0, eflag);
                 emitf(Xmatch);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
                 break;
         case WHILE:
- q=codep;
+ q = codep;
                 outcode(c0, 0);
- if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */
+ if(q==codep)
+ emitf(Xsettrue); /* empty condition == while(true) */
                 emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
                 outcode(c1, eflag);
                 emitf(Xjump);
                 emiti(q);
@@ -235,8 +268,8 @@
                 emitf(Xmark);
                 outcode(c0, eflag);
                 emitf(Xlocal);
- p=emitf(Xfor);
- q=emiti(0);
+ p = emitf(Xfor);
+ q = emiti(0);
                 outcode(c2, eflag);
                 emitf(Xjump);
                 emiti(p);
@@ -263,10 +296,14 @@
         case PIPEFD:
                 emitf(Xpipefd);
                 emiti(t->rtype);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
                 break;
         case REDIR:
                 emitf(Xmark);
@@ -283,28 +320,31 @@
                 case HERE:
                         emitf(Xread);
                         break;
+ case RDWR:
+ emitf(Xrdwr);
+ break;
                 }
                 emiti(t->fd0);
                 outcode(c1, eflag);
                 emitf(Xpopredir);
                 break;
         case '=':
- tt=t;
- for(;t && t->type=='=';t=c2);
+ tt = t;
+ for(;t && t->type=='=';t = c2);
                 if(t){
- for(t=tt;t->type=='=';t=c2){
+ for(t = tt;t->type=='=';t = c2){
                                 emitf(Xmark);
                                 outcode(c1, eflag);
                                 emitf(Xmark);
                                 outcode(c0, eflag);
                                 emitf(Xlocal);
                         }
- t=tt;
- outcode(c2, eflag);
- for(;t->type=='=';t=c2) emitf(Xunlocal);
+ outcode(t, eflag);
+ for(t = tt; t->type=='='; t = c2)
+ emitf(Xunlocal);
                 }
                 else{
- for(t=tt;t;t=c2){
+ for(t = tt;t;t = c2){
                                 emitf(Xmark);
                                 outcode(c1, eflag);
                                 emitf(Xmark);
@@ -312,17 +352,22 @@
                                 emitf(Xassign);
                         }
                 }
- t=tt; /* so tests below will work */
+ t = tt; /* so tests below will work */
                 break;
         case PIPE:
                 emitf(Xpipe);
                 emiti(t->fd0);
                 emiti(t->fd1);
- p=emiti(0);
- q=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ q = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ q = emiti(0);
+ }
                 outcode(c1, eflag);
                 emitf(Xreturn);
                 stuffdot(q);
@@ -330,8 +375,8 @@
                 break;
         }
         if(t->type!=NOT && t->type!=';')
- runq->iflast=t->type==IF;
- else if(c0) runq->iflast=c0->type==IF;
+ runq->iflast = t->type==IF;
+ else if(c0) runq->iflast = c0->type==IF;
 }
 /*
  * switch code looks like this:
@@ -353,7 +398,9 @@
  * leave:
  * Xpopm
  */
-void codeswitch(tree *t, int eflag)
+
+void
+codeswitch(tree *t, int eflag)
 {
         int leave; /* patch jump address to leave switch */
         int out; /* jump here to leave switch */
@@ -368,23 +415,23 @@
         emitf(Xmark);
         outcode(c0, eflag);
         emitf(Xjump);
- nextcase=emiti(0);
- out=emitf(Xjump);
- leave=emiti(0);
+ nextcase = emiti(0);
+ out = emitf(Xjump);
+ leave = emiti(0);
         stuffdot(nextcase);
- t=c1->child[0];
+ t = c1->child[0];
         while(t->type==';'){
- tt=c1;
+ tt = c1;
                 emitf(Xmark);
- for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
+ for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
                 emitf(Xcase);
- nextcase=emiti(0);
- t=tt;
+ nextcase = emiti(0);
+ t = tt;
                 for(;;){
                         if(t->type==';'){
                                 if(iscase(c0)) break;
                                 outcode(c0, eflag);
- t=c1;
+ t = c1;
                         }
                         else{
                                 if(!iscase(t)) outcode(t, eflag);
@@ -398,23 +445,32 @@
         stuffdot(leave);
         emitf(Xpopm);
 }
-int iscase(tree *t)
+
+int
+iscase(tree *t)
 {
- if(t->type!=SIMPLE) return 0;
- do t=c0; while(t->type==ARGLIST);
+ 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)
+
+code*
+codecopy(code *cp)
 {
         cp[0].i++;
         return cp;
 }
-void codefree(code *cp)
+
+void
+codefree(code *cp)
 {
         code *p;
- if(--cp[0].i!=0) return;
- for(p=cp+1;p->f;p++){
+ if(--cp[0].i!=0)
+ return;
+ for(p = cp+1;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==Xsubshell || p->f==Xtrue) p++;
diff -r bb17f966e24a -r 1161d90df941 rc/exec.c
--- a/rc/exec.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/exec.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,12 +1,3 @@
-#include <u.h>
-#include <signal.h>
-#if defined(PLAN9PORT) && defined(__sun__)
-# define BSD_COMP /* sigh. for TIOCNOTTY */
-#endif
-#ifdef __sun__
-#include <sys/termios.h>
-#endif
-#include <sys/ioctl.h>
 #include "rc.h"
 #include "getflags.h"
 #include "exec.h"
@@ -16,90 +7,118 @@
  * Start executing the given code at the given pc with the given redirection
  */
 char *argv0="rc";
-void start(code *c, int pc, var *local)
+
+void
+start(code *c, int pc, var *local)
 {
- struct thread *p=new(struct thread);
- p->code=codecopy(c);
- p->pc=pc;
- p->argv=0;
- p->redir=p->startredir=runq?runq->redir:0;
- p->local=local;
- p->cmdfile=0;
- p->cmdfd=0;
- p->eof=0;
- p->iflag=0;
- p->lineno=1;
- p->pid=-1;
- p->ret=runq;
- runq=p;
+ struct thread *p = new(struct thread);
+
+ p->code = codecopy(c);
+ p->pc = pc;
+ p->argv = 0;
+ p->redir = p->startredir = runq?runq->redir:0;
+ p->local = local;
+ p->cmdfile = 0;
+ p->cmdfd = 0;
+ p->eof = 0;
+ p->iflag = 0;
+ p->lineno = 1;
+ p->ret = runq;
+ runq = p;
 }
-word *newword(char *wd, word *next)
+
+word*
+newword(char *wd, word *next)
 {
- word *p=new(word);
- p->word=strdup(wd);
- p->next=next;
+ word *p = new(word);
+ p->word = strdup(wd);
+ p->next = next;
         return p;
 }
-void pushword(char *wd)
+
+void
+pushword(char *wd)
 {
- if(runq->argv==0) panic("pushword but no argv!", 0);
- runq->argv->words=newword(wd, runq->argv->words);
+ if(runq->argv==0)
+ panic("pushword but no argv!", 0);
+ runq->argv->words = newword(wd, runq->argv->words);
 }
-void popword(void){
+
+void
+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;
+ 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;
         efree(p->word);
         efree((char *)p);
 }
-void freelist(word *w)
+
+void
+freelist(word *w)
 {
         word *nw;
         while(w){
- nw=w->next;
+ nw = w->next;
                 efree(w->word);
                 efree((char *)w);
- w=nw;
+ w = nw;
         }
 }
-void pushlist(void){
- list *p=new(list);
- p->next=runq->argv;
- p->words=0;
- runq->argv=p;
+
+void
+pushlist(void)
+{
+ list *p = new(list);
+ p->next = runq->argv;
+ p->words = 0;
+ runq->argv = p;
 }
-void poplist(void){
- list *p=runq->argv;
- if(p==0) panic("poplist but no argv", 0);
+
+void
+poplist(void)
+{
+ list *p = runq->argv;
+ if(p==0)
+ panic("poplist but no argv", 0);
         freelist(p->words);
- runq->argv=p->next;
+ runq->argv = p->next;
         efree((char *)p);
 }
-int count(word *w)
+
+int
+count(word *w)
 {
         int n;
- for(n=0;w;n++) w=w->next;
+ 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;
+
+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;
 }
-var *newvar(char *name, var *next)
+
+var*
+newvar(char *name, var *next)
 {
- var *v=new(var);
- v->name=name;
- v->val=0;
- v->fn=0;
- v->changed=0;
- v->fnchanged=0;
- v->next=next;
+ var *v = new(var);
+ v->name = name;
+ v->val = 0;
+ v->fn = 0;
+ v->changed = 0;
+ v->fnchanged = 0;
+ v->next = next;
         v->changefn = 0;
         return v;
 }
@@ -117,52 +136,59 @@
         char num[12], *rcmain;
         int i;
         
- argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
- if(argc==-1) usage("[file [arg ...]]");
- if(argv[0][0]=='-') flag['l']=flagset;
- if(flag['I']) flag['i'] = 0;
+ /* needed for rcmain later */
+ putenv("PLAN9", unsharp("#9"));
+
+ argc = getflags(argc, argv, "SsrdiIlxepvVc: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;
- rcmain=flag['m']?flag['m'][0]:Rcmain();
- err=openfd(2);
+ rcmain = flag['m'] ? flag['m'][0] : Rcmain();
+ err = openfd(2);
         kinit();
         Trapinit();
         Vinit();
- itoa(num, mypid=getpid());
+ inttoascii(num, mypid = getpid());
         pathinit();
         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;
- bootstrap[i++].i=1;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xword;
+ i = 0;
+ 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++].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++].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;
+ bootstrap[i++].f = Xsimple;
+ bootstrap[i++].f = Xexit;
+ bootstrap[i].i = 0;
         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);
+ if(flag['r'])
+ pfnc(err, runq);
                 runq->pc++;
                 (*runq->code[runq->pc-1].f)();
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
         }
- return 0;
 }
 /*
  * Opcode routines
@@ -198,6 +224,7 @@
  * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
  * depending on type), push /dev/fd/??
  * Xpopm(value) pop value from stack
+ * Xrdwr(file)[fd] open file for reading and writing
  * Xread(file)[fd] open file to read
  * Xsettraps(names){... Xreturn} define trap functions
  * Xshowtraps print trap list
@@ -209,16 +236,24 @@
  * Xword[string] push string
  * Xwrite(file)[fd] open file to write
  */
-void Xappend(void){
+
+void
+Xappend(void)
+{
         char *file;
         int f;
         switch(count(runq->argv->words)){
- default: Xerror1(">> requires singleton"); return;
- case 0: Xerror1(">> requires file"); return;
- case 1: break;
+ default:
+ Xerror1(">> requires singleton");
+ return;
+ case 0:
+ Xerror1(">> requires file");
+ return;
+ case 1:
+ break;
         }
- file=runq->argv->words->word;
- if((f=open(file, 1))<0 && (f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 1))<0 && (f = Creat(file))<0){
                 pfmt(err, "%s: ", file);
                 Xerror("can't open");
                 return;
@@ -228,126 +263,114 @@
         runq->pc++;
         poplist();
 }
-void Xasync(void){
- int null=open("/dev/null", 0);
- int tty;
- int pid;
- char npid[10];
- if(null<0){
- Xerror("Can't open /dev/null\n");
- return;
- }
- switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
- case -1:
- close(null);
- Xerror("try again");
- break;
- case 0:
- /*
- * I don't know what the right thing to do here is,
- * so this is all experimentally determined.
- * If we just dup /dev/null onto 0, then running
- * ssh foo & will reopen /dev/tty, try to read a password,
- * get a signal, and repeat, in a tight loop, forever.
- * Arguably this is a bug in ssh (it behaves the same
- * way under bash as under rc) but I'm fixing it here
- * anyway. If we dissociate the process from the tty,
- * then it won't be able to open /dev/tty ever again.
- * The SIG_IGN on SIGTTOU makes writing the tty
- * (via fd 1 or 2, for example) succeed even though
- * our pgrp is not the terminal's controlling pgrp.
- */
- if((tty=open("/dev/tty", OREAD)) >= 0){
- /*
- * Should make reads of tty fail, writes succeed.
- */
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- ioctl(tty, TIOCNOTTY);
- close(tty);
- }
- if(isatty(0))
- pushredir(ROPEN, null, 0);
- else
- close(null);
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- close(null);
- runq->pc=runq->code[runq->pc].i;
- itoa(npid, pid);
- setvar("apid", newword(npid, (word *)0));
- break;
- }
-}
-void Xsettrue(void){
+
+void
+Xsettrue(void)
+{
         setstatus("");
 }
-void Xbang(void){
+
+void
+Xbang(void)
+{
         setstatus(truestatus()?"false":"");
 }
-void Xclose(void){
+
+void
+Xclose(void)
+{
         pushredir(RCLOSE, runq->code[runq->pc].i, 0);
         runq->pc++;
 }
-void Xdup(void){
+
+void
+Xdup(void)
+{
         pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
         runq->pc+=2;
 }
-void Xeflag(void){
+
+void
+Xeflag(void)
+{
         if(eflagok && !truestatus()) Xexit();
 }
-void Xexit(void){
+
+void
+Xexit(void)
+{
         struct var *trapreq;
         struct word *starval;
- static int beenhere=0;
+ static int beenhere = 0;
         if(getpid()==mypid && !beenhere){
- trapreq=vlook("sigexit");
+ trapreq = vlook("sigexit");
                 if(trapreq->fn){
- beenhere=1;
+ beenhere = 1;
                         --runq->pc;
- starval=vlook("*")->val;
+ starval = vlook("*")->val;
                         start(trapreq->fn, trapreq->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=copywords(starval, (struct word *)0);
- runq->local->changed=1;
- runq->redir=runq->startredir=0;
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = copywords(starval, (struct word *)0);
+ runq->local->changed = 1;
+ runq->redir = runq->startredir = 0;
                         return;
                 }
         }
         Exit(getstatus());
 }
-void Xfalse(void){
- if(truestatus()) runq->pc=runq->code[runq->pc].i;
+
+void
+Xfalse(void)
+{
+ if(truestatus()) runq->pc = runq->code[runq->pc].i;
         else runq->pc++;
 }
 int ifnot; /* dynamic if not flag */
-void Xifnot(void){
+
+void
+Xifnot(void)
+{
         if(ifnot)
                 runq->pc++;
         else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
 }
-void Xjump(void){
- runq->pc=runq->code[runq->pc].i;
+
+void
+Xjump(void)
+{
+ runq->pc = runq->code[runq->pc].i;
 }
-void Xmark(void){
+
+void
+Xmark(void)
+{
         pushlist();
 }
-void Xpopm(void){
+
+void
+Xpopm(void)
+{
         poplist();
 }
-void Xread(void){
+
+void
+Xread(void)
+{
         char *file;
         int f;
         switch(count(runq->argv->words)){
- default: Xerror1("< requires singleton\n"); return;
- case 0: Xerror1("< requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("< requires singleton\n");
+ return;
+ case 0:
+ Xerror1("< requires file\n");
+ return;
+ case 1:
+ break;
         }
- file=runq->argv->words->word;
- if((f=open(file, 0))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 0))<0){
                 pfmt(err, "%s: ", file);
                 Xerror("can't open");
                 return;
@@ -356,51 +379,25 @@
         runq->pc++;
         poplist();
 }
-void turfredir(void){
- while(runq->redir!=runq->startredir)
- Xpopredir();
-}
-void Xpopredir(void){
- struct redir *rp=runq->redir;
- if(rp==0) panic("turfredir null!", 0);
- runq->redir=rp->next;
- if(rp->type==ROPEN) close(rp->from);
- efree((char *)rp);
-}
-void Xreturn(void){
- struct thread *p=runq;
- turfredir();
- while(p->argv) poplist();
- codefree(p->code);
- runq=p->ret;
- efree((char *)p);
- if(runq==0) Exit(getstatus());
-}
-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){
+
+void
+Xrdwr(void)
+{
         char *file;
         int f;
+
         switch(count(runq->argv->words)){
- default: Xerror1("> requires singleton\n"); return;
- case 0: Xerror1("> requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("<> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("<> requires file\n");
+ return;
+ case 1:
+ break;
         }
- file=runq->argv->words->word;
- if((f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, ORDWR))<0){
                 pfmt(err, "%s: ", file);
                 Xerror("can't open");
                 return;
@@ -409,31 +406,120 @@
         runq->pc++;
         poplist();
 }
-char *_list2str(word *words, int c){
+
+void
+turfredir(void)
+{
+ while(runq->redir!=runq->startredir)
+ Xpopredir();
+}
+
+void
+Xpopredir(void)
+{
+ struct redir *rp = runq->redir;
+ if(rp==0)
+ panic("turfredir null!", 0);
+ runq->redir = rp->next;
+ if(rp->type==ROPEN)
+ close(rp->from);
+ efree((char *)rp);
+}
+
+void
+Xreturn(void)
+{
+ struct thread *p = runq;
+ turfredir();
+ while(p->argv) poplist();
+ codefree(p->code);
+ runq = p->ret;
+ efree((char *)p);
+ if(runq==0)
+ Exit(getstatus());
+}
+
+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 f;
+ switch(count(runq->argv->words)){
+ default:
+ Xerror1("> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("> requires file\n");
+ return;
+ case 1:
+ break;
+ }
+ file = runq->argv->words->word;
+ if((f = Creat(file))<0){
+ pfmt(err, "%s: ", file);
+ Xerror("can't open");
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+char*
+list2str(word *words)
+{
         char *value, *s, *t;
- int len=0;
+ int len = 0;
         word *ap;
- for(ap=words;ap;ap=ap->next)
+ for(ap = words;ap;ap = ap->next)
                 len+=1+strlen(ap->word);
- value=emalloc(len+1);
- s=value;
- for(ap=words;ap;ap=ap->next){
- for(t=ap->word;*t;) *s++=*t++;
- *s++=c;
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=' ';
         }
- if(s==value) *s='\0';
+ if(s==value)
+ *s='\0';
         else s[-1]='\0';
         return value;
 }
-char *list2str(word *words){
- return _list2str(words, ' ');
-}
-void Xmatch(void){
+
+void
+Xmatch(void)
+{
         word *p;
         char *subject;
- subject=list2str(runq->argv->words);
+ subject = list2str(runq->argv->words);
         setstatus("no match");
- for(p=runq->argv->next->words;p;p=p->next)
+ for(p = runq->argv->next->words;p;p = p->next)
                 if(match(subject, p->word, '\0')){
                         setstatus("");
                         break;
@@ -442,14 +528,17 @@
         poplist();
         poplist();
 }
-void Xcase(void){
+
+void
+Xcase(void)
+{
         word *p;
         char *s;
- int ok=0;
- s=list2str(runq->argv->next->words);
- for(p=runq->argv->words;p;p=p->next){
+ int ok = 0;
+ s = list2str(runq->argv->next->words);
+ for(p = runq->argv->words;p;p = p->next){
                 if(match(s, p->word, '\0')){
- ok=1;
+ ok = 1;
                         break;
                 }
         }
@@ -457,28 +546,33 @@
         if(ok)
                 runq->pc++;
         else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
         poplist();
 }
-word *conclist(word *lp, word *rp, word *tail)
+
+word*
+conclist(word *lp, word *rp, word *tail)
 {
         char *buf;
         word *v;
         if(lp->next || rp->next)
- tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
+ tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
                         tail);
- buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
+ buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
         strcpy(buf, lp->word);
         strcat(buf, rp->word);
- v=newword(buf, tail);
+ v = newword(buf, tail);
         efree(buf);
         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);
+
+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");
@@ -488,42 +582,50 @@
                         Xerror1("mismatched list lengths in concatenation");
                         return;
                 }
- vp=conclist(lp, rp, vp);
+ vp = conclist(lp, rp, vp);
         }
         poplist();
         poplist();
- runq->argv->words=vp;
+ runq->argv->words = vp;
 }
-void Xassign(void){
+
+void
+Xassign(void)
+{
         var *v;
         if(count(runq->argv->words)!=1){
                 Xerror1("variable name not singleton!");
                 return;
         }
         deglob(runq->argv->words->word);
- v=vlook(runq->argv->words->word);
+ v = vlook(runq->argv->words->word);
         poplist();
         globlist();
         freewords(v->val);
- v->val=runq->argv->words;
- v->changed=1;
+ v->val = runq->argv->words;
+ v->changed = 1;
         if(v->changefn)
                 v->changefn(v);
- runq->argv->words=0;
+ runq->argv->words = 0;
         poplist();
 }
 /*
  * copy arglist a, adding the copy to the front of tail
  */
-word *copywords(word *a, word *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;
+ 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){
+
+void
+Xdol(void)
+{
         word *a, *star;
         char *s, *t;
         int n;
@@ -531,24 +633,27 @@
                 Xerror1("variable name not singleton!");
                 return;
         }
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
         deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
- a=runq->argv->next->words;
+ n = 0;
+ 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);
+ a = copywords(vlook(s)->val, a);
         else{
- star=vlook("*")->val;
+ star = vlook("*")->val;
                 if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
- a=newword(star->word, a);
+ while(--n) star = star->next;
+ a = newword(star->word, a);
                 }
         }
         poplist();
- runq->argv->words=a;
+ runq->argv->words = a;
 }
-void Xqdol(void){
+
+void
+Xqdol(void)
+{
         word *a, *p;
         char *s;
         int n;
@@ -556,20 +661,20 @@
                 Xerror1("variable name not singleton!");
                 return;
         }
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
         deglob(s);
- a=vlook(s)->val;
+ a = vlook(s)->val;
         poplist();
- n=count(a);
+ n = count(a);
         if(n==0){
                 pushword("");
                 return;
         }
- for(p=a;p;p=p->next) n+=strlen(p->word);
- s=emalloc(n);
+ for(p = a;p;p = p->next) n+=strlen(p->word);
+ s = emalloc(n);
         if(a){
                 strcpy(s, a->word);
- for(p=a->next;p;p=p->next){
+ for(p = a->next;p;p = p->next){
                         strcat(s, " ");
                         strcat(s, p->word);
                 }
@@ -579,37 +684,77 @@
         pushword(s);
         efree(s);
 }
-word *subwords(word *val, int len, word *sub, word *a)
+
+word*
+copynwords(word *a, word *tail, int n)
 {
- 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;
+}
+
+word*
+subwords(word *val, int len, word *sub, word *a)
+{
+ int n, m;
         char *s;
- if(!sub) return a;
- a=subwords(val, len, sub->next, a);
- s=sub->word;
+ if(!sub)
+ return a;
+ a = subwords(val, len, sub->next, a);
+ s = sub->word;
         deglob(s);
- n=0;
- while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
- if(n<1 || len<n) return a;
- for(;n!=1;--n) val=val->next;
- return newword(val->word, a);
+ 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){
+
+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;
+ s = runq->argv->next->words->word;
         deglob(s);
- a=runq->argv->next->next->words;
- v=vlook(s)->val;
- a=subwords(v, count(v), runq->argv->words, a);
+ 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;
+ runq->argv->words = a;
 }
-void Xcount(void){
+
+void
+Xcount(void)
+{
         word *a;
         char *s, *t;
         int n;
@@ -618,112 +763,102 @@
                 Xerror1("variable name not singleton!");
                 return;
         }
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
         deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+ n = 0;
+ for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
         if(n==0 || *t){
- a=vlook(s)->val;
- itoa(num, count(a));
+ a = vlook(s)->val;
+ inttoascii(num, count(a));
         }
         else{
- a=vlook("*")->val;
- itoa(num, a && 1<=n && n<=count(a)?1:0);
+ a = vlook("*")->val;
+ inttoascii(num, a && 1<=n && n<=count(a)?1:0);
         }
         poplist();
         pushword(num);
 }
-void Xlocal(void){
+
+void
+Xlocal(void)
+{
         if(count(runq->argv->words)!=1){
                 Xerror1("variable name must be singleton\n");
                 return;
         }
         deglob(runq->argv->words->word);
- runq->local=newvar(strdup(runq->argv->words->word), runq->local);
- runq->local->val=copywords(runq->argv->next->words, (word *)0);
- runq->local->changed=1;
+ runq->local = newvar(strdup(runq->argv->words->word), runq->local);
+ runq->local->val = copywords(runq->argv->next->words, (word *)0);
+ runq->local->changed = 1;
         poplist();
         poplist();
 }
-void Xunlocal(void){
- var *v=runq->local, *hid;
- if(v==0) panic("Xunlocal: no locals!", 0);
- runq->local=v->next;
- hid=vlook(v->name);
- hid->changed=1;
+
+void
+Xunlocal(void)
+{
+ var *v = runq->local, *hid;
+ if(v==0)
+ panic("Xunlocal: no locals!", 0);
+ runq->local = v->next;
+ hid = vlook(v->name);
+ hid->changed = 1;
         efree(v->name);
         freewords(v->val);
         efree((char *)v);
 }
-void freewords(word *w)
+
+void
+freewords(word *w)
 {
         word *nw;
         while(w){
                 efree(w->word);
- nw=w->next;
+ nw = w->next;
                 efree((char *)w);
- w=nw;
+ w = nw;
         }
 }
-void Xfn(void){
+
+void
+Xfn(void)
+{
         var *v;
         word *a;
         int end;
- end=runq->code[runq->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=runq->pc+2;
- v->fnchanged=1;
+ end = runq->code[runq->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 = runq->pc+2;
+ v->fnchanged = 1;
         }
- runq->pc=end;
+ runq->pc = end;
         poplist();
 }
-void Xdelfn(void){
+
+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;
+ 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();
 }
-void Xpipe(void){
- struct thread *p=runq;
- int pc=p->pc, forkid;
- int lfd=p->code[pc++].i;
- int rfd=p->code[pc++].i;
- int pfd[2];
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- switch(forkid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- runq->ret=0;
- close(pfd[PRD]);
- pushredir(ROPEN, pfd[PWR], lfd);
- break;
- default:
- start(p->code, p->code[pc].i, runq->local);
- close(pfd[PWR]);
- pushredir(ROPEN, pfd[PRD], rfd);
- p->pc=p->code[pc+1].i;
- p->pid=forkid;
- break;
- }
-}
-char *concstatus(char *s, char *t)
+
+char*
+concstatus(char *s, char *t)
 {
         static char v[NSTATUS+1];
- int n=strlen(s);
+ int n = strlen(s);
         strncpy(v, s, NSTATUS);
         if(n<NSTATUS){
                 v[n]='|';
@@ -732,7 +867,10 @@
         v[NSTATUS]='\0';
         return v;
 }
-void Xpipewait(void){
+
+void
+Xpipewait(void)
+{
         char status[NSTATUS+1];
         if(runq->pid==-1)
                 setstatus(concstatus(runq->status, getstatus()));
@@ -744,31 +882,35 @@
                 setstatus(concstatus(getstatus(), status));
         }
 }
-void Xrdcmds(void){
- struct thread *p=runq;
+
+void
+Xrdcmds(void)
+{
+ struct thread *p = runq;
         word *prompt;
         flush(err);
- nerror=0;
+ nerror = 0;
         if(flag['s'] && !truestatus())
                 pfmt(err, "status=%v\n", vlook("status")->val);
         if(runq->iflag){
- prompt=vlook("prompt")->val;
+ prompt = vlook("prompt")->val;
                 if(prompt)
- promptstr=prompt->word;
+ promptstr = prompt->word;
                 else
                         promptstr="% ";
         }
         Noerror();
         if(yyparse()){
                 if(!p->iflag || p->eof && !Eintr()){
- if(p->cmdfile) efree(p->cmdfile);
+ if(p->cmdfile)
+ efree(p->cmdfile);
                         closeio(p->cmdfd);
                         Xreturn(); /* should this be omitted? */
                 }
                 else{
                         if(Eintr()){
                                 pchr(err, '\n');
- p->eof=0;
+ p->eof = 0;
                         }
                         --p->pc; /* go back for next command */
                 }
@@ -780,7 +922,9 @@
         }
         freenodes();
 }
-void Xerror(char *s)
+
+void
+Xerror(char *s)
 {
         if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
                 pfmt(err, "rc: %s: %r\n", s);
@@ -790,7 +934,9 @@
         setstatus("error");
         while(!runq->iflag) Xreturn();
 }
-void Xerror1(char *s)
+
+void
+Xerror1(char *s)
 {
         if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
                 pfmt(err, "rc: %s\n", s);
@@ -800,150 +946,55 @@
         setstatus("error");
         while(!runq->iflag) Xreturn();
 }
-void Xbackq(void){
- char wd[8193];
- int c;
- char *s, *ewd=&wd[8192], *stop;
- struct io *f;
- var *ifs=vlook("ifs");
- word *v, *nextv;
- int pfd[2];
- int pid;
- stop=ifs->val?ifs->val->word:"";
- if(pipe(pfd)<0){
- Xerror("can't make pipe");
- return;
- }
- switch(pid=fork()){
- case -1: Xerror("try again");
- close(pfd[PRD]);
- close(pfd[PWR]);
- return;
- case 0:
- close(pfd[PRD]);
- start(runq->code, runq->pc+1, runq->local);
- pushredir(ROPEN, pfd[PWR], 1);
- return;
- default:
- close(pfd[PWR]);
- f=openfd(pfd[PRD]);
- s=wd;
- v=0;
- while((c=rchr(f))!=EOF){
- if(strchr(stop, c) || s==ewd){
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- s=wd;
- }
- }
- else *s++=c;
- }
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- }
- closeio(f);
- Waitfor(pid, 0);
- /* v points to reversed arglist -- reverse it onto argv */
- while(v){
- nextv=v->next;
- v->next=runq->argv->words;
- runq->argv->words=v;
- v=nextv;
- }
- runq->pc=runq->code[runq->pc].i;
- return;
- }
-}
-/*
- * Who should wait for the exit from the fork?
- */
-void Xpipefd(void){
- struct thread *p=runq;
- int pc=p->pc;
- char name[40];
- int pfd[2];
- int sidefd, mainfd;
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- if(p->code[pc].i==READ){
- sidefd=pfd[PWR];
- mainfd=pfd[PRD];
- }
- else{
- sidefd=pfd[PRD];
- mainfd=pfd[PWR];
- }
- switch(fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- close(mainfd);
- pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
- runq->ret=0;
- break;
- default:
- close(sidefd);
- pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
- strcpy(name, Fdprefix);
- itoa(name+strlen(name), mainfd);
- pushword(name);
- p->pc=p->code[pc+1].i;
- break;
- }
-}
-void Xsubshell(void){
- int pid;
- switch(pid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- Waitfor(pid, 1);
- runq->pc=runq->code[runq->pc].i;
- break;
- }
-}
-void setstatus(char *s)
+
+void
+setstatus(char *s)
 {
         setvar("status", newword(s, (word *)0));
 }
-char *getstatus(void){
- var *status=vlook("status");
+
+char*
+getstatus(void)
+{
+ var *status = vlook("status");
         return status->val?status->val->word:"";
 }
-int truestatus(void){
+
+int
+truestatus(void)
+{
         char *s;
- for(s=getstatus();*s;s++)
- if(*s!='|' && *s!='0') return 0;
+ for(s = getstatus();*s;s++)
+ if(*s!='|' && *s!='0')
+ return 0;
         return 1;
 }
-void Xdelhere(void){
+
+void
+Xdelhere(void)
+{
         Unlink(runq->code[runq->pc++].s);
 }
-void Xfor(void){
+
+void
+Xfor(void)
+{
         if(runq->argv->words==0){
                 poplist();
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
         }
         else{
                 freelist(runq->local->val);
- runq->local->val=runq->argv->words;
- runq->local->changed=1;
- runq->argv->words=runq->argv->words->next;
- runq->local->val->next=0;
+ runq->local->val = runq->argv->words;
+ runq->local->changed = 1;
+ runq->argv->words = runq->argv->words->next;
+ runq->local->val->next = 0;
                 runq->pc++;
         }
 }
-void Xglob(void){
+
+void
+Xglob(void)
+{
         globlist();
 }
diff -r bb17f966e24a -r 1161d90df941 rc/exec.h
--- a/rc/exec.h Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/exec.h Fri Jul 31 21:02:58 2009 +0100
@@ -5,6 +5,7 @@
 extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(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);
+extern void Xrdwr(void);
 extern void Xrdfn(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);
@@ -51,7 +52,6 @@
         int iflag; /* interactive? */
         int lineno; /* linenumber */
         int pid; /* process for Xpipewait to wait for */
- int done; /* have we seen a wait message for this process? */
         char status[NSTATUS]; /* status for Xpipewait */
         tree *treenodes; /* tree nodes created by this process */
         thread *ret; /* who continues when this finishes */
@@ -61,12 +61,16 @@
 code *codebuf; /* compiler output */
 int ntrap; /* number of outstanding traps */
 int trap[NSIG]; /* number of outstanding traps per type */
-extern struct builtin{
+struct builtin{
         char *name;
         void (*fnc)(void);
-}Builtin[];
+};
+extern struct builtin Builtin[];
 int eflagok; /* kludge flag so that -e doesn't exit in startup */
+int havefork;
+
 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 *);
diff -r bb17f966e24a -r 1161d90df941 rc/fns.h
--- a/rc/fns.h Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/fns.h Fri Jul 31 21:02:58 2009 +0100
@@ -7,13 +7,14 @@
 int Executable(char*);
 void Execute(word*, word*);
 void Exit(char*);
+int ForkExecute(char*, char**, int, int, int);
 int Globsize(char*);
 int Isatty(int);
 void Memcpy(char*, char*, long);
 void Noerror(void);
 int Opendir(char*);
 long Read(int, char*, long);
-int Readdir(int, char*);
+int Readdir(int, char*, int);
 long Seek(int, long, long);
 void Trapinit(void);
 void Unlink(char*);
@@ -21,24 +22,29 @@
 void Vinit(void);
 int Waitfor(int, int);
 long Write(int, char*, long);
+void addwaitpid(int);
 int advance(void);
 int back(int);
 void cleanhere(char*);
 void codefree(code*);
 int compile(tree*);
 char * list2str(word*);
-char * _list2str(word*, int);
 int count(word*);
 void deglob(char*);
+void delwaitpid(int);
 void dotrap(void);
 void freenodes(void);
 void freewords(word*);
 void globlist(void);
+int havewaitpid(int);
 int idchr(int);
-void itoa(char*, long);
+void inttoascii(char*, long);
 void kinit(void);
+int mapfd(int);
 int match(char*, char*, int);
 int matchfn(char*, char*);
+char** mkargv(word*);
+void clearwaitpids(void);
 void panic(char*, int);
 void pathinit(void);
 void poplist(void);
@@ -48,9 +54,9 @@
 void pushredir(int, int, int);
 void pushword(char*);
 void readhere(void);
+word* searchpath(char*);
 void setstatus(char*);
 void setvar(char*, word*);
-void _setvar(char*, word*, int);
 void skipnl(void);
 void start(code*, int, var*);
 int truestatus(void);
diff -r bb17f966e24a -r 1161d90df941 rc/getflags.c
--- a/rc/getflags.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/getflags.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,7 +3,7 @@
 #include "rc.h"
 #include "getflags.h"
 #include "fns.h"
-char *flagset[]={"<flag>"};
+char *flagset[] = {"<flag>"};
 char **flag[NFLAG];
 char cmdline[NCMDLINE+1];
 char *cmdname;
@@ -19,105 +19,118 @@
 #define FLAGSYN 3
 #define BADFLAG 4
 static int badflag;
-int getflags(int argc, char *argv[], char *flags, int stop)
+
+int
+getflags(int argc, char *argv[], char *flags, int stop)
 {
         char *s, *t;
         int i, j, c, count;
- flagarg=flags;
- if(cmdname==0) cmdname=argv[0];
- s=cmdline;
- for(i=0;i!=argc;i++){
- for(t=argv[i];*t;t++)
+ flagarg = flags;
+ if(cmdname==0)
+ cmdname = argv[0];
+ s = cmdline;
+ for(i = 0;i!=argc;i++){
+ for(t = argv[i];*t;t++)
                         if(s!=&cmdline[NCMDLINE])
                                 *s++=*t;
                 if(i!=argc-1 && s!=&cmdline[NCMDLINE])
                         *s++=' ';
         }
         *s='\0';
- i=1;
+ i = 1;
         while(i!=argc){
                 if(argv[i][0]!='-' || argv[i][1]=='\0'){
- if(stop) return argc;
+ if(stop)
+ return argc;
                         i++;
                         continue;
                 }
- s=argv[i]+1;
+ 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; }
+ count = scanflag(c, flags);
+ if(count==-1)
+ return -1;
+ if(flag[c]){ reason = RESET; badflag = c; return -1; }
                         if(count==0){
- flag[c]=flagset;
+ flag[c] = flagset;
                                 if(*s=='\0'){
- for(j=i+1;j<=argc;j++)
- argv[j-1]=argv[j];
+ 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];
+ for(j = i+1;j<=argc;j++)
+ argv[j-1] = argv[j];
                                         --argc;
- s=argv[i];
+ s = argv[i];
                                 }
                                 if(argc-i<count){
- reason=FEWARGS;
- badflag=c;
+ 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;
+ flag[c] = argv+argc+1;
+ flag[c][0] = s;
                                 s="";
                         }
                 }
         }
         return argc;
 }
-static void reverse(char **p, char **q)
+
+static void
+reverse(char **p, char **q)
 {
         char *t;
- for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
+ for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
 }
-static int scanflag(int c, char *f)
+
+static int
+scanflag(int c, char *f)
 {
         int fc, count;
- if(0<=c && c<NFLAG) while(*f){
- if(*f==' '){
- f++;
- continue;
+ 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;
                 }
- 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;
+ reason = BADFLAG;
+ badflag = c;
         return -1;
 }
-void usage(char *tail)
+
+void
+usage(char *tail)
 {
         char *s, *t, c;
- int count, nflag=0;
+ int count, nflag = 0;
         switch(reason){
         case RESET:
                 errs("Flag -");
@@ -140,46 +153,52 @@
         }
         errs("Usage: ");
         errs(cmdname);
- for(s=flagarg;*s;){
+ for(s = flagarg;*s;){
                 c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
                 if(*s==':'){
                         s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
                 }
- else count=0;
+ else count = 0;
                 if(count==0){
- if(nflag==0) errs(" [-");
+ if(nflag==0)
+ errs(" [-");
                         nflag++;
                         errc(c);
                 }
                 if(*s=='['){
                         s++;
                         while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
                 }
         }
- if(nflag) errs("]");
- for(s=flagarg;*s;){
+ if(nflag)
+ errs("]");
+ for(s = flagarg;*s;){
                 c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
                 if(*s==':'){
                         s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
                 }
- else count=0;
+ else count = 0;
                 if(count!=0){
                         errs(" [-");
                         errc(c);
                         if(*s=='['){
                                 s++;
- t=s;
+ t = s;
                                 while(*s!=']' && *s!='\0') s++;
                                 errs(" ");
                                 errn(t, s-t);
- if(*s==']') s++;
+ if(*s==']')
+ s++;
                         }
                         else
                                 while(count--) errs(" arg");
@@ -188,7 +207,8 @@
                 else if(*s=='['){
                         s++;
                         while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
                 }
         }
         if(tail){
@@ -198,20 +218,27 @@
         errs("\n");
         Exit("bad flags");
 }
-static void errn(char *s, int count)
+
+static void
+errn(char *s, int count)
 {
         while(count){ errc(*s++); --count; }
 }
-static void errs(char *s)
+
+static void
+errs(char *s)
 {
         while(*s) errc(*s++);
 }
 #define NBUF 80
-static char buf[NBUF], *bufp=buf;
-static void errc(int c){
+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;
+ bufp = buf;
         }
 }
diff -r bb17f966e24a -r 1161d90df941 rc/glob.c
--- a/rc/glob.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/glob.c Fri Jul 31 21:02:58 2009 +0100
@@ -6,68 +6,77 @@
 /*
  * delete all the GLOB marks from s, in place
  */
-void deglob(char *s)
+
+void
+deglob(char *s)
 {
- char *t=s;
+ char *t = s;
         do{
- if(*t==GLOB) t++;
+ if(*t==GLOB)
+ t++;
                 *s++=*t;
         }while(*t++);
 }
-int globcmp(const void *s, const void *t)
+
+int
+globcmp(const void *s, const void *t)
 {
         return strcmp(*(char**)s, *(char**)t);
 }
-void globsort(word *left, word *right)
+
+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((char *)list, n, sizeof(char *), globcmp);
- for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
+ 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];
         efree((char *)list);
 }
 /*
  * Push names prefixed by globname and suffixed by a match of p onto the astack.
  * namep points to the end of the prefix in globname.
  */
-void globdir(char *p, char *namep)
+
+void
+globdir(char *p, char *namep)
 {
         char *t, *newp;
         int f;
         /* scan the pattern looking for a component with a metacharacter in it */
         if(*p=='\0'){
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
                 return;
         }
- t=namep;
- newp=p;
+ t = namep;
+ newp = p;
         while(*newp){
                 if(*newp==GLOB)
                         break;
                 *t=*newp++;
                 if(*t++=='/'){
- namep=t;
- p=newp;
+ namep = t;
+ p = newp;
                 }
         }
         /* If we ran out of pattern, append the name if accessible */
         if(*newp=='\0'){
                 *t='\0';
                 if(access(globname, 0)==0)
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
                 return;
         }
         /* read the directory and recur for any entry that matches */
         *namep='\0';
- if((f=Opendir(globname[0]?globname:"."))<0) return;
+ if((f = Opendir(globname[0]?globname:"."))<0) return;
         while(*newp!='/' && *newp!='\0') newp++;
- while(Readdir(f, namep)){
+ while(Readdir(f, namep, *newp=='/')){
                 if(matchfn(namep, p)){
- for(t=namep;*t;t++);
+ for(t = namep;*t;t++);
                         globdir(newp, t);
                 }
         }
@@ -77,22 +86,24 @@
  * Push all file names matched by p on the current thread's stack.
  * If there are no matches, the list consists of p.
  */
-void glob(char *p)
+
+void
+glob(char *p)
 {
- word *svglobv=globv;
- int globlen=Globsize(p);
+ word *svglobv = globv;
+ int globlen = Globsize(p);
         if(!globlen){
                 deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
                 return;
         }
- globname=emalloc(globlen);
+ globname = emalloc(globlen);
         globname[0]='\0';
         globdir(p, globname);
         efree(globname);
         if(svglobv==globv){
                 deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
         }
         else
                 globsort(globv, svglobv);
@@ -100,12 +111,18 @@
 /*
  * Do p and q point at equal utf codes
  */
-int equtf(char *p, char *q){
- if(*p!=*q) return 0;
+
+int
+equtf(char *p, char *q)
+{
+ if(*p!=*q)
+ return 0;
         if(twobyte(*p)) return p[1]==q[1];
         if(threebyte(*p)){
- if(p[1]!=q[1]) return 0;
- if(p[1]=='\0') return 1; /* broken code at end of string! */
+ if(p[1]!=q[1])
+ return 0;
+ if(p[1]=='\0')
+ return 1; /* broken code at end of string! */
                 return p[2]==q[2];
         }
         return 1;
@@ -114,7 +131,10 @@
  * Return a pointer to the next utf code in the string,
  * not jumping past nuls in broken utf codes!
  */
-char *nextutf(char *p){
+
+char*
+nextutf(char *p)
+{
         if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
         if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
         return p+1;
@@ -122,7 +142,10 @@
 /*
  * Convert the utf code at *p to a unicode value
  */
-int unicode(char *p){
+
+int
+unicode(char *p)
+{
         int u=*p&0xff;
         if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
         if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
@@ -135,77 +158,97 @@
  * ? matches any single character
  * [...] matches the enclosed list of characters
  */
-int matchfn(char *s, char *p)
+
+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, '/');
 }
-int match(char *s, char *p, int stop)
+
+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)){
+ 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;
+ if(*s!=GLOB)
+ return 0;
                         break;
                 case '*':
                         for(;;){
                                 if(match(s, nextutf(p), stop)) return 1;
- if(!*s) break;
- s=nextutf(s);
+ if(!*s)
+ break;
+ s = nextutf(s);
                         }
                         return 0;
                 case '?':
- if(*s=='\0') return 0;
+ if(*s=='\0')
+ return 0;
                         break;
                 case '[':
- if(*s=='\0') return 0;
- c=unicode(s);
+ if(*s=='\0')
+ return 0;
+ c = unicode(s);
                         p++;
                         compl=*p=='~';
- if(compl) p++;
- hit=0;
+ if(compl)
+ p++;
+ hit = 0;
                         while(*p!=']'){
- if(*p=='\0') return 0; /* syntax error */
- lo=unicode(p);
- p=nextutf(p);
- if(*p!='-') hi=lo;
+ 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(*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(lo<=c && c<=hi)
+ hit = 1;
                         }
- if(compl) hit=!hit;
- if(!hit) return 0;
+ if(compl)
+ hit=!hit;
+ if(!hit)
+ return 0;
                         break;
                 }
         }
         return *s=='\0';
 }
-void globlist1(word *gl)
+
+void
+globlist1(word *gl)
 {
         if(gl){
                 globlist1(gl->next);
                 glob(gl->word);
         }
 }
-void globlist(void){
+
+void
+globlist(void)
+{
         word *a;
- globv=0;
+ globv = 0;
         globlist1(runq->argv->words);
         poplist();
         pushlist();
         if(globv){
- for(a=globv;a->next;a=a->next);
- a->next=runq->argv->words;
- runq->argv->words=globv;
+ for(a = globv;a->next;a = a->next);
+ a->next = runq->argv->words;
+ runq->argv->words = globv;
         }
 }
diff -r bb17f966e24a -r 1161d90df941 rc/havefork.c
--- a/rc/havefork.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/havefork.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,5 +1,9 @@
 #include <u.h>
 #include <signal.h>
+#if defined(PLAN9PORT) && defined(__sun__)
+# define BSD_COMP /* sigh. for TIOCNOTTY */
+#endif
+#include <sys/ioctl.h>
 #include "rc.h"
 #include "getflags.h"
 #include "exec.h"
@@ -12,10 +16,9 @@
 Xasync(void)
 {
         int null = open("/dev/null", 0);
+ int tty;
         int pid;
- int tcpgrp, pgrp;
         char npid[10];
-
         if(null<0){
                 Xerror("Can't open /dev/null\n");
                 return;
@@ -26,17 +29,39 @@
                 Xerror("try again");
                 break;
         case 0:
+ clearwaitpids();
                 /*
- * Should make reads of tty fail, writes succeed.
+ * I don't know what the right thing to do here is,
+ * so this is all experimentally determined.
+ * If we just dup /dev/null onto 0, then running
+ * ssh foo & will reopen /dev/tty, try to read a password,
+ * get a signal, and repeat, in a tight loop, forever.
+ * Arguably this is a bug in ssh (it behaves the same
+ * way under bash as under rc) but I'm fixing it here
+ * anyway. If we dissociate the process from the tty,
+ * then it won't be able to open /dev/tty ever again.
+ * The SIG_IGN on SIGTTOU makes writing the tty
+ * (via fd 1 or 2, for example) succeed even though
+ * our pgrp is not the terminal's controlling pgrp.
                  */
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
- pushredir(ROPEN, null, 0);
+ if((tty = open("/dev/tty", OREAD)) >= 0){
+ /*
+ * Should make reads of tty fail, writes succeed.
+ */
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ ioctl(tty, TIOCNOTTY);
+ close(tty);
+ }
+ if(isatty(0))
+ pushredir(ROPEN, null, 0);
+ else
+ close(null);
                 start(runq->code, runq->pc+1, runq->local);
                 runq->ret = 0;
                 break;
         default:
+ addwaitpid(pid);
                 close(null);
                 runq->pc = runq->code[runq->pc].i;
                 inttoascii(npid, pid);
@@ -62,12 +87,14 @@
                 Xerror("try again");
                 break;
         case 0:
+ clearwaitpids();
                 start(p->code, pc+2, runq->local);
                 runq->ret = 0;
                 close(pfd[PRD]);
                 pushredir(ROPEN, pfd[PWR], lfd);
                 break;
         default:
+ addwaitpid(forkid);
                 start(p->code, p->code[pc].i, runq->local);
                 close(pfd[PWR]);
                 pushredir(ROPEN, pfd[PRD], rfd);
@@ -103,11 +130,13 @@
                 close(pfd[PWR]);
                 return;
         case 0:
+ clearwaitpids();
                 close(pfd[PRD]);
                 start(runq->code, runq->pc+1, runq->local);
                 pushredir(ROPEN, pfd[PWR], 1);
                 return;
         default:
+ addwaitpid(pid);
                 close(pfd[PWR]);
                 f = openfd(pfd[PRD]);
                 s = wd;
@@ -144,7 +173,7 @@
 Xpipefd(void)
 {
         struct thread *p = runq;
- int pc = p->pc;
+ int pc = p->pc, pid;
         char name[40];
         int pfd[2];
         int sidefd, mainfd;
@@ -160,17 +189,19 @@
                 sidefd = pfd[PRD];
                 mainfd = pfd[PWR];
         }
- switch(fork()){
+ switch(pid = fork()){
         case -1:
                 Xerror("try again");
                 break;
         case 0:
+ clearwaitpids();
                 start(p->code, pc+2, runq->local);
                 close(mainfd);
                 pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
                 runq->ret = 0;
                 break;
         default:
+ addwaitpid(pid);
                 close(sidefd);
                 pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
                 strcpy(name, Fdprefix);
@@ -190,10 +221,12 @@
                 Xerror("try again");
                 break;
         case 0:
+ clearwaitpids();
                 start(runq->code, runq->pc+1, runq->local);
                 runq->ret = 0;
                 break;
         default:
+ addwaitpid(pid);
                 Waitfor(pid, 1);
                 runq->pc = runq->code[runq->pc].i;
                 break;
@@ -211,6 +244,7 @@
         case -1:
                 return -1;
         case 0:
+ clearwaitpids();
                 pushword("exec");
                 execexec();
                 strcpy(buf, "can't exec: ");
@@ -218,5 +252,6 @@
                 errstr(buf+n, ERRMAX-n);
                 Exit(buf);
         }
+ addwaitpid(pid);
         return pid;
 }
diff -r bb17f966e24a -r 1161d90df941 rc/here.c
--- a/rc/here.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/here.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,32 +3,37 @@
 #include "io.h"
 #include "fns.h"
 struct here *here, **ehere;
-int ser=0;
+int ser = 0;
 char tmp[]="/tmp/here0000.0000";
 char hex[]="0123456789abcdef";
 void psubst(io*, char*);
 void pstrs(io*, word*);
-void hexnum(char *p, int n)
+
+void
+hexnum(char *p, int n)
 {
         *p++=hex[(n>>12)&0xF];
         *p++=hex[(n>>8)&0xF];
         *p++=hex[(n>>4)&0xF];
- *p=hex[n&0xF];
+ *p = hex[n&0xF];
 }
-tree *heredoc(tree *tag)
+
+tree*
+heredoc(tree *tag)
 {
- struct here *h=new(struct here);
- if(tag->type!=WORD) yyerror("Bad here tag");
- h->next=0;
+ struct here *h = new(struct here);
+ if(tag->type!=WORD)
+ yyerror("Bad here tag");
+ h->next = 0;
         if(here)
- *ehere=h;
+ *ehere = h;
         else
- here=h;
+ here = h;
         ehere=&h->next;
- h->tag=tag;
+ h->tag = tag;
         hexnum(&tmp[9], getpid());
         hexnum(&tmp[14], ser++);
- h->name=strdup(tmp);
+ h->name = strdup(tmp);
         return token(tmp, WORD);
 }
 /*
@@ -36,27 +41,32 @@
  * missubstitution, or a misrecognized EOF marker.
  */
 #define NLINE 4096
-void readhere(void){
+
+void
+readhere(void)
+{
         struct here *h, *nexth;
         io *f;
         char *s, *tag;
         int c, subst;
         char line[NLINE+1];
- for(h=here;h;h=nexth){
+ for(h = here;h;h = nexth){
                 subst=!h->tag->quoted;
- tag=h->tag->str;
- c=Creat(h->name);
- if(c<0) yyerror("can't create here document");
- f=openfd(c);
- s=line;
+ tag = h->tag->str;
+ c = Creat(h->name);
+ if(c<0)
+ yyerror("can't create here document");
+ f = openfd(c);
+ s = line;
                 pprompt();
- while((c=rchr(runq->cmdfd))!=EOF){
+ while((c = rchr(runq->cmdfd))!=EOF){
                         if(c=='\n' || s==&line[NLINE]){
                                 *s='\0';
- if(strcmp(line, tag)==0) break;
- if(subst) psubst(f, line);
+ if(tag && strcmp(line, tag)==0) break;
+ if(subst)
+ psubst(f, line);
                                 else pstr(f, line);
- s=line;
+ s = line;
                                 if(c=='\n'){
                                         pprompt();
                                         pchr(f, c);
@@ -68,13 +78,15 @@
                 flush(f);
                 closeio(f);
                 cleanhere(h->name);
- nexth=h->next;
+ nexth = h->next;
                 efree((char *)h);
         }
- here=0;
- doprompt=1;
+ here = 0;
+ doprompt = 1;
 }
-void psubst(io *f, char *s)
+
+void
+psubst(io *f, char *s)
 {
         char *t, *u;
         int savec, n;
@@ -83,48 +95,55 @@
                 if(*s!='$'){
                         if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
                                 pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
                         }
                         else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
                                 pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
                                 pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
                         }
                         pchr(f, *s++);
                 }
                 else{
                         t=++s;
- if(*t=='$') pchr(f, *t++);
+ 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';
+ n = 0;
+ for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
                                 if(n && *u=='\0'){
- star=vlook("*")->val;
+ star = vlook("*")->val;
                                         if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
+ while(--n) star = star->next;
                                                 pstr(f, star->word);
                                         }
                                 }
                                 else
                                         pstrs(f, vlook(s)->val);
- *t=savec;
- if(savec=='^') t++;
+ *t = savec;
+ if(savec=='^')
+ t++;
                         }
- s=t;
+ s = t;
                 }
         }
 }
-void pstrs(io *f, word *a)
+
+void
+pstrs(io *f, word *a)
 {
         if(a){
                 while(a->next && a->next->word){
                         pstr(f, a->word);
                         pchr(f, ' ');
- a=a->next;
+ a = a->next;
                 }
                 pstr(f, a->word);
         }
diff -r bb17f966e24a -r 1161d90df941 rc/io.c
--- a/rc/io.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/io.c Fri Jul 31 21:02:58 2009 +0100
@@ -2,68 +2,121 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-int pfmtnest=0;
-void pfmt(io *f, char *fmt, ...){
+int pfmtnest = 0;
+
+void
+pfmt(io *f, char *fmt, ...)
+{
         va_list ap;
         char err[ERRMAX];
         va_start(ap, fmt);
         pfmtnest++;
         for(;*fmt;fmt++)
- if(*fmt!='%') pchr(f, *fmt);
+ if(*fmt!='%')
+ pchr(f, *fmt);
                 else switch(*++fmt){
- case '\0': va_end(ap); return;
- 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': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/
- case 'Q': pquo(f, va_arg(ap, char *)); break;
- case 'q': pwrd(f, va_arg(ap, char *)); break;
- case 'r': errstr(err, sizeof err); pstr(f, err); break;
- case 's': pstr(f, va_arg(ap, char *)); break;
- case 't': pcmd(f, va_arg(ap, struct tree *)); break;
- case 'v': pval(f, va_arg(ap, struct word *)); break;
- default: pchr(f, *fmt); break;
+ case '\0':
+ va_end(ap);
+ return;
+ 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 'r':
+ rerrstr(err, sizeof err); pstr(f, err);
+ break;
+ case 's':
+ pstr(f, va_arg(ap, char *));
+ break;
+ case 't':
+ pcmd(f, va_arg(ap, struct tree *));
+ break;
+ case 'v':
+ pval(f, va_arg(ap, struct word *));
+ break;
+ default:
+ pchr(f, *fmt);
+ break;
                 }
         va_end(ap);
- if(--pfmtnest==0) flush(f);
+ if(--pfmtnest==0)
+ flush(f);
 }
-void pchr(io *b, int c)
+
+void
+pchr(io *b, int c)
 {
- if(b->bufp==b->ebuf) fullbuf(b, c);
+ if(b->bufp==b->ebuf)
+ fullbuf(b, c);
         else *b->bufp++=c;
 }
-int rchr(io *b)
+
+int
+rchr(io *b)
 {
- if(b->bufp==b->ebuf) return emptybuf(b);
+ if(b->bufp==b->ebuf)
+ return emptybuf(b);
         return *b->bufp++ & 0xFF;
 }
 
-void pquo(io *f, char *s)
+void
+pquo(io *f, char *s)
 {
         pchr(f, '\'');
         for(;*s;s++)
- if(*s=='\'') pfmt(f, "''");
+ if(*s=='\'')
+ pfmt(f, "''");
                 else pchr(f, *s);
         pchr(f, '\'');
 }
-void pwrd(io *f, char *s)
+
+void
+pwrd(io *f, char *s)
 {
         char *t;
- for(t=s;*t;t++) if(!wordchr(*t)) break;
- if(t==s || *t) pquo(f, s);
+ for(t = s;*t;t++) if(!wordchr(*t)) break;
+ if(t==s || *t)
+ pquo(f, s);
         else pstr(f, s);
 }
-void phex(io *f, long p)
+
+void
+pptr(io *f, void *v)
 {
         int n;
- for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+ uintptr p;
+
+ 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]);
 }
-void pstr(io *f, char *s)
+
+void
+pstr(io *f, char *s)
 {
- if(s==0) s="(null)";
+ if(s==0)
+ s="(null)";
         while(*s) pchr(f, *s++);
 }
-void pdec(io *f, long n)
+
+void
+pdec(io *f, int n)
 {
         if(n<0){
                 n=-n;
@@ -73,110 +126,136 @@
                         return;
                 }
                 /* n is two's complement minimum integer */
- n=1-n;
+ n = 1-n;
                 pchr(f, '-');
                 pdec(f, n/10);
                 pchr(f, n%10+'1');
                 return;
         }
- if(n>9) pdec(f, n/10);
+ if(n>9)
+ pdec(f, n/10);
         pchr(f, n%10+'0');
 }
-void poct(io *f, ulong n)
+
+void
+poct(io *f, unsigned n)
 {
- if(n>7) poct(f, n>>3);
+ if(n>7)
+ poct(f, n>>3);
         pchr(f, (n&7)+'0');
 }
-void pval(io *f, word *a)
+
+void
+pval(io *f, word *a)
 {
         if(a){
                 while(a->next && a->next->word){
                         pwrd(f, a->word);
                         pchr(f, ' ');
- a=a->next;
+ a = a->next;
                 }
                 pwrd(f, a->word);
         }
 }
-int fullbuf(io *f, int c)
+
+int
+fullbuf(io *f, int c)
 {
         flush(f);
         return *f->bufp++=c;
 }
-void flush(io *f)
+
+void
+flush(io *f)
 {
         int n;
         char *s;
         if(f->strp){
- n=f->ebuf-f->strp;
- f->strp=realloc(f->strp, n+101);
- if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101);
- f->bufp=f->strp+n;
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ n = f->ebuf-f->strp;
+ f->strp = realloc(f->strp, n+101);
+ if(f->strp==0)
+ panic("Can't realloc %d bytes in flush!", n+101);
+ f->bufp = f->strp+n;
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
         }
         else{
- n=f->bufp-f->buf;
+ n = f->bufp-f->buf;
                 if(n && Write(f->fd, f->buf, n) < 0){
                         Write(3, "Write error\n", 12);
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
                 }
- f->bufp=f->buf;
- f->ebuf=f->buf+NBUF;
+ f->bufp = f->buf;
+ f->ebuf = f->buf+NBUF;
         }
 }
-io *openfd(int fd){
- io *f;
- f=new(struct io);
- f->fd=fd;
- f->bufp=f->ebuf=f->buf;
- f->strp=0;
+
+io*
+openfd(int fd)
+{
+ io *f = new(struct io);
+ f->fd = fd;
+ f->bufp = f->ebuf = f->buf;
+ f->strp = 0;
         return f;
 }
-io *openstr(void){
- io *f=new(struct io);
+
+io*
+openstr(void)
+{
+ io *f = new(struct io);
         char *s;
         f->fd=-1;
- f->bufp=f->strp=emalloc(101);
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ f->bufp = f->strp = emalloc(101);
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
         return f;
 }
 /*
  * Open a corebuffer to read. EOF occurs after reading len
  * characters from buf.
  */
-io *opencore(char *s, int len)
+
+io*
+opencore(char *s, int len)
 {
- io *f=new(struct io);
- char *buf=emalloc(len);
+ io *f = new(struct io);
+ char *buf = emalloc(len);
         f->fd= -1 /*open("/dev/null", 0)*/;
- f->bufp=f->strp=buf;
- f->ebuf=buf+len;
+ f->bufp = f->strp = buf;
+ f->ebuf = buf+len;
         Memcpy(buf, s, len);
         return f;
 }
-/*
-void rewind(io *io)
+
+void
+iorewind(io *io)
 {
- if(io->fd==-1) io->bufp=io->strp;
+ if(io->fd==-1)
+ io->bufp = io->strp;
         else{
- io->bufp=io->ebuf=io->buf;
+ io->bufp = io->ebuf = io->buf;
                 Seek(io->fd, 0L, 0);
         }
 }
-*/
-void closeio(io *io)
+
+void
+closeio(io *io)
 {
- if(io->fd>=0) close(io->fd);
- if(io->strp) efree(io->strp);
+ if(io->fd>=0)
+ close(io->fd);
+ if(io->strp)
+ efree(io->strp);
         efree((char *)io);
 }
-int emptybuf(io *f)
+
+int
+emptybuf(io *f)
 {
         int n;
- if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF;
- f->bufp=f->buf;
- f->ebuf=f->buf+n;
+ 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++&0xff;
 }
diff -r bb17f966e24a -r 1161d90df941 rc/io.h
--- a/rc/io.h Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/io.h Fri Jul 31 21:02:58 2009 +0100
@@ -18,9 +18,9 @@
 void closeio(io*);
 void flush(io*);
 int fullbuf(io*, int);
-void pdec(io*, long);
-void poct(io*, ulong);
-void phex(io*, long);
+void pdec(io*, int);
+void poct(io*, unsigned);
+void pptr(io*, void*);
 void pquo(io*, char*);
 void pwrd(io*, char*);
 void pstr(io*, char*);
diff -r bb17f966e24a -r 1161d90df941 rc/lex.c
--- a/rc/lex.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/lex.c Fri Jul 31 21:02:58 2009 +0100
@@ -4,11 +4,15 @@
 #include "getflags.h"
 #include "fns.h"
 int getnext(void);
-int wordchr(int c)
+
+int
+wordchr(int c)
 {
         return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
 }
-int idchr(int c)
+
+int
+idchr(int c)
 {
         /*
          * Formerly:
@@ -17,127 +21,170 @@
          */
         return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
 }
-int future=EOF;
-int doprompt=1;
+int future = EOF;
+int doprompt = 1;
 int inquote;
+int incomm;
 /*
  * Look ahead in the input stream
  */
-int nextc(void){
- if(future==EOF) future=getnext();
+
+int
+nextc(void)
+{
+ if(future==EOF)
+ future = getnext();
         return future;
 }
 /*
  * Consume the lookahead character.
  */
-int advance(void){
- int c=nextc();
- lastc=future;
- future=EOF;
+
+int
+advance(void)
+{
+ int c = nextc();
+ lastc = future;
+ future = EOF;
         return c;
 }
 /*
  * read a character from the input stream
  */
-int getnext(void){
- register int c;
- static int peekc=EOF;
+
+int
+getnext(void)
+{
+ int c;
+ static int peekc = EOF;
         if(peekc!=EOF){
- c=peekc;
- peekc=EOF;
+ c = peekc;
+ peekc = EOF;
                 return c;
         }
- if(runq->eof) return EOF;
- if(doprompt) pprompt();
- c=rchr(runq->cmdfd);
+ if(runq->eof)
+ return EOF;
+ if(doprompt)
+ pprompt();
+ c = rchr(runq->cmdfd);
         if(!inquote && c=='\\'){
- c=rchr(runq->cmdfd);
- if(c=='\n'){
- doprompt=1;
+ c = rchr(runq->cmdfd);
+ if(c=='\n' && !incomm){ /* don't continue a comment */
+ doprompt = 1;
                         c=' ';
                 }
                 else{
- peekc=c;
+ peekc = c;
                         c='\\';
                 }
         }
- doprompt=doprompt || c=='\n' || c==EOF;
- if(c==EOF) runq->eof++;
+ doprompt = doprompt || c=='\n' || c==EOF;
+ if(c==EOF)
+ runq->eof++;
         else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
         return c;
 }
-void pprompt(void){
+
+void
+pprompt(void)
+{
         var *prompt;
         if(runq->iflag){
                 pstr(err, promptstr);
                 flush(err);
- prompt=vlook("prompt");
+ prompt = vlook("prompt");
                 if(prompt->val && prompt->val->next)
- promptstr=prompt->val->next->word;
+ promptstr = prompt->val->next->word;
                 else
                         promptstr="\t";
         }
         runq->lineno++;
- doprompt=0;
+ doprompt = 0;
 }
-void skipwhite(void){
+
+void
+skipwhite(void)
+{
         int c;
         for(;;){
- c=nextc();
- if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */
+ c = nextc();
+ /* Why did this used to be if(!inquote && c=='#') ?? */
+ if(c=='#'){
+ incomm = 1;
                         for(;;){
- c=nextc();
- if(c=='\n' || c==EOF) break;
+ c = nextc();
+ if(c=='\n' || c==EOF) {
+ incomm = 0;
+ break;
+ }
                                 advance();
                         }
                 }
- if(c==' ' || c=='\t') advance();
+ if(c==' ' || c=='\t')
+ advance();
                 else return;
         }
 }
-void skipnl(void){
- register int c;
+
+void
+skipnl(void)
+{
+ int c;
         for(;;){
                 skipwhite();
- c=nextc();
- if(c!='\n') return;
+ c = nextc();
+ if(c!='\n')
+ return;
                 advance();
         }
 }
-int nextis(int c){
+
+int
+nextis(int c)
+{
         if(nextc()==c){
                 advance();
                 return 1;
         }
         return 0;
 }
-char *addtok(char *p, int val){
- if(p==0) return 0;
- if(p==&tok[NTOK]){
- *p=0;
+
+char*
+addtok(char *p, int val)
+{
+ if(p==0)
+ return 0;
+ if(p==&tok[NTOK-1]){
+ *p = 0;
                 yyerror("token buffer too short");
                 return 0;
         }
         *p++=val;
         return p;
 }
-char *addutf(char *p, int c){
- p=addtok(p, c);
+
+char*
+addutf(char *p, int c)
+{
+ p = addtok(p, c);
         if(twobyte(c)) /* 2-byte escape */
                 return addtok(p, advance());
         if(threebyte(c)){ /* 3-byte escape */
- p=addtok(p, advance());
+ p = addtok(p, advance());
                 return addtok(p, advance());
         }
         return p;
 }
 int lastdol; /* was the last token read '$' or '$#' or '"'? */
 int lastword; /* was the last token read a word or compound word terminator? */
-int yylex(void){
- register int c, d=nextc();
- register char *w=tok;
- register struct tree *t;
- yylval.tree=0;
+
+int
+yylex(void)
+{
+ int 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
@@ -146,7 +193,7 @@
          * we insert a `^' before it.
          */
         if(lastword){
- lastword=0;
+ lastword = 0;
                 if(d=='('){
                         advance();
                         strcpy(tok, "( [SUB]");
@@ -157,15 +204,15 @@
                         return '^';
                 }
         }
- inquote=0;
+ inquote = 0;
         skipwhite();
- switch(c=advance()){
+ switch(c = advance()){
         case EOF:
- lastdol=0;
+ lastdol = 0;
                 strcpy(tok, "EOF");
                 return EOF;
         case '$':
- lastdol=1;
+ lastdol = 1;
                 if(nextis('#')){
                         strcpy(tok, "$#");
                         return COUNT;
@@ -177,7 +224,7 @@
                 strcpy(tok, "$");
                 return '$';
         case '&':
- lastdol=0;
+ lastdol = 0;
                 if(nextis('&')){
                         skipnl();
                         strcpy(tok, "&&");
@@ -186,7 +233,7 @@
                 strcpy(tok, "&");
                 return '&';
         case '|':
- lastdol=0;
+ lastdol = 0;
                 if(nextis(c)){
                         skipnl();
                         strcpy(tok, "||");
@@ -194,7 +241,7 @@
                 }
         case '<':
         case '>':
- lastdol=0;
+ lastdol = 0;
                 /*
                  * funny redirection tokens:
                  * redir: arrow | arrow '[' fd ']'
@@ -204,121 +251,128 @@
                  * some possibilities are nonsensical and get a message.
                  */
                 *w++=c;
- t=newtree();
+ t = newtree();
                 switch(c){
                 case '|':
- t->type=PIPE;
- t->fd0=1;
- t->fd1=0;
+ t->type = PIPE;
+ t->fd0 = 1;
+ t->fd1 = 0;
                         break;
                 case '>':
- t->type=REDIR;
+ t->type = REDIR;
                         if(nextis(c)){
- t->rtype=APPEND;
+ t->rtype = APPEND;
                                 *w++=c;
                         }
- else t->rtype=WRITE;
- t->fd0=1;
+ else t->rtype = WRITE;
+ t->fd0 = 1;
                         break;
                 case '<':
- t->type=REDIR;
+ t->type = REDIR;
                         if(nextis(c)){
- t->rtype=HERE;
+ t->rtype = HERE;
                                 *w++=c;
- }
- else t->rtype=READ;
- t->fd0=0;
+ } else if (nextis('>')){
+ t->rtype = RDWR;
+ *w++=c;
+ } else t->rtype = READ;
+ t->fd0 = 0;
                         break;
                 }
                 if(nextis('[')){
                         *w++='[';
- c=advance();
+ c = advance();
+ *w++=c;
                         if(c<'0' || '9'<c){
                         RedirErr:
- *w++ = c;
- *w=0;
+ *w = 0;
                                 yyerror(t->type==PIPE?"pipe syntax"
                                                 :"redirection syntax");
                                 return EOF;
                         }
- t->fd0=0;
+ t->fd0 = 0;
                         do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
                                 *w++=c;
- c=advance();
+ c = advance();
                         }while('0'<=c && c<='9');
                         if(c=='='){
                                 *w++='=';
- if(t->type==REDIR) t->type=DUP;
- c=advance();
+ if(t->type==REDIR)
+ t->type = DUP;
+ c = advance();
                                 if('0'<=c && c<='9'){
- t->rtype=DUPFD;
- t->fd1=t->fd0;
- t->fd0=0;
+ t->rtype = DUPFD;
+ t->fd1 = t->fd0;
+ t->fd0 = 0;
                                         do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
                                                 *w++=c;
- c=advance();
+ c = advance();
                                         }while('0'<=c && c<='9');
                                 }
                                 else{
- if(t->type==PIPE) goto RedirErr;
- t->rtype=CLOSE;
+ if(t->type==PIPE)
+ goto RedirErr;
+ t->rtype = CLOSE;
                                 }
                         }
- *w=0;
                         if(c!=']'
                         || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
                                 goto RedirErr;
                         *w++=']';
                 }
                 *w='\0';
- yylval.tree=t;
- if(t->type==PIPE) skipnl();
+ yylval.tree = t;
+ if(t->type==PIPE)
+ skipnl();
                 return t->type;
         case '\'':
- lastdol=0;
- lastword=1;
- inquote=1;
+ lastdol = 0;
+ lastword = 1;
+ inquote = 1;
                 for(;;){
- c=advance();
- if(c==EOF) break;
+ c = advance();
+ if(c==EOF)
+ break;
                         if(c=='\''){
                                 if(nextc()!='\'')
                                         break;
                                 advance();
                         }
- w=addutf(w, c);
+ w = addutf(w, c);
                 }
- if(w!=0) *w='\0';
- t=token(tok, WORD);
- t->quoted=1;
- yylval.tree=t;
+ if(w!=0)
+ *w='\0';
+ t = token(tok, WORD);
+ t->quoted = 1;
+ yylval.tree = t;
                 return t->type;
         }
         if(!wordchr(c)){
- lastdol=0;
- tok[0]=c;
+ lastdol = 0;
+ tok[0] = c;
                 tok[1]='\0';
                 return c;
         }
         for(;;){
                 /* next line should have (char)c==GLOB, but ken's compiler is broken */
                 if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
- w=addtok(w, GLOB);
- w=addutf(w, c);
- c=nextc();
+ w = addtok(w, GLOB);
+ w = addutf(w, c);
+ c = nextc();
                 if(lastdol?!idchr(c):!wordchr(c)) break;
                 advance();
         }
 
- lastword=1;
- lastdol=0;
- if(w!=0) *w='\0';
- t=klook(tok);
- if(t->type!=WORD) lastword=0;
- t->quoted=0;
- yylval.tree=t;
+ lastword = 1;
+ lastdol = 0;
+ if(w!=0)
+ *w='\0';
+ t = klook(tok);
+ if(t->type!=WORD)
+ lastword = 0;
+ t->quoted = 0;
+ yylval.tree = t;
         return t->type;
 }
-
diff -r bb17f966e24a -r 1161d90df941 rc/pcmd.c
--- a/rc/pcmd.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/pcmd.c Fri Jul 31 21:02:58 2009 +0100
@@ -5,39 +5,66 @@
 #define c0 t->child[0]
 #define c1 t->child[1]
 #define c2 t->child[2]
-void pdeglob(io *f, char *s)
+
+void
+pdeglob(io *f, char *s)
 {
         while(*s){
- if(*s==GLOB) s++;
+ if(*s==GLOB)
+ s++;
                 pchr(f, *s++);
         }
 }
-void pcmd(io *f, tree *t)
+
+void
+pcmd(io *f, tree *t)
 {
- if(t==0) return;
+ 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", c0); break;
- case ANDAND: pfmt(f, "%t && %t", c0, c1); break;
- case BANG: pfmt(f, "! %t", c0); break;
- case BRACE: pfmt(f, "{%t}", c0); 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;
+ 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", c0);
+ break;
+ case ANDAND: pfmt(f, "%t && %t", c0, c1);
+ break;
+ case BANG: pfmt(f, "! %t", c0);
+ break;
+ case BRACE: pfmt(f, "{%t}", c0);
+ 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 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);
@@ -48,22 +75,26 @@
                 break;
         case ';':
                 if(c0){
- if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
+ if(c1)
+ pfmt(f, "%t%c%t", c0, nl, c1);
                         else pfmt(f, "%t", c0);
                 }
                 else pfmt(f, "%t", c1);
                 break;
         case WORDS:
- if(c0) pfmt(f, "%t ", c0);
+ 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);
+ if(c1)
+ pfmt(f, " in %t", c1);
                 pfmt(f, ")%t", c2);
                 break;
         case WORD:
- if(t->quoted) pfmt(f, "%Q", t->str);
+ if(t->quoted)
+ pfmt(f, "%Q", t->str);
                 else pdeglob(f, t->str);
                 break;
         case DUP:
@@ -79,27 +110,35 @@
                 case HERE:
                         pchr(f, '<');
                 case READ:
+ case RDWR:
                         pchr(f, '<');
- if(t->fd0!=0) pfmt(f, "[%d]", t->fd0);
+ 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);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
                         break;
                 }
                 pfmt(f, "%t", c0);
- if(c1) pfmt(f, " %t", c1);
+ if(c1)
+ pfmt(f, " %t", c1);
                 break;
         case '=':
                 pfmt(f, "%t=%t", c0, c1);
- if(c2) pfmt(f, " %t", c2);
+ 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);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
                 }
                 else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
                 pfmt(f, "%t", c1);
diff -r bb17f966e24a -r 1161d90df941 rc/pfnc.c
--- a/rc/pfnc.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/pfnc.c Fri Jul 31 21:02:58 2009 +0100
@@ -5,7 +5,7 @@
 struct{
         void (*f)(void);
         char *name;
-}fname[]={
+}fname[] = {
         Xappend, "Xappend",
         Xasync, "Xasync",
         Xbang, "Xbang",
@@ -18,6 +18,7 @@
         Xjump, "Xjump",
         Xmark, "Xmark",
         Xpopm, "Xpopm",
+ Xrdwr, "Xrdwr",
         Xread, "Xread",
         Xreturn, "Xreturn",
         Xtrue, "Xtrue",
@@ -50,18 +51,21 @@
         Xrdfn, "Xrdfn",
         Xqdol, "Xqdol",
 0};
-void pfnc(io *fd, thread *t)
+
+void
+pfnc(io *fd, thread *t)
 {
         int i;
- void (*fn)(void)=t->code[t->pc].f;
+ void (*fn)(void) = t->code[t->pc].f;
         list *a;
         pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
- for(i=0;fname[i].f;i++) if(fname[i].f==fn){
+ 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) pfmt(fd, " (%v)", a->words);
+ if(!fname[i].f)
+ pfmt(fd, "%p", fn);
+ for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
         pchr(fd, '\n');
         flush(fd);
 }
diff -r bb17f966e24a -r 1161d90df941 rc/plan9ish.c
--- a/rc/plan9ish.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/plan9ish.c Fri Jul 31 21:02:58 2009 +0100
@@ -27,12 +27,11 @@
 char*
 Rcmain(void)
 {
- static char Rcmain[] = PREFIX"/etc/rcmain";
- char *rcmain = getenv("RCMAIN");
- return rcmain ? rcmain : Rcmain;
+ return unsharp("#9/rcmain");
 }
 
 char Fdprefix[]="/dev/fd/";
+long readnb(int, char *, long);
 void execfinit(void);
 void execbind(void);
 void execmount(void);
@@ -129,7 +128,7 @@
                 for(s=*env;*s && *s!='(' && *s!='=';s++);
                 switch(*s){
                 case '\0':
- // pfmt(err, "rc: odd environment %q?\n", *env);
+ /* pfmt(err, "rc: odd environment %q?\n", *env); */
                         break;
                 case '=':
                         *s='\0';
@@ -200,7 +199,10 @@
         Waitmsg *w;
         char errbuf[ERRMAX];
 
+ if(pid >= 0 && !havewaitpid(pid))
+ return 0;
         while((w = wait()) != nil){
+ delwaitpid(w->pid);
                 if(w->pid==pid){
                         if(strncmp(w->msg, "signal: ", 8) == 0)
                                 fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
@@ -208,7 +210,7 @@
                         free(w);
                         return 0;
                 }
- if(strncmp(w->msg, "signal: ", 8) == 0)
+ if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
                         fprint(2, "%d: %s\n", w->pid, w->msg);
                 for(p=runq->ret;p;p=p->ret)
                         if(p->pid==w->pid){
@@ -218,7 +220,7 @@
                 free(w);
         }
 
- errstr(errbuf, sizeof errbuf);
+ rerrstr(errbuf, sizeof errbuf);
         if(strcmp(errbuf, "interrupted")==0) return -1;
         return 0;
 }
@@ -412,9 +414,11 @@
         close(f);
         return -1;
 }
-int Readdir(int f, char *p)
+int Readdir(int f, char *p, int onlydirs)
 {
         int n;
+ USED(onlydirs); /* only advisory */
+
         if(f<0 || f>=NFD)
                 return 0;
         if(dir[f].i==dir[f].n){ /* read */
@@ -490,7 +494,7 @@
 {
         int i;
 
- i = read(fd, buf, cnt);
+ i = readnb(fd, buf, cnt);
         if(ntrap) dotrap();
         return i;
 }
@@ -547,3 +551,54 @@
 void *Malloc(ulong n){
         return malloc(n);
 }
+
+int
+exitcode(char *msg)
+{
+ int n;
+
+ n = atoi(msg);
+ if(n == 0)
+ n = 1;
+ return n;
+}
+
+int *waitpids;
+int nwaitpids;
+
+void
+addwaitpid(int pid)
+{
+ waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
+ if(waitpids == 0)
+ panic("Can't realloc %d waitpids", nwaitpids+1);
+ 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;
+}
diff -r bb17f966e24a -r 1161d90df941 rc/rc.1
--- a/rc/rc.1 Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/rc.1 Fri Jul 31 21:02:58 2009 +0100
@@ -208,6 +208,11 @@
 is followed by a parenthesized list of subscripts, the
 value substituted is a list composed of the requested elements (origin 1).
 The parenthesis must follow the variable name with no spaces.
+Subscripts can also take the form
+.IB m - n
+or
+.IB m -
+to indicate a sequence of elements.
 Assignments to variables are described below.
 .HP
 .BI $# argument
diff -r bb17f966e24a -r 1161d90df941 rc/rc.h
--- a/rc/rc.h Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/rc.h Fri Jul 31 21:02:58 2009 +0100
@@ -26,7 +26,7 @@
 #define YYMAXDEPTH 500
 #ifndef PAREN
 #ifndef YYMAJOR
-#include "y.tab.h"
+#include "x.tab.h"
 #endif
 #endif
 
@@ -80,6 +80,7 @@
 #define HERE 4
 #define DUPFD 5
 #define CLOSE 6
+#define RDWR 7
 struct var{
         char *name; /* ascii name */
         word *val; /* value */
diff -r bb17f966e24a -r 1161d90df941 rc/simple.c
--- a/rc/simple.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/simple.c Fri Jul 31 21:02:58 2009 +0100
@@ -15,22 +15,24 @@
         while(c->f==Xpopredir) c++;
         return c->f==Xexit;
 }
-void Xsimple(void){
+
+void
+Xsimple(void)
+{
         word *a;
- thread *p=runq;
+ thread *p = runq;
         var *v;
         struct builtin *bp;
- int pid, n;
- char buf[ERRMAX];
+ int pid;
         globlist();
- a=runq->argv->words;
+ a = runq->argv->words;
         if(a==0){
                 Xerror1("empty argument list");
                 return;
         }
         if(flag['x'])
                 pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
- v=gvlook(a->word);
+ v = gvlook(a->word);
         if(v->fn)
                 execfunc(v);
         else{
@@ -41,10 +43,10 @@
                                 poplist();
                                 return;
                         }
- a=a->next;
+ a = a->next;
                         popword();
                 }
- for(bp=Builtin;bp->name;bp++)
+ for(bp = Builtin;bp->name;bp++)
                         if(strcmp(a->word, bp->name)==0){
                                 (*bp->fnc)();
                                 return;
@@ -58,30 +60,22 @@
                 else{
                         flush(err);
                         Updenv(); /* necessary so changes don't go out again */
- switch(pid=fork()){
- case -1:
+ if((pid = execforkexec()) < 0){
                                 Xerror("try again");
                                 return;
- case 0:
- pushword("exec");
- execexec();
- strcpy(buf, "can't exec: ");
- n = strlen(buf);
- errstr(buf+n, ERRMAX-n);
- Exit(buf);
- default:
- kidpid = pid;
- poplist();
- /* interrupts don't get us out */
- while(Waitfor(pid, 1) < 0)
- ;
- kidpid = 0;
                         }
+
+ /* interrupts don't get us out */
+ poplist();
+ while(Waitfor(pid, 1) < 0)
+ ;
                 }
         }
 }
-struct word nullpath={ "", 0};
-void doredir(redir *rp)
+struct word nullpath = { "", 0};
+
+void
+doredir(redir *rp)
 {
         if(rp){
                 doredir(rp->next);
@@ -92,22 +86,32 @@
                                 close(rp->from);
                         }
                         break;
- case RDUP: Dup(rp->from, rp->to); break;
- case RCLOSE: close(rp->from); break;
+ case RDUP:
+ Dup(rp->from, rp->to);
+ break;
+ case RCLOSE:
+ close(rp->from);
+ break;
                 }
         }
 }
-word *searchpath(char *w){
+
+word*
+searchpath(char *w)
+{
         word *path;
         if(strncmp(w, "/", 1)==0
 /* || strncmp(w, "#", 1)==0 */
         || strncmp(w, "./", 2)==0
         || strncmp(w, "../", 3)==0
- || (path=vlook("path")->val)==0)
+ || (path = vlook("path")->val)==0)
                 path=&nullpath;
         return path;
 }
-void execexec(void){
+
+void
+execexec(void)
+{
         popword(); /* "exec" */
         if(runq->argv->words==0){
                 Xerror1("empty argument list");
@@ -117,19 +121,24 @@
         Execute(runq->argv->words, searchpath(runq->argv->words->word));
         poplist();
 }
-void execfunc(var *func)
+
+void
+execfunc(var *func)
 {
         word *starval;
         popword();
- starval=runq->argv->words;
- runq->argv->words=0;
+ starval = runq->argv->words;
+ runq->argv->words = 0;
         poplist();
- start(func->fn, func->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=starval;
- runq->local->changed=1;
+ start(func->fn, func->pc, runq->local);
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = starval;
+ runq->local->changed = 1;
 }
-int dochdir(char *word){
+
+int
+dochdir(char *word)
+{
         /* report to /dev/wdir if it exists and we're interactive */
         static int wdirfd = -2;
         if(chdir(word)<0) return -1;
@@ -141,21 +150,26 @@
         }
         return 1;
 }
-void execcd(void){
- word *a=runq->argv->words;
+
+void
+execcd(void)
+{
+ word *a = runq->argv->words;
         word *cdpath;
         char dir[512];
         setstatus("can't cd");
- cdpath=vlook("cdpath")->val;
+ cdpath = vlook("cdpath")->val;
         switch(count(a)){
         default:
                 pfmt(err, "Usage: cd [directory]\n");
                 break;
         case 2:
- if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
- for(;cdpath;cdpath=cdpath->next){
+ if(a->next->word[0]=='/' || cdpath==0)
+ cdpath=&nullpath;
+ for(;cdpath;cdpath = cdpath->next){
                         strcpy(dir, cdpath->word);
- if(dir[0]) strcat(dir, "/");
+ if(dir[0])
+ strcat(dir, "/");
                         strcat(dir, a->next->word);
                         if(dochdir(dir)>=0){
                                 if(strlen(cdpath->word)
@@ -165,10 +179,11 @@
                                 break;
                         }
                 }
- if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
+ if(cdpath==0)
+ pfmt(err, "Can't cd %s: %r\n", a->next->word);
                 break;
         case 1:
- a=vlook("HOME")->val;
+ a = vlook("home")->val;
                 if(count(a)>=1){
                         if(dochdir(a->word)>=0)
                                 setstatus("");
@@ -181,14 +196,22 @@
         }
         poplist();
 }
-void execexit(void){
+
+void
+execexit(void)
+{
         switch(count(runq->argv->words)){
- default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
- case 2: setstatus(runq->argv->words->next->word);
+ default:
+ pfmt(err, "Usage: exit [status]\nExiting anyway\n");
+ case 2:
+ setstatus(runq->argv->words->next->word);
         case 1: Xexit();
         }
 }
-void execshift(void){
+
+void
+execshift(void)
+{
         int n;
         word *a;
         var *star;
@@ -198,72 +221,87 @@
                 setstatus("shift usage");
                 poplist();
                 return;
- case 2: n=atoi(runq->argv->words->next->word); break;
- case 1: n=1; break;
+ case 2:
+ n = atoi(runq->argv->words->next->word);
+ break;
+ case 1:
+ n = 1;
+ break;
         }
- star=vlook("*");
+ star = vlook("*");
         for(;n && star->val;--n){
- a=star->val->next;
+ a = star->val->next;
                 efree(star->val->word);
                 efree((char *)star->val);
- star->val=a;
- star->changed=1;
+ star->val = a;
+ star->changed = 1;
         }
         setstatus("");
         poplist();
 }
-int octal(char *s)
+
+int
+octal(char *s)
 {
- int n=0;
+ int n = 0;
         while(*s==' ' || *s=='\t' || *s=='\n') s++;
- while('0'<=*s && *s<='7') n=n*8+*s++-'0';
+ while('0'<=*s && *s<='7') n = n*8+*s++-'0';
         return n;
 }
-int mapfd(int fd)
+
+int
+mapfd(int fd)
 {
         redir *rp;
- for(rp=runq->redir;rp;rp=rp->next){
+ for(rp = runq->redir;rp;rp = rp->next){
                 switch(rp->type){
                 case RCLOSE:
- if(rp->from==fd) fd=-1;
+ if(rp->from==fd)
+ fd=-1;
                         break;
                 case RDUP:
                 case ROPEN:
- if(rp->to==fd) fd=rp->from;
+ if(rp->to==fd)
+ fd = rp->from;
                         break;
                 }
         }
         return fd;
 }
 union code rdcmds[4];
-void execcmds(io *f)
+
+void
+execcmds(io *f)
 {
- static int first=1;
+ static int first = 1;
         if(first){
- rdcmds[0].i=1;
- rdcmds[1].f=Xrdcmds;
- rdcmds[2].f=Xreturn;
- first=0;
+ rdcmds[0].i = 1;
+ rdcmds[1].f = Xrdcmds;
+ rdcmds[2].f = Xreturn;
+ first = 0;
         }
         start(rdcmds, 1, runq->local);
- runq->cmdfd=f;
- runq->iflast=0;
+ runq->cmdfd = f;
+ runq->iflast = 0;
 }
-void execeval(void){
+
+void
+execeval(void)
+{
         char *cmdline, *s, *t;
- int len=0;
+ int len = 0;
         word *ap;
         if(count(runq->argv->words)<=1){
                 Xerror1("Usage: eval cmd ...");
                 return;
         }
- eflagok=1;
- for(ap=runq->argv->words->next;ap;ap=ap->next)
+ eflagok = 1;
+ for(ap = runq->argv->words->next;ap;ap = ap->next)
                 len+=1+strlen(ap->word);
- cmdline=emalloc(len);
- s=cmdline;
- for(ap=runq->argv->words->next;ap;ap=ap->next){
- for(t=ap->word;*t;) *s++=*t++;
+ cmdline = emalloc(len);
+ s = cmdline;
+ for(ap = runq->argv->words->next;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
                 *s++=' ';
         }
         s[-1]='\n';
@@ -272,36 +310,39 @@
         efree(cmdline);
 }
 union code dotcmds[14];
-void execdot(void){
- int iflag=0;
+
+void
+execdot(void)
+{
+ int iflag = 0;
         int fd;
         list *av;
- thread *p=runq;
+ thread *p = runq;
         char *zero;
- static int first=1;
+ static int first = 1;
         char file[512];
         word *path;
         if(first){
- dotcmds[0].i=1;
- dotcmds[1].f=Xmark;
- dotcmds[2].f=Xword;
+ dotcmds[0].i = 1;
+ dotcmds[1].f = Xmark;
+ dotcmds[2].f = Xword;
                 dotcmds[3].s="0";
- dotcmds[4].f=Xlocal;
- dotcmds[5].f=Xmark;
- dotcmds[6].f=Xword;
+ dotcmds[4].f = Xlocal;
+ dotcmds[5].f = Xmark;
+ dotcmds[6].f = Xword;
                 dotcmds[7].s="*";
- dotcmds[8].f=Xlocal;
- dotcmds[9].f=Xrdcmds;
- dotcmds[10].f=Xunlocal;
- dotcmds[11].f=Xunlocal;
- dotcmds[12].f=Xreturn;
- first=0;
+ dotcmds[8].f = Xlocal;
+ dotcmds[9].f = Xrdcmds;
+ dotcmds[10].f = Xunlocal;
+ dotcmds[11].f = Xunlocal;
+ dotcmds[12].f = Xreturn;
+ first = 0;
         }
         else
- eflagok=1;
+ eflagok = 1;
         popword();
         if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
- iflag=1;
+ iflag = 1;
                 popword();
         }
         /* get input file */
@@ -309,18 +350,20 @@
                 Xerror1("Usage: . [-i] file [arg ...]");
                 return;
         }
- zero=strdup(p->argv->words->word);
+ zero = strdup(p->argv->words->word);
         popword();
         fd=-1;
- for(path=searchpath(zero);path;path=path->next){
+ for(path = searchpath(zero);path;path = path->next){
                 strcpy(file, path->word);
- if(file[0]) strcat(file, "/");
+ if(file[0])
+ strcat(file, "/");
                 strcat(file, zero);
+ if((fd = open(file, 0))>=0) break;
                 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
- fd=Dup1(0);
- if(fd>=0) break;
+ fd = Dup1(0);
+ if(fd>=0)
+ break;
                 }
- if((fd=open(file, 0))>=0) break;
         }
         if(fd<0){
                 pfmt(err, "%s: ", zero);
@@ -331,38 +374,41 @@
         /* set up for a new command loop */
         start(dotcmds, 1, (struct var *)0);
         pushredir(RCLOSE, fd, 0);
- runq->cmdfile=zero;
- runq->cmdfd=openfd(fd);
- runq->iflag=iflag;
- runq->iflast=0;
+ runq->cmdfile = zero;
+ runq->cmdfd = openfd(fd);
+ runq->iflag = iflag;
+ runq->iflast = 0;
         /* push $* value */
         pushlist();
- runq->argv->words=p->argv->words;
+ runq->argv->words = p->argv->words;
         /* free caller's copy of $* */
- av=p->argv;
- p->argv=av->next;
+ av = p->argv;
+ p->argv = av->next;
         efree((char *)av);
         /* push $0 value */
         pushlist();
         pushword(zero);
         ndot++;
 }
-void execflag(void){
+
+void
+execflag(void)
+{
         char *letter, *val;
         switch(count(runq->argv->words)){
         case 2:
                 setstatus(flag[(uchar)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;
+ letter = runq->argv->words->next->word;
+ val = runq->argv->words->next->next->word;
                 if(strlen(letter)==1){
                         if(strcmp(val, "+")==0){
- flag[(uchar)letter[0]]=flagset;
+ flag[(uchar)letter[0]] = flagset;
                                 break;
                         }
                         if(strcmp(val, "-")==0){
- flag[(uchar)letter[0]]=0;
+ flag[(uchar)letter[0]] = 0;
                                 break;
                         }
                 }
@@ -372,53 +418,57 @@
         }
         poplist();
 }
-void execwhatis(void){ /* mildly wrong -- should fork before writing */
+
+void
+execwhatis(void){ /* mildly wrong -- should fork before writing */
         word *a, *b, *path;
         var *v;
         struct builtin *bp;
         char file[512];
         struct io out[1];
         int found, sep;
- a=runq->argv->words->next;
+ a = runq->argv->words->next;
         if(a==0){
                 Xerror1("Usage: whatis name ...");
                 return;
         }
         setstatus("");
- out->fd=mapfd(1);
- out->bufp=out->buf;
- out->ebuf=&out->buf[NBUF];
- out->strp=0;
- for(;a;a=a->next){
- v=vlook(a->word);
+ out->fd = mapfd(1);
+ out->bufp = out->buf;
+ out->ebuf = &out->buf[NBUF];
+ out->strp = 0;
+ 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){
+ for(b = v->val;b && b->word;b = b->next){
                                         pfmt(out, "%c%q", sep, b->word);
                                         sep=' ';
                                 }
                                 pfmt(out, ")\n");
                         }
- found=1;
+ found = 1;
                 }
                 else
- found=0;
- v=gvlook(a->word);
- if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
+ found = 0;
+ v = gvlook(a->word);
+ if(v->fn)
+ pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
                 else{
- for(bp=Builtin;bp->name;bp++)
+ for(bp = Builtin;bp->name;bp++)
                                 if(strcmp(a->word, bp->name)==0){
                                         pfmt(out, "builtin %s\n", a->word);
                                         break;
                                 }
                         if(!bp->name){
- for(path=searchpath(a->word);path;path=path->next){
+ for(path = searchpath(a->word);path;path = path->next){
                                         strcpy(file, path->word);
- if(file[0]) strcat(file, "/");
+ if(file[0])
+ strcat(file, "/");
                                         strcat(file, a->word);
                                         if(Executable(file)){
                                                 pfmt(out, "%s\n", file);
@@ -435,11 +485,20 @@
         poplist();
         flush(err);
 }
-void execwait(void){
+
+void
+execwait(void)
+{
         switch(count(runq->argv->words)){
- default: Xerror1("Usage: wait [pid]"); return;
- case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
- case 1: Waitfor(-1, 0); break;
+ default:
+ Xerror1("Usage: wait [pid]");
+ return;
+ case 2:
+ Waitfor(atoi(runq->argv->words->next->word), 0);
+ break;
+ case 1:
+ Waitfor(-1, 0);
+ break;
         }
         poplist();
 }
diff -r bb17f966e24a -r 1161d90df941 rc/subr.c
--- a/rc/subr.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/subr.c Fri Jul 31 21:02:58 2009 +0100
@@ -2,20 +2,30 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-char *emalloc(long n){
- char *p=(char *)Malloc(n);
- if(p==0) panic("Can't malloc %d bytes", n);
-/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } *//**/
+
+char*
+emalloc(long n)
+{
+ char *p = (char *)Malloc(n);
+ if(p==0)
+ panic("Can't malloc %d bytes", n);
+/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
+ memset(p, 0, n);
         return p;
 }
-void efree(char *p)
+
+void
+efree(char *p)
 {
-/* pfmt(err, "free %p\n", p); flush(err); *//**/
- if(p) free(p);
+/* pfmt(err, "free %p\n", p); flush(err); /**/
+ if(p)
+ free(p);
         else pfmt(err, "free 0\n");
 }
 extern int lastword, lastdol;
-void yyerror(char *m)
+
+void
+yyerror(char *m)
 {
         pfmt(err, "rc: ");
         if(runq->cmdfile && !runq->iflag)
@@ -24,17 +34,21 @@
                 pfmt(err, "%s: ", runq->cmdfile);
         else if(!runq->iflag)
                 pfmt(err, "line %d: ", runq->lineno);
- if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok);
+ if(tok[0] && tok[0]!='\n')
+ pfmt(err, "token %q: ", tok);
         pfmt(err, "%s\n", m);
         flush(err);
- lastword=0;
- lastdol=0;
+ lastword = 0;
+ lastdol = 0;
         while(lastc!='\n' && lastc!=EOF) advance();
         nerror++;
         setvar("status", newword(m, (word *)0));
 }
 char *bp;
-void iacvt(int n){
+
+static void
+iacvt(int n)
+{
         if(n<0){
                 *bp++='-';
                 n=-n; /* doesn't work for n==-inf */
@@ -43,13 +57,17 @@
                 iacvt(n/10);
         *bp++=n%10+'0';
 }
-void itoa(char *s, long n)
+
+void
+inttoascii(char *s, long n)
 {
- bp=s;
+ bp = s;
         iacvt(n);
         *bp='\0';
 }
-void panic(char *s, int n)
+
+void
+panic(char *s, int n)
 {
         pfmt(err, "rc: ");
         pfmt(err, s, n);
diff -r bb17f966e24a -r 1161d90df941 rc/trap.c
--- a/rc/trap.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/trap.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,22 +3,25 @@
 #include "fns.h"
 #include "io.h"
 extern char *Signame[];
-void dotrap(void){
- register int i;
- register struct var *trapreq;
- register struct word *starval;
- starval=vlook("*")->val;
- while(ntrap) for(i=0;i!=NSIG;i++) while(trap[i]){
+
+void
+dotrap(void)
+{
+ int i;
+ struct var *trapreq;
+ struct word *starval;
+ starval = vlook("*")->val;
+ while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
                 --trap[i];
                 --ntrap;
                 if(getpid()!=mypid) Exit(getstatus());
- trapreq=vlook(Signame[i]);
+ trapreq = vlook(Signame[i]);
                 if(trapreq->fn){
                         start(trapreq->fn, trapreq->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=copywords(starval, (struct word *)0);
- runq->local->changed=1;
- runq->redir=runq->startredir=0;
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = copywords(starval, (struct word *)0);
+ runq->local->changed = 1;
+ runq->redir = runq->startredir = 0;
                 }
                 else if(i==SIGINT || i==SIGQUIT){
                         /*
diff -r bb17f966e24a -r 1161d90df941 rc/tree.c
--- a/rc/tree.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/tree.c Fri Jul 31 21:02:58 2009 +0100
@@ -7,108 +7,140 @@
  * create and clear a new tree node, and add it
  * to the node list.
  */
-tree *newtree(void){
- tree *t=new(tree);
- t->iskw=0;
- t->str=0;
- t->child[0]=t->child[1]=t->child[2]=0;
- t->next=treenodes;
- treenodes=t;
+
+tree*
+newtree(void)
+{
+ tree *t = new(tree);
+ t->iskw = 0;
+ t->str = 0;
+ t->child[0] = t->child[1] = t->child[2] = 0;
+ t->next = treenodes;
+ treenodes = t;
         return t;
 }
-void freenodes(void){
+
+void
+freenodes(void)
+{
         tree *t, *u;
- for(t=treenodes;t;t=u){
- u=t->next;
- if(t->str) efree(t->str);
+ for(t = treenodes;t;t = u){
+ u = t->next;
+ if(t->str)
+ efree(t->str);
                 efree((char *)t);
         }
- treenodes=0;
+ treenodes = 0;
 }
-tree *tree1(int type, tree *c0)
+
+tree*
+tree1(int type, tree *c0)
 {
         return tree3(type, c0, (tree *)0, (tree *)0);
 }
-tree *tree2(int type, tree *c0, tree *c1)
+
+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*
+tree3(int type, tree *c0, tree *c1, tree *c2)
 {
         tree *t;
         if(type==';'){
- if(c0==0) return c1;
- if(c1==0) return c0;
+ 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;
+ t = newtree();
+ t->type = type;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ t->child[2] = c2;
         return t;
 }
-tree *mung1(tree *t, tree *c0)
+
+tree*
+mung1(tree *t, tree *c0)
 {
- t->child[0]=c0;
+ t->child[0] = c0;
         return t;
 }
-tree *mung2(tree *t, tree *c0, tree *c1)
+
+tree*
+mung2(tree *t, tree *c0, tree *c1)
 {
- t->child[0]=c0;
- t->child[1]=c1;
+ t->child[0] = c0;
+ t->child[1] = c1;
         return t;
 }
-tree *mung3(tree *t, tree *c0, tree *c1, tree *c2)
+
+tree*
+mung3(tree *t, tree *c0, tree *c1, tree *c2)
 {
- t->child[0]=c0;
- t->child[1]=c1;
- t->child[2]=c2;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ t->child[2] = c2;
         return t;
 }
-tree *epimung(tree *comp, tree *epi)
+
+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;
+ 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*
+simplemung(tree *t)
 {
         tree *u;
         struct io *s;
- t=tree1(SIMPLE, t);
- s=openstr();
+ t = tree1(SIMPLE, t);
+ s = openstr();
         pfmt(s, "%t", t);
- t->str=strdup(s->strp);
+ t->str = strdup(s->strp);
         closeio(s);
- for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){
+ 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;
+ u->child[1]->child[1] = t;
+ t = u->child[1];
+ u->child[1] = 0;
                 }
         }
         return t;
 }
-tree *token(char *str, int type)
+
+tree*
+token(char *str, int type)
 {
- tree *t=newtree();
- t->type=type;
- t->str=strdup(str);
+ tree *t = newtree();
+ t->type = type;
+ t->str = strdup(str);
         return t;
 }
-void freetree(tree *p)
+
+void
+freetree(tree *p)
 {
- if(p==0) return;
+ if(p==0)
+ return;
         freetree(p->child[0]);
         freetree(p->child[1]);
         freetree(p->child[2]);
- if(p->str) efree(p->str);
+ if(p->str)
+ efree(p->str);
         efree((char *)p);
 }
diff -r bb17f966e24a -r 1161d90df941 rc/unixcrap.c
--- a/rc/unixcrap.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/unixcrap.c Fri Jul 31 21:02:58 2009 +0100
@@ -2,6 +2,8 @@
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/resource.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <libc.h>
 #include "rc.h"
 #include "exec.h"
@@ -209,3 +211,26 @@
         poplist();
         flush(err);
 }
+
+/*
+ * Cope with non-blocking read.
+ */
+long
+readnb(int fd, char *buf, long cnt)
+{
+ int n, didreset;
+ int flgs;
+
+ didreset = 0;
+ while((n = read(fd, buf, cnt)) == -1)
+ if(!didreset && errno == EAGAIN){
+ if((flgs = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ flgs &= ~O_NONBLOCK;
+ if(fcntl(fd, F_SETFL, flgs) == -1)
+ return -1;
+ didreset = 1;
+ }
+
+ return n;
+}
diff -r bb17f966e24a -r 1161d90df941 rc/var.c
--- a/rc/var.c Thu Feb 09 13:39:50 2006 +0100
+++ b/rc/var.c Fri Jul 31 21:02:58 2009 +0100
@@ -1,9 +1,11 @@
 #include "rc.h"
 #include "exec.h"
 #include "fns.h"
-int hash(char *s, int n)
+
+int
+hash(char *s, int n)
 {
- register int h=0, i=1;
+ int h = 0, i = 1;
         while(*s) h+=*s++*i++;
         h%=n;
         return h<0?h+n:h;
@@ -14,16 +16,21 @@
         int type;
         struct kw *next;
 }*kw[NKW];
-void kenter(int type, char *name)
+
+void
+kenter(int type, char *name)
 {
- register int h=hash(name, NKW);
- register struct kw *p=new(struct kw);
- p->type=type;
- p->name=name;
- p->next=kw[h];
- kw[h]=p;
+ 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){
+
+void
+kinit(void)
+{
         kenter(FOR, "for");
         kenter(IN, "in");
         kenter(WHILE, "while");
@@ -35,47 +42,59 @@
         kenter(SWITCH, "switch");
         kenter(FN, "fn");
 }
-tree *klook(char *name)
+
+tree*
+klook(char *name)
 {
         struct kw *p;
- tree *t=token(name, WORD);
- for(p=kw[hash(name, NKW)];p;p=p->next)
+ 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;
+ t->type = p->type;
+ t->iskw = 1;
                         break;
                 }
         return t;
 }
-var *gvlook(char *name)
+
+var*
+gvlook(char *name)
 {
- int h=hash(name, NVAR);
+ 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(strdup(name), gvar[h]);
+ for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
+ return gvar[h] = newvar(strdup(name), gvar[h]);
 }
-var *vlook(char *name)
+
+var*
+vlook(char *name)
 {
         var *v;
         if(runq)
- for(v=runq->local;v;v=v->next)
+ 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, int callfn)
+
+void
+_setvar(char *name, word *val, int callfn)
 {
- register struct var *v=vlook(name);
+ struct var *v = vlook(name);
         freewords(v->val);
         v->val=val;
         v->changed=1;
         if(callfn && v->changefn)
                 v->changefn(v);
 }
-void setvar(char *name, word *val)
+
+void
+setvar(char *name, word *val)
 {
         _setvar(name, val, 1);
 }
-void bigpath(var *v)
+
+void
+bigpath(var *v)
 {
         /* convert $PATH to $path */
         char *p, *q;
@@ -107,19 +126,42 @@
         }
         _setvar("path", w, 0);
 }
-void littlepath(var *v)
+
+char*
+list2strcolon(word *words)
+{
+ char *value, *s, *t;
+ int len = 0;
+ word *ap;
+ for(ap = words;ap;ap = ap->next)
+ len+=1+strlen(ap->word);
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=':';
+ }
+ if(s==value)
+ *s='\0';
+ else s[-1]='\0';
+ return value;
+}
+void
+littlepath(var *v)
 {
         /* convert $path to $PATH */
         char *p;
         word *w;
 
- p = _list2str(v->val, ':');
+ p = list2strcolon(v->val);
         w = new(word);
         w->word = p;
         w->next = nil;
         _setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */
 }
-void pathinit(void)
+
+void
+pathinit(void)
 {
         var *v;
 
diff -r bb17f966e24a -r 1161d90df941 sed/sed.1
--- a/sed/sed.1 Thu Feb 09 13:39:50 2006 +0100
+++ b/sed/sed.1 Fri Jul 31 21:02:58 2009 +0100
@@ -4,10 +4,7 @@
 .SH SYNOPSIS
 .B sed
 [
-.B -n
-]
-[
-.B -g
+.B -gln
 ]
 [
 .B -e
@@ -44,6 +41,11 @@
 .B -g
 causes all substitutions to be global, as if suffixed
 .BR g .
+The
+.B -l
+option causes
+.I sed
+to flush its output buffer after every newline.
 .PP
 A script consists of editing commands, one per line,
 of the following form:
diff -r bb17f966e24a -r 1161d90df941 sed/sed.c
--- a/sed/sed.c Thu Feb 09 13:39:50 2006 +0100
+++ b/sed/sed.c Fri Jul 31 21:02:58 2009 +0100
@@ -16,7 +16,7 @@
         LBSIZE = 8192, /* input line size */
         LABSIZE = 50, /* max label name size */
         MAXSUB = 10, /* max number of sub reg exp */
- MAXFILES = 120, /* max output files */
+ MAXFILES = 120 /* max output files */
 };
         /* An address is a line #, a R.E., "$", a reference to the last
          * R.E., or nothing.
@@ -27,7 +27,7 @@
                 A_DOL,
                 A_LINE,
                 A_RE,
- A_LAST,
+ A_LAST
         }type;
         union {
                 long line; /* Line # */
@@ -137,6 +137,7 @@
 
 int nflag; /* Command line flags */
 int gflag;
+int lflag;
 
 int dolflag; /* Set when at true EOF */
 int sflag; /* Set when substitution done */
@@ -233,6 +234,9 @@
                         continue;
                 case 'g':
                         gflag++;
+ continue;
+ case 'l':
+ lflag++;
                         continue;
                 default:
                         fprint(2, "sed: Unknown flag: %c\n", ARGC());
@@ -990,7 +994,7 @@
                 return 0;
         subexp[0].s.rsp = buf;
         subexp[0].e.rep = 0;
- if (rregexec(pattern, linebuf, subexp, MAXSUB)) {
+ if (rregexec(pattern, linebuf, subexp, MAXSUB) > 0) {
                 loc1 = subexp[0].s.rsp;
                 loc2 = subexp[0].e.rep;
                 return 1;
@@ -1315,6 +1319,8 @@
         while (n--)
                 Bputrune(bp, *buf++);
         Bputc(bp, '\n');
+ if(lflag)
+ Bflush(bp);
 }
 
 int
diff -r bb17f966e24a -r 1161d90df941 sort/sort.c
--- a/sort/sort.c Thu Feb 09 13:39:50 2006 +0100
+++ b/sort/sort.c Fri Jul 31 21:02:58 2009 +0100
@@ -34,7 +34,7 @@
         NSzerofract,
         NSexp,
         NSexpsign,
- NSexpdigit,
+ NSexpdigit
 };
 
 typedef struct Line Line;
@@ -243,8 +243,7 @@
                 done(0);
         if(strncmp(s, "sys: write on closed pipe", 25) == 0)
                 done(0);
- fprint(2, "sort: note: %s\n", s);
- abort();
+ noted(NDFLT);
 }
 
 Line*
@@ -1583,7 +1582,7 @@
 
 enum
 {
- Threshold = 14,
+ Threshold = 14
 };
 
 void rsort4(Key***, ulong, int);
diff -r bb17f966e24a -r 1161d90df941 test/test.1
--- a/test/test.1 Thu Feb 09 13:39:50 2006 +0100
+++ b/test/test.1 Fri Jul 31 21:02:58 2009 +0100
@@ -17,7 +17,7 @@
 .TP "\w'\fIn1 \fL-eq \fIn2\fLXX'u"
 .BI -r " file"
 True if the file exists (is accessible) and is readable.
-.PD
+.PD0
 .TP
 .BI -w " file"
 True if the file exists and is writable.
@@ -146,7 +146,7 @@
 .TP "\w'\fL( \fIexpr\fL )XX'u"
 .B !
 unary negation operator
-.PD
+.PD0
 .TP
 .B -o
 binary
diff -r bb17f966e24a -r 1161d90df941 test/test.c
--- a/test/test.c Thu Feb 09 13:39:50 2006 +0100
+++ b/test/test.c Fri Jul 31 21:02:58 2009 +0100
@@ -6,13 +6,15 @@
  * Plan 9 additions:
  * -A file exists and is append-only
  * -L file exists and is exclusive-use
+ * -T file exists and is temporary
  */
 
 #include <u.h>
 #include <libc.h>
+
+#define isatty plan9_isatty
+
 #define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
-
-extern int isatty(int); /* <unistd.h> */
 
 int ap;
 int ac;
@@ -23,14 +25,21 @@
 int fsizep(char *);
 int isdir(char *);
 int isreg(char *);
+int isatty(int);
 int isint(char *, int *);
+int isolder(char *, char *);
+int isolderthan(char *, char *);
+int isnewerthan(char *, char *);
 int hasmode(char *, ulong);
 int tio(char *, int);
 int e(void), e1(void), e2(void), e3(void);
+char *nxtarg(int);
 
 void
 main(int argc, char *argv[])
 {
+ int r;
+ char *c;
 
         ac = argc; av = argv; ap = 1;
         if(EQ(argv[0],"[")) {
@@ -38,8 +47,16 @@
                         synbad("] missing","");
         }
         argv[ac] = 0;
- if (ac<=1) exits("usage");
- exits(e()?0:"false");
+ if (ac<=1)
+ exits("usage");
+ r = e();
+ /*
+ * nice idea but short-circuit -o and -a operators may have
+ * not consumed their right-hand sides.
+ */
+ if(0 && (c = nxtarg(1)) != nil)
+ synbad("unexpected operator/operand: ", c);
+ exits(r?0:"false");
 }
 
 char *
@@ -66,27 +83,32 @@
 }
 
 int
-e(void) {
+e(void)
+{
         int p1;
 
         p1 = e1();
- if (EQ(nxtarg(1), "-o")) return(p1 || e());
+ if (EQ(nxtarg(1), "-o"))
+ return(p1 || e());
         ap--;
         return(p1);
 }
 
 int
-e1(void) {
+e1(void)
+{
         int p1;
 
         p1 = e2();
- if (EQ(nxtarg(1), "-a")) return (p1 && e1());
+ if (EQ(nxtarg(1), "-a"))
+ return (p1 && e1());
         ap--;
         return(p1);
 }
 
 int
-e2(void) {
+e2(void)
+{
         if (EQ(nxtarg(0), "!"))
                 return(!e2());
         ap--;
@@ -94,16 +116,16 @@
 }
 
 int
-e3(void) {
- int p1;
- char *a;
- char *p2;
- int int1, int2;
+e3(void)
+{
+ int p1, int1, int2;
+ char *a, *p2;
 
         a = nxtarg(0);
         if(EQ(a, "(")) {
                 p1 = e();
- if(!EQ(nxtarg(0), ")")) synbad(") expected","");
+ if(!EQ(nxtarg(0), ")"))
+ synbad(") expected","");
                 return(p1);
         }
 
@@ -112,6 +134,9 @@
 
         if(EQ(a, "-L"))
                 return(hasmode(nxtarg(0), DMEXCL));
+
+ if(EQ(a, "-T"))
+ return(hasmode(nxtarg(0), DMTMP));
 
         if(EQ(a, "-f"))
                 return(isreg(nxtarg(0)));
@@ -147,10 +172,12 @@
                 return(fsizep(nxtarg(0)));
 
         if(EQ(a, "-t"))
- if(ap>=ac || !nxtintarg(&int1))
+ if(ap>=ac)
                         return(isatty(1));
+ else if(nxtintarg(&int1))
+ return(isatty(int1));
                 else
- return(isatty(int1));
+ synbad("not a valid file descriptor number ", "");
 
         if(EQ(a, "-n"))
                 return(!EQ(nxtarg(0), ""));
@@ -166,8 +193,17 @@
         if(EQ(p2, "!="))
                 return(!EQ(nxtarg(0), a));
 
+ if(EQ(p2, "-older"))
+ return(isolder(nxtarg(0), a));
+
+ if(EQ(p2, "-ot"))
+ return(isolderthan(nxtarg(0), a));
+
+ if(EQ(p2, "-nt"))
+ return(isnewerthan(nxtarg(0), a));
+
         if(!isint(a, &int1))
- return(!EQ(a,""));
+ synbad("unexpected operator/operand: ", p2);
 
         if(nxtintarg(&int2)){
                 if(EQ(p2, "-eq"))
@@ -201,9 +237,10 @@
         Dir *d;
 
         d = dirstat(f);
- if(d == 0)
+ if(d == nil)
                 return(-1);
         *dir = *d;
+ free(d);
         dir->name = 0;
         dir->uid = 0;
         dir->gid = 0;
@@ -218,9 +255,10 @@
         Dir *d;
 
         d = dirfstat(f);
- if(d == 0)
+ if(d == nil)
                 return(-1);
         *dir = *d;
+ free(d);
         dir->name = 0;
         dir->uid = 0;
         dir->gid = 0;
@@ -259,6 +297,18 @@
 }
 
 int
+isatty(int fd)
+{
+ Dir d1, d2;
+
+ if(localfstat(fd, &d1) < 0)
+ return 0;
+ if(localstat("/dev/cons", &d2) < 0)
+ return 0;
+ return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path;
+}
+
+int
 fsizep(char *f)
 {
         Dir dir;
@@ -290,3 +340,72 @@
         *pans = strtol(s, &ep, 0);
         return (*ep == 0);
 }
+
+int
+isolder(char *pin, char *f)
+{
+ char *p = pin;
+ ulong n, m;
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+
+ /* parse time */
+ n = 0;
+ while(*p){
+ m = strtoul(p, &p, 0);
+ switch(*p){
+ case 0:
+ n = m;
+ break;
+ case 'y':
+ m *= 12;
+ /* fall through */
+ case 'M':
+ m *= 30;
+ /* fall through */
+ case 'd':
+ m *= 24;
+ /* fall through */
+ case 'h':
+ m *= 60;
+ /* fall through */
+ case 'm':
+ m *= 60;
+ /* fall through */
+ case 's':
+ n += m;
+ p++;
+ break;
+ default:
+ synbad("bad time syntax, ", pin);
+ }
+ }
+
+ return(dir.mtime+n < time(0));
+}
+
+int
+isolderthan(char *a, char *b)
+{
+ Dir ad, bd;
+
+ if(localstat(a, &ad)<0)
+ return(0);
+ if(localstat(b, &bd)<0)
+ return(0);
+ return ad.mtime > bd.mtime;
+}
+
+int
+isnewerthan(char *a, char *b)
+{
+ Dir ad, bd;
+
+ if(localstat(a, &ad)<0)
+ return(0);
+ if(localstat(b, &bd)<0)
+ return(0);
+ return ad.mtime < bd.mtime;
+}
diff -r bb17f966e24a -r 1161d90df941 touch/touch.c
--- a/touch/touch.c Thu Feb 09 13:39:50 2006 +0100
+++ b/touch/touch.c Fri Jul 31 21:02:58 2009 +0100
@@ -3,6 +3,7 @@
 
 int touch(int, char *);
 ulong now;
+int tflag;
 
 void
 usage(void)
@@ -20,6 +21,7 @@
         now = time(0);
         ARGBEGIN{
         case 't':
+ tflag = 1;
                 now = strtoul(EARGF(usage()), 0, 0);
                 break;
         case 'c':
@@ -52,11 +54,15 @@
                 fprint(2, "touch: %s: cannot wstat: %r\n", name);
                 return 1;
         }
- if ((fd = create(name, OREAD, 0666)) < 0) {
+ if((fd = create(name, OREAD, 0666)) < 0) {
                 fprint(2, "touch: %s: cannot create: %r\n", name);
                 return 1;
         }
- dirfwstat(fd, &stbuff);
+ if(tflag && dirfwstat(fd, &stbuff) < 0){
+ fprint(2, "touch: %s: cannot wstat: %r\n", name);
+ close(fd);
+ return 1;
+ }
         close(fd);
         return 0;
 }
diff -r bb17f966e24a -r 1161d90df941 yacc/yacc.c
--- a/yacc/yacc.c Thu Feb 09 13:39:50 2006 +0100
+++ b/yacc/yacc.c Fri Jul 31 21:02:58 2009 +0100
@@ -98,7 +98,7 @@
         EMPTY = 1,
         WHOKNOWS = 0,
         OK = 1,
- NOMORE = -1000,
+ NOMORE = -1000
 };
 
         /* macros for getting associativity and precedence levels */
@@ -1223,7 +1223,7 @@
         openup(stemc, dflag, vflag, ytab, ytabc);
         fout = dflag?fdefine:ftable;
         if(yyarg){
- Bprint(fdefine, "#define\tYYARG\t1\n\n");
+ Bprint(ftable, "#define\tYYARG\t1\n\n");
         }
         if((fd = mkstemp(ttempname)) >= 0){
                 tempname = ttempname;
Received on Fri Jul 31 2009 - 20:03:15 UTC

This archive was generated by hypermail 2.2.0 : Fri Jul 31 2009 - 20:12:05 UTC