URI: 
       upgraded 9base to p9p 20090731 - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit abc072187111c9098f80518e9c8d0b81ae1577d0
   DIR parent 89cb321008eab13102fa98bd1b28caadc2c5218e
  HTML Author: Anselm R Garbe <anselm@garbe.us>
       Date:   Fri, 31 Jul 2009 21:02:58 +0100
       
       upgraded 9base to p9p 20090731
       Diffstat:
         M Makefile                            |       2 +-
         A awk/README                          |      13 +++++++++++++
         M awk/awk.h                           |       1 +
         M awk/awkgram.y                       |       1 +
         M awk/lex.c                           |       3 ++-
         M awk/lib.c                           |      27 +++++++++++++++++++++++++++
         M awk/main.c                          |       3 ++-
         M awk/maketab.c                       |       1 +
         M awk/parse.c                         |       1 +
         M awk/proto.h                         |       3 +++
         M awk/re.c                            |      18 +++++++++---------
         M awk/run.c                           |      25 ++++++++++++++++---------
         M awk/tran.c                          |       1 +
         M bc/bc.1                             |       2 +-
         M bc/bc.y                             |     181 ++++++++++++++++---------------
         M config.mk                           |       4 +++-
         M dc/dc.c                             |      31 ++++++++-----------------------
         M grep/comp.c                         |       6 +++---
         M grep/main.c                         |      14 +++++++++-----
         M grep/sub.c                          |       2 +-
         M lib9/Makefile                       |     199 ++++++++++++++++++++++++++++++-
         M lib9/_exits.c                       |       6 +++---
         M lib9/_p9dialparse.c                 |       5 ++---
         M lib9/_p9dir.c                       |     144 ++++++++++++++++---------------
         M lib9/atexit.c                       |       4 +++-
         M lib9/bio.h                          |      21 +++------------------
         M lib9/bio/bbuffered.c                |       1 -
         M lib9/bio/bflush.c                   |       1 -
         M lib9/bio/bgetc.c                    |       1 -
         M lib9/bio/bgetd.c                    |       1 -
         M lib9/bio/binit.c                    |       7 ++-----
         M lib9/bio/boffset.c                  |       5 ++---
         M lib9/bio/brdline.c                  |       1 -
         M lib9/bio/brdstr.c                   |       2 --
         M lib9/bio/bread.c                    |       1 -
         M lib9/bio/bseek.c                    |      11 ++++-------
         M lib9/bio/bvprint.c                  |       7 +++----
         M lib9/bio/bwrite.c                   |       1 -
         M lib9/bio/lib9.std.h                 |       8 +++++++-
         M lib9/convD2M.c                      |      61 +++++++++++++++++++++++++------
         M lib9/convM2D.c                      |      50 ++++++++++++++++++++++++++-----
         M lib9/convM2S.c                      |      17 ++++++++++++++++-
         M lib9/convS2M.c                      |      28 +++++++++++++++++++++++++---
         A lib9/crypt.c                        |      68 +++++++++++++++++++++++++++++++
         M lib9/ctime.c                        |     157 +++++++++++++++++++++++++++----
         M lib9/debugmalloc.c                  |      16 ++++++++--------
         M lib9/dial.c                         |      21 ++++++++++++++-------
         M lib9/dirfwstat.c                    |       6 +++++-
         M lib9/dirread.c                      |      10 ++++++++--
         M lib9/dirwstat.c                     |      24 ++++++++++++++++++------
         M lib9/encodefmt.c                    |      11 ++---------
         M lib9/errstr.c                       |       2 +-
         A lib9/exitcode.c                     |       9 +++++++++
         M lib9/fcallfmt.c                     |       4 ++--
         M lib9/fmt.h                          |      17 ++++++++++++++++-
         M lib9/fmt/LICENSE                    |      19 +++++++++++--------
         C lib9/fmt/LICENSE -> lib9/fmt/NOTICE |       0 
         C lib9/fmt/LICENSE -> lib9/fmt/README |       0 
         M lib9/fmt/charstod.c                 |      14 +-------------
         M lib9/fmt/dofmt.c                    |     128 +++++++++++++++++++++++--------
         M lib9/fmt/dorfmt.c                   |      25 +++++++------------------
         M lib9/fmt/errfmt.c                   |      14 +-------------
         M lib9/fmt/fltfmt.c                   |     748 +++++++++++++++++++++----------
         M lib9/fmt/fmt.c                      |      17 +++--------------
         M lib9/fmt/fmtdef.h                   |      27 ++++++++-------------------
         M lib9/fmt/fmtfd.c                    |      18 ++++--------------
         M lib9/fmt/fmtfdflush.c               |      16 ++--------------
         A lib9/fmt/fmtlocale.c                |      55 +++++++++++++++++++++++++++++++
         M lib9/fmt/fmtlock.c                  |      14 +-------------
         A lib9/fmt/fmtnull.c                  |      33 +++++++++++++++++++++++++++++++
         M lib9/fmt/fmtprint.c                 |      14 +-------------
         M lib9/fmt/fmtquote.c                 |      25 ++++++++++---------------
         M lib9/fmt/fmtrune.c                  |      14 +-------------
         M lib9/fmt/fmtstr.c                   |      15 ++-------------
         M lib9/fmt/fmtvprint.c                |      14 +-------------
         M lib9/fmt/fprint.c                   |      14 +-------------
         A lib9/fmt/nan.h                      |       4 ++++
         M lib9/fmt/nan64.c                    |      59 ++++++++++++++++++-------------
         M lib9/fmt/plan9.h                    |       5 +++++
         M lib9/fmt/pow10.c                    |      14 +-------------
         M lib9/fmt/print.c                    |      14 +-------------
         M lib9/fmt/runefmtstr.c               |      15 ++-------------
         M lib9/fmt/runeseprint.c              |      14 +-------------
         M lib9/fmt/runesmprint.c              |      14 +-------------
         M lib9/fmt/runesnprint.c              |      14 +-------------
         M lib9/fmt/runesprint.c               |      14 +-------------
         M lib9/fmt/runevseprint.c             |      15 ++-------------
         M lib9/fmt/runevsmprint.c             |      21 +++++----------------
         M lib9/fmt/runevsnprint.c             |      15 ++-------------
         M lib9/fmt/seprint.c                  |      14 +-------------
         M lib9/fmt/smprint.c                  |      14 +-------------
         M lib9/fmt/snprint.c                  |      14 +-------------
         M lib9/fmt/sprint.c                   |      21 ++++++---------------
         M lib9/fmt/strtod.c                   |      20 ++++----------------
         M lib9/fmt/test.c                     |      35 +++++++++++++++++++------------
         M lib9/fmt/vfprint.c                  |      14 +-------------
         M lib9/fmt/vseprint.c                 |      15 ++-------------
         M lib9/fmt/vsmprint.c                 |      21 +++++----------------
         M lib9/fmt/vsnprint.c                 |      15 ++-------------
         A lib9/getcallerpc-arm.c              |       8 ++++++++
         M lib9/getnetconn.c                   |       4 ++--
         M lib9/getns.c                        |      25 ++++++++++++++++++++++++-
         M lib9/lib9.h                         |      19 ++-----------------
         M lib9/libc.h                         |      17 ++++++++++++-----
         M lib9/malloctag.c                    |       4 ----
         M lib9/nan.c                          |       2 +-
         A lib9/netcrypt.c                     |      18 ++++++++++++++++++
         M lib9/netmkaddr.c                    |      38 +++++++++++++++++++------------
         M lib9/notify.c                       |       9 +++++----
         M lib9/nrand.c                        |       2 --
         M lib9/nulldir.c                      |       2 +-
         M lib9/opentemp.c                     |      13 +++++++++----
         A lib9/pin.c                          |      11 +++++++++++
         M lib9/portdate                       |      85 ++++++++++++++++++++-----------
         M lib9/post9p.c                       |      93 +++++++++++++++++++++----------
         M lib9/rand.c                         |       3 ---
         M lib9/readn.c                        |       1 -
         M lib9/regex/regcomp.c                |      10 +++++-----
         M lib9/regex/regexec.c                |       2 +-
         M lib9/regex/rregexec.c               |      19 +++++++++----------
         M lib9/rfork.c                        |      10 +++++++---
         M lib9/sendfd.c                       |       5 ++++-
         M lib9/sleep.c                        |      12 ++++++++++++
         M lib9/sysfatal.c                     |       5 -----
         A lib9/test.c                         |       8 ++++++++
         A lib9/testfltfmt.c                   |     183 +++++++++++++++++++++++++++++++
         A lib9/testfmt.c                      |     148 +++++++++++++++++++++++++++++++
         A lib9/testprint.c                    |      14 ++++++++++++++
         A lib9/tm2sec.c                       |     110 +++++++++++++++++++++++++++++++
         M lib9/truerand.c                     |       2 +-
         M lib9/u.h                            |      23 ++++++++++++++++++++---
         M lib9/utf.h                          |       2 +-
         A lib9/utf/NOTICE                     |      13 +++++++++++++
         A lib9/utf/README                     |      13 +++++++++++++
         C lib9/lib9.h -> lib9/utf/lib9.h      |       0 
         M lib9/utf/rune.c                     |       2 +-
         M lib9/utf/utfecpy.c                  |       1 +
         A lib9/write.c                        |      23 +++++++++++++++++++++++
         A lib9/zoneinfo.c                     |     215 +++++++++++++++++++++++++++++++
         A lib9/zoneinfo.h                     |      19 +++++++++++++++++++
         M ls/ls.c                             |      11 +++++------
         D mk/Makefile                         |      37 -------------------------------
         D mk/NOTICE                           |      27 ---------------------------
         D mk/README                           |       7 -------
         D mk/arc.c                            |      52 -------------------------------
         D mk/archive.c                        |     253 -------------------------------
         D mk/bufblock.c                       |      88 -------------------------------
         D mk/env.c                            |     149 -------------------------------
         D mk/file.c                           |      90 -------------------------------
         D mk/fns.h                            |      88 -------------------------------
         D mk/graph.c                          |     279 -------------------------------
         D mk/job.c                            |      33 -------------------------------
         D mk/lex.c                            |     146 -------------------------------
         D mk/main.c                           |     287 -------------------------------
         D mk/match.c                          |      49 -------------------------------
         D mk/mk.1                             |     691 -------------------------------
         D mk/mk.c                             |     234 -------------------------------
         D mk/mk.h                             |     182 -------------------------------
         D mk/parse.c                          |     318 -------------------------------
         D mk/rc.c                             |     194 ------------------------------
         D mk/recipe.c                         |     117 -------------------------------
         D mk/rule.c                           |     110 -------------------------------
         D mk/run.c                            |     296 -------------------------------
         D mk/sh.c                             |     206 -------------------------------
         D mk/shell.c                          |      80 -------------------------------
         D mk/shprint.c                        |     125 -------------------------------
         D mk/symtab.c                         |      97 ------------------------------
         D mk/sys.h                            |       5 -----
         D mk/sys.std.h                        |      22 ----------------------
         D mk/unix.c                           |     341 -------------------------------
         D mk/var.c                            |      41 -------------------------------
         D mk/varsub.c                         |     256 -------------------------------
         D mk/word.c                           |     180 -------------------------------
         M rc/Makefile                         |       3 ++-
         M rc/code.c                           |     226 +++++++++++++++++++------------
         M rc/exec.c                           |    1031 ++++++++++++++++---------------
         M rc/exec.h                           |      10 +++++++---
         M rc/fns.h                            |      14 ++++++++++----
         M rc/getflags.c                       |     171 ++++++++++++++++++-------------
         M rc/glob.c                           |     165 +++++++++++++++++++------------
         M rc/havefork.c                       |      53 +++++++++++++++++++++++++------
         M rc/here.c                           |      97 ++++++++++++++++++-------------
         M rc/io.c                             |     231 +++++++++++++++++++++----------
         M rc/io.h                             |       6 +++---
         M rc/lex.c                            |     280 ++++++++++++++++++-------------
         M rc/pcmd.c                           |     107 +++++++++++++++++++++----------
         M rc/pfnc.c                           |      16 ++++++++++------
         M rc/plan9ish.c                       |      71 +++++++++++++++++++++++++++----
         M rc/rc.1                             |       5 +++++
         M rc/rc.h                             |       3 ++-
         M rc/simple.c                         |     331 ++++++++++++++++++-------------
         M rc/subr.c                           |      48 +++++++++++++++++++++----------
         M rc/trap.c                           |      25 ++++++++++++++-----------
         M rc/tree.c                           |     132 +++++++++++++++++++------------
         M rc/unixcrap.c                       |      25 +++++++++++++++++++++++++
         M rc/var.c                            |      98 ++++++++++++++++++++++---------
         M sed/sed.1                           |      10 ++++++----
         M sed/sed.c                           |      12 +++++++++---
         M sort/sort.c                         |       7 +++----
         M test/test.1                         |       4 ++--
         M test/test.c                         |     159 +++++++++++++++++++++++++++----
         M touch/touch.c                       |      10 ++++++++--
         M yacc/yacc.c                         |       4 ++--
       
       203 files changed, 4891 insertions(+), 7638 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       @@ -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:
   DIR diff --git a/awk/README b/awk/README
       @@ -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
       +
   DIR diff --git a/awk/awk.h b/awk/awk.h
       @@ -182,3 +182,4 @@ extern        int        pairstack[], paircnt;
        #define freeable(p)        ( ((p)->tval & (STR|DONTFREE)) == STR )
        
        #include "proto.h"
       +
   DIR diff --git a/awk/awkgram.y b/awk/awkgram.y
       @@ -486,3 +486,4 @@ void checkdup(Node *vl, Cell *cp)        /* check if name already in list */
                        }
                }
        }
       +
   DIR diff --git a/awk/lex.c b/awk/lex.c
       @@ -86,8 +86,8 @@ Keyword keywords[] ={        /* keep sorted: binary searched */
                { "system",        FSYSTEM,        BLTIN },
                { "tolower",        FTOLOWER,        BLTIN },
                { "toupper",        FTOUPPER,        BLTIN },
       -        { "while",        WHILE,                WHILE },
                { "utf",        FUTF,                BLTIN },
       +        { "while",        WHILE,                WHILE },
        };
        
        #define DEBUG
       @@ -567,3 +567,4 @@ void unputstr(char *s)        /* put a string back on input */
                for (i = strlen(s)-1; i >= 0; i--)
                        unput(s[i]);
        }
       +
   DIR diff --git a/awk/lib.c b/awk/lib.c
       @@ -673,6 +673,32 @@ int is_number(char *s)
        {
                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 @@ int is_number(char *s)
                else
                        return 0;
        }
       +
   DIR diff --git a/awk/main.c b/awk/main.c
       @@ -57,7 +57,7 @@ int main(int argc, char *argv[])
        
                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 @@ char *cursource(void)        /* current source file name */
                else
                        return NULL;
        }
       +
   DIR diff --git a/awk/maketab.c b/awk/maketab.c
       @@ -166,3 +166,4 @@ int main(int argc, char *argv[])
                printf("}\n");
                return 0;
        }
       +
   DIR diff --git a/awk/parse.c b/awk/parse.c
       @@ -269,3 +269,4 @@ Node *itonp(int i)        /* and vice versa */
        {
                return (Node *) (long) i;
        }
       +
   DIR diff --git a/awk/proto.h b/awk/proto.h
       @@ -22,6 +22,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 *);
        extern        int        constnode(Node *);
       @@ -175,3 +177,4 @@ extern        Cell        *gsub(Node **, int);
        
        extern        FILE        *popen(const char *, const char *);
        extern        int        pclose(FILE *);
       +
   DIR diff --git a/awk/re.c b/awk/re.c
       @@ -25,15 +25,13 @@ THIS SOFTWARE.
        
        #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 @@ void
        
                /* 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 @@ nematch(void *p, char *s, char *start)
        }
        /* 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 @@ overflow(void)
        {
                FATAL("%s", "regular expression too big");
        }
       +
   DIR diff --git a/awk/run.c b/awk/run.c
       @@ -133,6 +133,7 @@ void run(Node *a)        /* execution of parse tree starts here */
        
        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 @@ Cell *execute(Node *u)        /* execute a node of the parse tree */
                                        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 @@ int format(char **pbuf, int *pbufsize, char *s, Node *a)        /* printf-like conversi
                                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 *bltin(Node **a, int n)        /* builtin functions. a[0] is type, a[1] is arg lis
        
        Cell *printstat(Node **a, int n)        /* print a[0] */
        {
       +        int r;
                Node *x;
                Cell *y;
                FILE *fp;
       @@ -1553,14 +1558,15 @@ Cell *printstat(Node **a, int n)        /* print a[0] */
                        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 @@ void backsub(char **pb_ptr, char **sptr_ptr)        /* handle \\& variations */
                *pb_ptr = pb;
                *sptr_ptr = sptr;
        }
       +
   DIR diff --git a/awk/tran.c b/awk/tran.c
       @@ -432,3 +432,4 @@ char *qstring(char *s, int delim)        /* collect string up to next delim */
                *bp++ = 0;
                return buf;
        }
       +
   DIR diff --git a/bc/bc.1 b/bc/bc.1
       @@ -159,7 +159,7 @@ Function definitions
        .B ,
        .I L
        .B ){
       -.PD
       +.PD0
        .br
        .B auto
        .I L
   DIR diff --git a/bc/bc.y b/bc/bc.y
       @@ -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 @@ stuff:
                        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 @@ def:
                _DEFINE LETTER '('
                {
                        $$ = getf($2);
       -                pre = (int*)"";
       -                post = (int*)"";
       +                pre = (char*)"";
       +                post = (char*)"";
                        lev = 1;
                        bindx = 0;
                        bstack[bindx] = 0;
       @@ -789,76 +786,85 @@ loop:
                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 @@ yyerror(char *s, ...)
        {
                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 @@ pp(char *s)
        {
                /* 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 @@ tp(char *s)
        {
                /* 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 @@ main(int argc, char **argv)
        {
                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) {
       -                argv--;
                        argc++;
       -                argv[1] = unsharp("#9/lib/bclib");
       +                argv--;
       +                *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 @@ main(int argc, char **argv)
                dup(p[0], 0);
                close(p[0]);
                close(p[1]);
       -        execlp("dc", "dc", (char*)0);
       +        execl(unsharp("#9/bin/dc"), "dc", nil);
        }
   DIR diff --git a/config.mk b/config.mk
       @@ -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}\""
   DIR diff --git a/dc/dc.c b/dc/dc.c
       @@ -165,7 +165,6 @@ void        release(Blk *p);
        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 @@ init(int argc, char *argv[])
                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 @@ copy(Blk *hptr, int size)
                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 @@ seekc(Blk *hptr, int n)
                        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 @@ more(Blk *hptr)
                        longest = size;
                lbytes += size/2;
                lmore++;
       -/*        free(hptr->beg);*//**/
       +/*        free(hptr->beg);*/
                p = realloc(hptr->beg, size);
        
                if(p == 0) {
       @@ -2269,19 +2267,6 @@ lookwd(Blk *p)
                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)
        {
   DIR diff --git a/grep/comp.c b/grep/comp.c
       @@ -128,12 +128,12 @@ loop:
        Rune        tab1[] =
        {
                0x007f,
       -        0x07ff,
       +        0x07ff
        };
        Rune        tab2[] =
        {
                0x003f,
       -        0x0fff,
       +        0x0fff
        };
        
        Re2
       @@ -144,7 +144,7 @@ rclass(Rune p0, Rune p1)
                Re2 x;
        
                if(p0 > p1)
       -                return re2char(0xff, 0xff);        // no match
       +                return re2char(0xff, 0xff);        /* no match */
        
                /*
                 * bust range into same length
   DIR diff --git a/grep/main.c b/grep/main.c
       @@ -21,6 +21,10 @@ main(int argc, char *argv[])
                        flags[ARGC()]++;
                        break;
        
       +        case 'q':        /* gnu grep -q means plan 9 grep -s */
       +                flags['s']++;
       +                break;
       +
                case 'E':        /* ignore, turns gnu grep into egrep */
                        break;
        
       @@ -170,11 +174,11 @@ loop:
                        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') {
   DIR diff --git a/grep/sub.c b/grep/sub.c
       @@ -30,7 +30,7 @@ sal(int n)
                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;
   DIR diff --git a/lib9/Makefile b/lib9/Makefile
       @@ -15,16 +15,203 @@ include ../config.mk
        
        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\
   DIR diff --git a/lib9/_exits.c b/lib9/_exits.c
       @@ -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));
        }
   DIR diff --git a/lib9/_p9dialparse.c b/lib9/_p9dialparse.c
       @@ -26,6 +26,8 @@ static struct {
                "tcp",        "venti",        17034,
                "tcp",        "wiki",        17035,
                "tcp",        "secstore",        5356,
       +        "udp",        "dns",        53,
       +        "tcp",        "dns",        53,
        };
        
        static int
       @@ -82,9 +84,6 @@ p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport)
                struct hostent *he;
                struct sockaddr_un *sockun;
        
       -        if(strncmp(addr, "/net/", 5) == 0)
       -                addr += 5;
       -
                *punix = nil;
                net = addr;
                if((host = strchr(net, '!')) == nil){
   DIR diff --git a/lib9/_p9dir.c b/lib9/_p9dir.c
       @@ -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 vlong
       +disksize(int fd, struct stat *st)
       +{
       +        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 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;
       +        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 @@ disksize(int fd, int dev)
                        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
       -#endif
        
       -#if !defined(__linux__) && !defined(__sun__)
       -#define _HAVESTGEN
       +#else
       +static vlong
       +disksize(int fd, struct stat *st)
       +{
       +        return 0;
       +}
        #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 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
                /* 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 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
                /* 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 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
        #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);
       -                }
       -#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)
       +                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
                }
        
                return sz;
   DIR diff --git a/lib9/atexit.c b/lib9/atexit.c
       @@ -50,5 +50,7 @@ exits(char *s)
                                onex[i].f = 0;
                                (*f)();
                        }
       -        exit(s && *s ? 1 : 0);
       +        if(s == 0 || *s == 0)
       +                exit(0);
       +        exit(exitcode(s));
        }
   DIR diff --git a/lib9/bio.h b/lib9/bio.h
       @@ -8,23 +8,8 @@ extern "C" {
        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;
        
        enum
       @@ -52,7 +37,7 @@ struct        Biobuf
                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 @@ long        Bgetrune(Biobuf*);
        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 @@ int        Bputrune(Biobuf*, long);
        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*);
   DIR diff --git a/lib9/bio/bbuffered.c b/lib9/bio/bbuffered.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <fmt.h>
        
        int
        Bbuffered(Biobuf *bp)
   DIR diff --git a/lib9/bio/bflush.c b/lib9/bio/bflush.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <unistd.h>
        
        int
        Bflush(Biobuf *bp)
   DIR diff --git a/lib9/bio/bgetc.c b/lib9/bio/bgetc.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <unistd.h>
        
        int
        Bgetc(Biobuf *bp)
   DIR diff --git a/lib9/bio/bgetd.c b/lib9/bio/bgetd.c
       @@ -1,6 +1,5 @@
        #include "lib9.h"
        #include <bio.h>
       -#include <fmt.h>
        
        struct        bgetd
        {
   DIR diff --git a/lib9/bio/binit.c b/lib9/bio/binit.c
       @@ -1,8 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <fmt.h>
       -#include        <stdlib.h>
       -#include        <unistd.h>
        
        enum
        {
       @@ -125,13 +122,13 @@ Bopen(char *name, int mode)
                        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;
                }
   DIR diff --git a/lib9/bio/boffset.c b/lib9/bio/boffset.c
       @@ -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:
   DIR diff --git a/lib9/bio/brdline.c b/lib9/bio/brdline.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <unistd.h>
        
        void*
        Brdline(Biobuf *bp, int delim)
   DIR diff --git a/lib9/bio/brdstr.c b/lib9/bio/brdstr.c
       @@ -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)
   DIR diff --git a/lib9/bio/bread.c b/lib9/bio/bread.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <unistd.h>
        
        long
        Bread(Biobuf *bp, void *ap, long count)
   DIR diff --git a/lib9/bio/bseek.c b/lib9/bio/bseek.c
       @@ -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 @@ Bseek(Biobuf *bp, off_t offset, int base)
        
                case Bwactive:
                        Bflush(bp);
       -                n = lseek(bp->fid, offset, base);
       +                n = seek(bp->fid, offset, base);
                        break;
                }
                bp->offset = n;
   DIR diff --git a/lib9/bio/bvprint.c b/lib9/bio/bvprint.c
       @@ -1,6 +1,5 @@
        #include "lib9.h"
        #include <bio.h>
       -#include <fmt.h>
        
        static int 
        fmtBflush(Fmt *f)
       @@ -30,10 +29,10 @@ Bvprint(Biobuf *bp, char *fmt, va_list arg)
                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;
        }
       -
       -
       -        
   DIR diff --git a/lib9/bio/bwrite.c b/lib9/bio/bwrite.c
       @@ -1,6 +1,5 @@
        #include        "lib9.h"
        #include        <bio.h>
       -#include        <unistd.h>
        
        long
        Bwrite(Biobuf *bp, void *ap, long count)
   DIR diff --git a/lib9/bio/lib9.std.h b/lib9/bio/lib9.std.h
       @@ -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)
       +
   DIR diff --git a/lib9/convD2M.c b/lib9/convD2M.c
       @@ -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 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
                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 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
                        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 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
                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 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
                                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);
       +}
   DIR diff --git a/lib9/convM2D.c b/lib9/convM2D.c
       @@ -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,26 +15,38 @@ statcheck(uchar *buf, uint nbuf)
        
                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;
        
                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 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
                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 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
                        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);
       +}
   DIR diff --git a/lib9/convM2S.c b/lib9/convM2S.c
       @@ -48,7 +48,7 @@ gqid(uchar *p, uchar *ep, Qid *q)
         * 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 @@ convM2S(uchar *ap, uint nap, Fcall *f)
                        p += BIT32SZ;
                        f->mode = GBIT8(p);
                        p += BIT8SZ;
       +                if(dotu)
       +                        p = gstring(p, ep, &f->extension);
                        break;
        
                case Tread:
       @@ -229,6 +231,13 @@ convM2S(uchar *ap, uint nap, Fcall *f)
        
                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 @@ convM2S(uchar *ap, uint nap, Fcall *f)
                        return size;
                return 0;
        }
       +
       +uint
       +convM2S(uchar *ap, uint nap, Fcall *f)
       +{
       +        return convM2Su(ap, nap, f, 0);
       +}
   DIR diff --git a/lib9/convS2M.c b/lib9/convS2M.c
       @@ -46,7 +46,7 @@ stringsz(char *s)
        }
        
        uint
       -sizeS2M(Fcall *f)
       +sizeS2Mu(Fcall *f, int dotu)
        {
                uint n;
                int i;
       @@ -102,6 +102,8 @@ sizeS2M(Fcall *f)
                        n += stringsz(f->name);
                        n += BIT32SZ;
                        n += BIT8SZ;
       +                if(dotu)
       +                        n += stringsz(f->extension);
                        break;
        
                case Tread:
       @@ -141,6 +143,8 @@ sizeS2M(Fcall *f)
        
                case Rerror:
                        n += stringsz(f->ename);
       +                if(dotu)
       +                        n += BIT16SZ;
                        break;
        
                case Rflush:
       @@ -198,12 +202,18 @@ sizeS2M(Fcall *f)
        }
        
        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 @@ convS2M(Fcall *f, uchar *ap, uint nap)
                        p += BIT32SZ;
                        PBIT8(p, f->mode);
                        p += BIT8SZ;
       +                if(dotu)
       +                        p = pstring(p, f->extension);
                        break;
        
                case Tread:
       @@ -331,6 +343,10 @@ convS2M(Fcall *f, uchar *ap, uint nap)
        
                case Rerror:
                        p = pstring(p, f->ename);
       +                if(dotu){
       +                        PBIT16(p, f->errornum);
       +                        p += BIT16SZ;
       +                }
                        break;
        
                case Rflush:
       @@ -397,3 +413,9 @@ convS2M(Fcall *f, uchar *ap, uint nap)
                        return 0;
                return size;
        }
       +
       +uint
       +convS2M(Fcall *f, uchar *ap, uint nap)
       +{
       +        return convS2Mu(f, ap, nap, 0);
       +}
   DIR diff --git a/lib9/crypt.c b/lib9/crypt.c
       @@ -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;
       +}
   DIR diff --git a/lib9/ctime.c b/lib9/ctime.c
       @@ -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 @@ asctime(Tm *t)
                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 @@ asctime(Tm *t)
                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';
        }
        
   DIR diff --git a/lib9/debugmalloc.c b/lib9/debugmalloc.c
       @@ -111,13 +111,13 @@ p9malloc(ulong n)
                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 @@ p9free(void *v)
                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 @@ p9calloc(ulong a, ulong b)
        {
                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;
        }
   DIR diff --git a/lib9/dial.c b/lib9/dial.c
       @@ -60,10 +60,6 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
                }
                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 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
                        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 @@ Unix:
                        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){
   DIR diff --git a/lib9/dirfwstat.c b/lib9/dirfwstat.c
       @@ -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 @@ dirfwstat(int fd, Dir *dir)
                        if(futimes(fd, tv) < 0)
                                ret = -1;
                }
       +        if(~dir->length != 0){
       +                if(ftruncate(fd, dir->length) < 0)
       +                        ret = -1;
       +        }
                return ret;
        }
        
   DIR diff --git a/lib9/dirread.c b/lib9/dirread.c
       @@ -18,19 +18,25 @@ mygetdents(int fd, struct dirent *buf, int n)
                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
        
        static int
   DIR diff --git a/lib9/dirwstat.c b/lib9/dirwstat.c
       @@ -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;
        }
   DIR diff --git a/lib9/encodefmt.c b/lib9/encodefmt.c
       @@ -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 @@ encodefmt(Fmt *f)
                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 @@ encodefmt(Fmt *f)
                } else
                        buf = obuf;
        
       -        // convert
       +        /* convert */
                out = buf;
                switch(f->r){
                case '<':
   DIR diff --git a/lib9/errstr.c b/lib9/errstr.c
       @@ -12,7 +12,7 @@
        
        enum
        {
       -        EPLAN9 = 0x19283745,
       +        EPLAN9 = 0x19283745
        };
        
        char *(*_syserrstr)(void);
   DIR diff --git a/lib9/exitcode.c b/lib9/exitcode.c
       @@ -0,0 +1,9 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +exitcode(char *s)
       +{
       +        return 1;
       +}
       +
   DIR diff --git a/lib9/fcallfmt.c b/lib9/fcallfmt.c
       @@ -124,7 +124,7 @@ fcallfmt(Fmt *fmt)
                        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 @@ fcallfmt(Fmt *fmt)
                        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;
   DIR diff --git a/lib9/fmt.h b/lib9/fmt.h
       @@ -34,6 +34,18 @@ struct Fmt{
                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 @@ enum{
                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 @@ double                fmtcharstod(int(*f)(void*), void *vp);
        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);
   DIR diff --git a/lib9/fmt/LICENSE b/lib9/fmt/LICENSE
       @@ -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@post.harvard.edu>.
       +Please send comments about the packaging to Russ Cox <rsc@swtch.com>.
        
   DIR diff --git a/lib9/fmt/LICENSE b/lib9/fmt/NOTICE
   DIR diff --git a/lib9/fmt/LICENSE b/lib9/fmt/README
   DIR diff --git a/lib9/fmt/charstod.c b/lib9/fmt/charstod.c
       @@ -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"
   DIR diff --git a/lib9/fmt/dofmt.c b/lib9/fmt/dofmt.c
       @@ -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 @@ __fmtflush(Fmt *f, void *t, int len)
        
        /*
         * 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 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
        
                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 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
                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 @@ int
        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 @@ __percentfmt(Fmt *f)
        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 @@ __ifmt(Fmt *f)
                 * Unsigned verbs for ANSI C
                 */
                switch(f->r){
       -        case 'x':
       -        case 'X':
                case 'o':
       -        case 'u':
                case 'p':
       +        case 'u':
       +        case 'x':
       +        case 'X':
                        fl |= FmtUnsigned;
                        fl &= ~(FmtSign|FmtSpace);
                        break;
       @@ -381,21 +387,25 @@ __ifmt(Fmt *f)
                                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;
       -                break;
       -        case 'x':
       -                base = 16;
       +                grouping = f->grouping;
                        break;
                case 'X':
       -                base = 16;
                        conv = "0123456789ABCDEF";
       +                /* fall through */
       +        case 'x':
       +                base = 16;
       +                thousands = ":";
                        break;
                case 'b':
                        base = 2;
       +                thousands = ":";
                        break;
                case 'o':
                        base = 8;
       @@ -413,7 +423,11 @@ __ifmt(Fmt *f)
                        }
                }
                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;
       @@ -422,6 +436,12 @@ __ifmt(Fmt *f)
                                        *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 @@ __ifmt(Fmt *f)
                                        *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){
       -                *p-- = '0';
       -                n = 1;
       +                /*
       +                 * "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++)
       +        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';
       +        }
                if(neg || (fl & (FmtSign|FmtSpace)))
                        n++;
                if(fl & FmtSharp){
       @@ -456,9 +507,19 @@ __ifmt(Fmt *f)
                        }
                }
                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 @@ __ifmt(Fmt *f)
                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 @@ __flagfmt(Fmt *f)
                case '#':
                        f->flags |= FmtSharp;
                        break;
       +        case '\'':
       +                f->flags |= FmtApost;
       +                break;
                case ' ':
                        f->flags |= FmtSpace;
                        break;
   DIR diff --git a/lib9/fmt/dorfmt.c b/lib9/fmt/dorfmt.c
       @@ -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 @@ dorfmt(Fmt *f, const Rune *fmt)
                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 @@ dorfmt(Fmt *f, const Rune *fmt)
                                        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 @@ dorfmt(Fmt *f, const Rune *fmt)
                                f->stop = s;
                        }
        
       -                fmt = __fmtdispatch(f, (Rune*)fmt, 1);
       +                fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
                        if(fmt == nil)
                                return -1;
                }
   DIR diff --git a/lib9/fmt/errfmt.c b/lib9/fmt/errfmt.c
       @@ -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>
   DIR diff --git a/lib9/fmt/fltfmt.c b/lib9/fmt/fltfmt.c
       @@ -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 @@ static double pows10[] =
                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 @@ pow10(int n)
        
                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;
       -        }
       -        if(__isInf(f, 1)) {
       -                strcpy(s2, "+Inf");
       -                return;
       -        }
       -        if(__isInf(f, -1)) {
       -                strcpy(s2, "-Inf");
       -                return;
       +        *p++ = ucase ? 'E' : 'e';
       +        if(e < 0) {
       +                *p++ = '-';
       +                e = -e;
       +        } else
       +                *p++ = '+';
       +        i = 0;
       +        while(e) {
       +                se[i++] = e % 10 + '0';
       +                e /= 10;
                }
       -        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);
       +                *neg = 1;
                }
        
       -        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);
       -                }
       +        /*
       +         * must handle zero specially.
       +         */
       +        if(f == 0){
       +                *exp = 0;
       +                s[0] = '0';
       +                s[1] = '\0';
       +                *ns = 1;
       +                return;
       +        }
       +                
       +        /*
       +         * find g,e such that f = g*10^e.
       +         * guess 10-exponent using 2-exponent, then fine tune.
       +         */
       +        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 NSIGNIF digits and convert
       -         * back to get accuracy.
       +         * convert NSIGNIF digits as a first approximation.
                 */
                for(i=0; i<NSIGNIF; i++) {
       -                d = g;
       -                s1[i] = d + '0';
       -                g = (g - d) * 10;
       +                d = (int)g;
       +                s[i] = d+'0';
       +                g = (g-d) * 10;
                }
       -        s1[i] = 0;
       +        s[i] = 0;
        
                /*
       -         * try decimal rounding to eliminate 9s
       +         * adjust e because s is 314159... not 3.14159...
                 */
       -        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;
       -        }
       +        e -= NSIGNIF-1;
       +        xfmtexp(s+NSIGNIF, e, 0);
        
                /*
       -         * convert back so s1 gets exact answer
       +         * adjust conversion until strtod(s) == f exactly.
                 */
       -        for(;;) {
       -                sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
       -                g = strtod(s1, nil);
       +        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
       +         */
       +        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
                 */
       -        c1 = 0;
       -        c2 = prec + 1;
       -        c3 = 0;
       -        c4 = prec;
       +        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++;
       +        case 'A':
       +        case 'E':
       +        case 'F':
       +        case 'G':
       +                chr += 'a'-'A';
       +                ucase = 1;
                        break;
       +        }
       +
       +        /*
       +         * pick off special numbers.
       +         */
       +        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;
       +        }
       +
       +        /*
       +         * get exact representation.
       +         */
       +        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':
                        /*
       -                 * decide on 'e' of 'f' style convers
       +                 * 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(xadd(s1, c2, 5))
       -                        e++;
       -                if(e >= -5 && e <= prec) {
       -                        c1 = -e - 1;
       -                        c4 = prec - e;
       -                        chr = 'h';        // flag for 'f' style
       +                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':
       -                if(xadd(s1, c2+e, 5))
       -                        e++;
       -                c1 = -e;
       -                if(c1 > prec)
       -                        c1 = c2;
       -                c2 += e;
       +                /*
       +                 * 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;
                }
       -
       +        
                /*
       -         * clean up c1 c2 and 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(c1 < 0)
       -                c1 = 0;
       -        if(c2 < 0)
       -                c2 = 0;
       -        if(c2 > NSIGNIF) {
       -                c3 = c2-NSIGNIF;
       -                c2 = NSIGNIF;
       +        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--;
       +                        }
       +                }
                }
        
                /*
       -         * copy digits
       +         * compute width of all digits and decimal point and suffix if any
                 */
       -        while(c1 > 0) {
       -                if(c1+c2+c3 == c4)
       -                        s2[d++] = '.';
       -                s2[d++] = '0';
       -                c1--;
       -        }
       -        while(c2 > 0) {
       -                if(c2+c3 == c4)
       -                        s2[d++] = '.';
       -                s2[d++] = s1[i++];
       -                c2--;
       +        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 */
                }
       -        while(c3 > 0) {
       -                if(c3 == c4)
       -                        s2[d++] = '.';
       -                s2[d++] = '0';
       -                c3--;
       +        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;
                }
        
                /*
       -         * strip trailing '0' on g conv
       +         * format the actual field.  too bad about doing this twice.
                 */
       -        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;
       +        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';
                                }
       -        }
       -        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;
       +                        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);
                        }
       -                s2[d++] = c1/10 + '0';
       -                s2[d++] = c1%10 + '0';
       +                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;
                }
       -        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);
       -}
   DIR diff --git a/lib9/fmt/fmt.c b/lib9/fmt/fmt.c
       @@ -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 @@ struct Convfmt
                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 @@ static Convfmt knownfmt[] = {
                ' ',        __flagfmt,
                '#',        __flagfmt,
                '%',        __percentfmt,
       +        '\'',        __flagfmt,
                '+',        __flagfmt,
                ',',        __flagfmt,
                '-',        __flagfmt,
   DIR diff --git a/lib9/fmt/fmtdef.h b/lib9/fmt/fmtdef.h
       @@ -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 @@ void         __fmtunlock(void);
        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 @@ int          __strfmt(Fmt *f);
        #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 @@ int          __strfmt(Fmt *f);
        #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 @@ int          __strfmt(Fmt *f);
                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;\
                }\
   DIR diff --git a/lib9/fmt/fmtfd.c b/lib9/fmt/fmtfd.c
       @@ -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 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size)
                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;
        }
   DIR diff --git a/lib9/fmt/fmtfdflush.c b/lib9/fmt/fmtfdflush.c
       @@ -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 @@ __fmtFdFlush(Fmt *f)
                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;
   DIR diff --git a/lib9/fmt/fmtlocale.c b/lib9/fmt/fmtlocale.c
       @@ -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;
       +}
       +
   DIR diff --git a/lib9/fmt/fmtlock.c b/lib9/fmt/fmtlock.c
       @@ -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"
   DIR diff --git a/lib9/fmt/fmtnull.c b/lib9/fmt/fmtnull.c
       @@ -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;
       +}
       +
   DIR diff --git a/lib9/fmt/fmtprint.c b/lib9/fmt/fmtprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/fmtquote.c b/lib9/fmt/fmtquote.c
       @@ -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 @@ __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int r
                        /* 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 @@ qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
                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 @@ __quotestrfmt(int runesin, Fmt *f)
                        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)
   DIR diff --git a/lib9/fmt/fmtrune.c b/lib9/fmt/fmtrune.c
       @@ -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"
   DIR diff --git a/lib9/fmt/fmtstr.c b/lib9/fmt/fmtstr.c
       @@ -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 @@ fmtstrflush(Fmt *f)
                if(f->start == nil)
                        return nil;
                *(char*)f->to = '\0';
       +        f->to = f->start;
                return (char*)f->start;
        }
   DIR diff --git a/lib9/fmt/fmtvprint.c b/lib9/fmt/fmtvprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/fprint.c b/lib9/fmt/fprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/nan.h b/lib9/fmt/nan.h
       @@ -0,0 +1,4 @@
       +extern double __NaN(void);
       +extern double __Inf(int);
       +extern int __isNaN(double);
       +extern int __isInf(double, int);
   DIR diff --git a/lib9/fmt/nan64.c b/lib9/fmt/nan64.c
       @@ -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)
   DIR diff --git a/lib9/fmt/plan9.h b/lib9/fmt/plan9.h
       @@ -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,
   DIR diff --git a/lib9/fmt/pow10.c b/lib9/fmt/pow10.c
       @@ -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"
   DIR diff --git a/lib9/fmt/print.c b/lib9/fmt/print.c
       @@ -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"
   DIR diff --git a/lib9/fmt/runefmtstr.c b/lib9/fmt/runefmtstr.c
       @@ -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 @@ runefmtstrflush(Fmt *f)
                if(f->start == nil)
                        return nil;
                *(Rune*)f->to = '\0';
       +        f->to = f->start;
                return f->start;
        }
   DIR diff --git a/lib9/fmt/runeseprint.c b/lib9/fmt/runeseprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/runesmprint.c b/lib9/fmt/runesmprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/runesnprint.c b/lib9/fmt/runesnprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/runesprint.c b/lib9/fmt/runesprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/runevseprint.c b/lib9/fmt/runevseprint.c
       @@ -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 @@ runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
                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';
   DIR diff --git a/lib9/fmt/runevsmprint.c b/lib9/fmt/runevsmprint.c
       @@ -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 @@ runeFmtStrFlush(Fmt *f)
        
                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 @@ runeFmtStrFlush(Fmt *f)
                        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 @@ runefmtstrinit(Fmt *f)
                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;
        }
        
   DIR diff --git a/lib9/fmt/runevsnprint.c b/lib9/fmt/runevsnprint.c
       @@ -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 @@ runevsnprint(Rune *buf, int len, char *fmt, va_list args)
                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';
   DIR diff --git a/lib9/fmt/seprint.c b/lib9/fmt/seprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/smprint.c b/lib9/fmt/smprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/snprint.c b/lib9/fmt/snprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/sprint.c b/lib9/fmt/sprint.c
       @@ -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 @@ sprint(char *buf, char *fmt, ...)
                /*
                 * 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);
   DIR diff --git a/lib9/fmt/strtod.c b/lib9/fmt/strtod.c
       @@ -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 @@ enum
                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 @@ fmtstrtod(const char *as, char **aas)
                /* 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 @@ xcmp(char *a, char *b)
        {
                int c1, c2;
        
       -        while(c1 = *b++) {
       +        while((c1 = *b++) != '\0') {
                        c2 = *a++;
                        if(isupper(c2))
                                c2 = tolower(c2);
   DIR diff --git a/lib9/fmt/test.c b/lib9/fmt/test.c
       @@ -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 @@ main(int argc, char *argv[])
                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;
        }
   DIR diff --git a/lib9/fmt/vfprint.c b/lib9/fmt/vfprint.c
       @@ -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"
   DIR diff --git a/lib9/fmt/vseprint.c b/lib9/fmt/vseprint.c
       @@ -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 @@ vseprint(char *buf, char *e, char *fmt, va_list args)
                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';
   DIR diff --git a/lib9/fmt/vsmprint.c b/lib9/fmt/vsmprint.c
       @@ -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 @@ fmtStrFlush(Fmt *f)
        
                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 @@ fmtStrFlush(Fmt *f)
                        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 @@ fmtstrinit(Fmt *f)
                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;
        }
        
   DIR diff --git a/lib9/fmt/vsnprint.c b/lib9/fmt/vsnprint.c
       @@ -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 @@ vsnprint(char *buf, int len, char *fmt, va_list args)
                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';
   DIR diff --git a/lib9/getcallerpc-arm.c b/lib9/getcallerpc-arm.c
       @@ -0,0 +1,8 @@
       +#include <lib9.h>
       +
       +ulong
       +getcallerpc(void *x)
       +{
       +        return ((ulong*)x)[-2];
       +}
       +
   DIR diff --git a/lib9/getnetconn.c b/lib9/getnetconn.c
       @@ -91,12 +91,12 @@ getnetconninfo(char *dir, int fd)
                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)
   DIR diff --git a/lib9/getns.c b/lib9/getns.c
       @@ -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 @@ nsfromdisplay(void)
                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 @@ nsfromdisplay(void)
                        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 @@ nsfromdisplay(void)
                        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);
   DIR diff --git a/lib9/lib9.h b/lib9/lib9.h
       @@ -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>
   DIR diff --git a/lib9/libc.h b/lib9/libc.h
       @@ -349,7 +349,7 @@ extern        vlong        p9nsec(void);
        enum
        {
                PNPROC                = 1,
       -        PNGROUP                = 2,
       +        PNGROUP                = 2
        };
        
        /* extern        int        abs(int); <stdlib.h> */
       @@ -376,6 +376,7 @@ extern        int        dec16(uchar*, int, char*, int);
        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        int        iounit(int);
        /* 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*);
       @@ -416,6 +417,9 @@ extern        long        p9time(long*);
        extern        void        needstack(int);
        extern        char*        readcons(char*, char*, int);
        
       +extern        void        (*_pin)(void);
       +extern        void        (*_unpin)(void);
       +
        #ifndef NOPLAN9DEFINES
        #define atexit                p9atexit
        #define atexitdont        p9atexitdont
       @@ -670,7 +674,7 @@ enum
                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        int        p9waitpid(void);
        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 @@ extern        ulong        rendezvous(ulong, ulong);
        #define open                p9open
        #define pipe                p9pipe
        #define        waitfor                p9waitfor
       +#define write                p9write
        #endif
        
        extern        Dir*        dirstat(char*);
       @@ -828,7 +834,8 @@ extern        char*        get9root(void);
        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 @@ extern        int        post9pservice(int, char*);
        #ifdef __GNUC__
        #        if __GNUC__ >= 3
        #                undef USED
       -#                define USED(x) { ulong __y __attribute__ ((unused)); __y = (ulong)(x); }
       +#                define USED(x) ((void)(x))
        #        endif
        #endif
        
   DIR diff --git a/lib9/malloctag.c b/lib9/malloctag.c
       @@ -1,9 +1,5 @@
        #include <lib9.h>
        
       -extern        long        p9lrand(void);
       -#define        USED(x)        if(x){}else{}
       -#define        lrand        p9lrand
       -
        void
        setmalloctag(void *v, ulong t)
        {
   DIR diff --git a/lib9/nan.c b/lib9/nan.c
       @@ -1,6 +1,6 @@
        #include <u.h>
        #include <libc.h>
       -#include "nan.h"
       +#include "fmt/nan.h"
        
        double
        NaN(void)
   DIR diff --git a/lib9/netcrypt.c b/lib9/netcrypt.c
       @@ -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;
       +}
   DIR diff --git a/lib9/netmkaddr.c b/lib9/netmkaddr.c
       @@ -16,21 +16,25 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
                 */
                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 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
                        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);
        
       +        snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
                return addr;
        }
   DIR diff --git a/lib9/notify.c b/lib9/notify.c
       @@ -38,6 +38,7 @@ enum
        {
                Restart = 1<<0,
                Ignore = 1<<1,
       +        NoNotify = 1<<2,
        };
        
        static Sig sigs[] = {
       @@ -58,7 +59,7 @@ static Sig sigs[] = {
                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 @@ static Sig sigs[] = {
                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 @@ noteinit(void)
                         */
                        if(handler(sig->sig) != SIG_DFL)
                                continue;
       -                notifyseton(sig->sig, 1);
       +                notifyseton(sig->sig, !(sig->flags&NoNotify));
                }
        }
        
   DIR diff --git a/lib9/nrand.c b/lib9/nrand.c
       @@ -1,7 +1,5 @@
        #include <lib9.h>
        
       -extern        long        p9lrand(void);
       -#define        lrand        p9lrand
        #define        MASK        0x7fffffffL
        
        int
   DIR diff --git a/lib9/nulldir.c b/lib9/nulldir.c
       @@ -5,5 +5,5 @@ void
        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 = "";
        }
   DIR diff --git a/lib9/opentemp.c b/lib9/opentemp.c
       @@ -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;
        }
        
   DIR diff --git a/lib9/pin.c b/lib9/pin.c
       @@ -0,0 +1,11 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +static void
       +nop(void)
       +{
       +}
       +
       +void (*_pin)(void) = nop;
       +void (*_unpin)(void) = nop;
       +
   DIR diff --git a/lib9/portdate b/lib9/portdate
       @@ -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
   DIR diff --git a/lib9/post9p.c b/lib9/post9p.c
       @@ -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)
       -                        return -1;
       -                s = smprint("unix!%s/%s", ns, name);
       -                free(ns);
       -        }
       -        if(s == nil)
       -                return -1;
       -        switch(fork()){
       -        case -1:
       +        if(name == nil && mtpt == nil){
       +                close(fd);
       +                werrstr("nothing to do");
                        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();
       -                if(w == nil)
       +        }
       +
       +        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;
       +                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);
       -                free(s);
       +                w = waitfor(pid);
       +                if(w == nil)
       +                        return -1;
                        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;
        }
   DIR diff --git a/lib9/rand.c b/lib9/rand.c
       @@ -1,8 +1,5 @@
        #include        <lib9.h>
        
       -extern        long        p9lrand(void);
       -#define        lrand        p9lrand
       -
        int
        p9rand(void)
        {
   DIR diff --git a/lib9/readn.c b/lib9/readn.c
       @@ -1,5 +1,4 @@
        #include <lib9.h>
       -#include <unistd.h>
        
        long
        readn(int f, void *av, long n)
   DIR diff --git a/lib9/regex/regcomp.c b/lib9/regex/regcomp.c
       @@ -261,18 +261,18 @@ optimize(Reprog *pp)
                        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;
        }
        
   DIR diff --git a/lib9/regex/regexec.c b/lib9/regex/regexec.c
       @@ -58,7 +58,7 @@ regexec1(Reprog *progp,        /* program to run */
                                        p = utfrune(s, '\n');
                                        if(p == 0 || s == j->eol)
                                                return match;
       -                                s = p;
       +                                s = p+1;
                                        break;
                                }
                        }
   DIR diff --git a/lib9/regex/rregexec.c b/lib9/regex/rregexec.c
       @@ -25,6 +25,7 @@ rregexec1(Reprog *progp,        /* program to run */
                Relist* tle;                /* ends of this and next list */
                Relist* nle;
                int match;
       +        Rune *p;
        
                match = 0;
                checkstart = j->startchar;
       @@ -44,20 +45,18 @@ rregexec1(Reprog *progp,        /* program to run */
                        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;
                                }
                        }
   DIR diff --git a/lib9/rfork.c b/lib9/rfork.c
       @@ -17,11 +17,12 @@ p9rfork(int flags)
                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 @@ p9rfork(int flags)
                        }
                        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){
   DIR diff --git a/lib9/sendfd.c b/lib9/sendfd.c
       @@ -78,7 +78,10 @@ recvfd(int s)
        
                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;
   DIR diff --git a/lib9/sleep.c b/lib9/sleep.c
       @@ -1,9 +1,21 @@
        #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)
        {
   DIR diff --git a/lib9/sysfatal.c b/lib9/sysfatal.c
       @@ -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
   DIR diff --git a/lib9/test.c b/lib9/test.c
       @@ -0,0 +1,8 @@
       +#include <lib9.h>
       +
       +int
       +main(int argc, char **argv)
       +{
       +        werrstr("hello world");
       +        print("%r\n");
       +}
   DIR diff --git a/lib9/testfltfmt.c b/lib9/testfltfmt.c
       @@ -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);
       +}
   DIR diff --git a/lib9/testfmt.c b/lib9/testfmt.c
       @@ -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);
       +}
   DIR diff --git a/lib9/testprint.c b/lib9/testprint.c
       @@ -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]));
       +}
   DIR diff --git a/lib9/tm2sec.c b/lib9/tm2sec.c
       @@ -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;
       +}
   DIR diff --git a/lib9/truerand.c b/lib9/truerand.c
       @@ -15,7 +15,7 @@ truerand(void)
                        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)
   DIR diff --git a/lib9/u.h b/lib9/u.h
       @@ -7,9 +7,10 @@ extern "C" {
        #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
       @@ -20,6 +21,17 @@ extern "C" {
        #        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 @@ extern "C" {
        #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 int8_t s8int;
        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 @@ typedef int32_t s32int;
         * 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
        
   DIR diff --git a/lib9/utf.h b/lib9/utf.h
       @@ -11,7 +11,7 @@ enum
                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 __ */
   DIR diff --git a/lib9/utf/NOTICE b/lib9/utf/NOTICE
       @@ -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.
       + */
   DIR diff --git a/lib9/utf/README b/lib9/utf/README
       @@ -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.
       + */
   DIR diff --git a/lib9/lib9.h b/lib9/utf/lib9.h
   DIR diff --git a/lib9/utf/rune.c b/lib9/utf/rune.c
       @@ -37,7 +37,7 @@ enum
                Maskx        = (1<<Bitx)-1,                        /* 0011 1111 */
                Testx        = Maskx ^ 0xFF,                        /* 1100 0000 */
        
       -        Bad        = Runeerror,
       +        Bad        = Runeerror
        };
        
        int
   DIR diff --git a/lib9/utf/utfecpy.c b/lib9/utf/utfecpy.c
       @@ -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"
   DIR diff --git a/lib9/write.c b/lib9/write.c
       @@ -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;
       +}
   DIR diff --git a/lib9/zoneinfo.c b/lib9/zoneinfo.c
       @@ -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;
       +        }
       +}
   DIR diff --git a/lib9/zoneinfo.h b/lib9/zoneinfo.h
       @@ -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);
       +
   DIR diff --git a/ls/ls.c b/ls/ls.c
       @@ -227,17 +227,16 @@ format(Dir *db, char *name)
                                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
   DIR diff --git a/mk/Makefile b/mk/Makefile
       @@ -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
   DIR diff --git a/mk/NOTICE b/mk/NOTICE
       @@ -1,27 +0,0 @@
       -Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
       -Portions Copyright © 1995-1997 C H Forsyth (forsyth@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.
   DIR diff --git a/mk/README b/mk/README
       @@ -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@post.harvard.edu>
       -
   DIR diff --git a/mk/arc.c b/mk/arc.c
       @@ -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);
       -}
   DIR diff --git a/mk/archive.c b/mk/archive.c
       @@ -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;
       -}
   DIR diff --git a/mk/bufblock.c b/mk/bufblock.c
       @@ -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;
       -}
   DIR diff --git a/mk/env.c b/mk/env.c
       @@ -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;
       -}
   DIR diff --git a/mk/file.c b/mk/file.c
       @@ -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;
       -                }
       -        }
       -}
   DIR diff --git a/mk/fns.h b/mk/fns.h
       @@ -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);
   DIR diff --git a/mk/graph.c b/mk/graph.c
       @@ -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;
       -}
   DIR diff --git a/mk/job.c b/mk/job.c
       @@ -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;
       -        }
       -}
   DIR diff --git a/mk/lex.c b/mk/lex.c
       @@ -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;
       -        }
       -}
   DIR diff --git a/mk/main.c b/mk/main.c
       @@ -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();
       -}
   DIR diff --git a/mk/match.c b/mk/match.c
       @@ -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;
       -}
   DIR diff --git a/mk/mk.1 b/mk/mk.1
       @@ -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.
   DIR diff --git a/mk/mk.c b/mk/mk.c
       @@ -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;
       -}
   DIR diff --git a/mk/mk.h b/mk/mk.h
       @@ -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"
   DIR diff --git a/mk/parse.c b/mk/parse.c
       @@ -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);
       -}
   DIR diff --git a/mk/rc.c b/mk/rc.c
       @@ -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,
       -};
   DIR diff --git a/mk/recipe.c b/mk/recipe.c
       @@ -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);
       -}
   DIR diff --git a/mk/rule.c b/mk/rule.c
       @@ -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);
       -}
   DIR diff --git a/mk/run.c b/mk/run.c
       @@ -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]);
       -}
   DIR diff --git a/mk/sh.c b/mk/sh.c
       @@ -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,
       -};
       -
   DIR diff --git a/mk/shell.c b/mk/shell.c
       @@ -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);
       -}
   DIR diff --git a/mk/shprint.c b/mk/shprint.c
       @@ -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);
       -}
   DIR diff --git a/mk/symtab.c b/mk/symtab.c
       @@ -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);
       -}
   DIR diff --git a/mk/sys.h b/mk/sys.h
       @@ -1,5 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <bio.h>
       -#include <regexp.h>
       -
   DIR diff --git a/mk/sys.std.h b/mk/sys.std.h
       @@ -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
   DIR diff --git a/mk/unix.c b/mk/unix.c
       @@ -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;
       -}
   DIR diff --git a/mk/var.c b/mk/var.c
       @@ -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;
       -}
   DIR diff --git a/mk/varsub.c b/mk/varsub.c
       @@ -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;
       -}
   DIR diff --git a/mk/word.c b/mk/word.c
       @@ -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');
       -}
   DIR diff --git a/rc/Makefile b/rc/Makefile
       @@ -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 @@ all:
        depend:
                @echo YACC ${YFILES}
                @${YACC} -d ${YFILES}
       +        @cp y.tab.h x.tab.h
        
        install: ${TARG}
                @mkdir -p ${DESTDIR}${PREFIX}/bin
   DIR diff --git a/rc/code.c b/rc/code.c
       @@ -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 @@ void codeswitch(tree*, int);
        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 @@ int compile(tree *t)
                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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
                                        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 @@ void outcode(tree *t, int eflag)
                        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 @@ void outcode(tree *t, int eflag)
         * 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 @@ void codeswitch(tree *t, int eflag)
                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 @@ void codeswitch(tree *t, int eflag)
                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++;
   DIR diff --git a/rc/exec.c b/rc/exec.c
       @@ -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)
       -{
       -        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;
       -}
       -word *newword(char *wd, word *next)
       -{
       -        word *p=new(word);
       -        p->word=strdup(wd);
       -        p->next=next;
       +
       +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->ret = runq;
       +        runq = p;
       +}
       +
       +word*
       +newword(char *wd, word *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 poplist(void){
       -        list *p=runq->argv;
       -        if(p==0) panic("poplist but no argv", 0);
       +
       +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);
                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;
       -}
       -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;
       +
       +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 *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 @@ main(int argc, char *argv[])
                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 @@ main(int argc, char *argv[])
         * 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 @@ main(int argc, char *argv[])
         * 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 @@ void Xappend(void){
                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,110 @@ void Xread(void){
                runq->pc++;
                poplist();
        }
       -void turfredir(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;
       +        }
       +        file = runq->argv->words->word;
       +        if((f = open(file, ORDWR))<0){
       +                pfmt(err, "%s: ", file);
       +                Xerror("can't open");
       +                return;
       +        }
       +        pushredir(ROPEN, f, runq->code[runq->pc].i);
       +        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);
       +
       +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;
       +
       +void
       +Xreturn(void)
       +{
       +        struct thread *p = runq;
                turfredir();
                while(p->argv) poplist();
                codefree(p->code);
       -        runq=p->ret;
       +        runq = p->ret;
                efree((char *)p);
       -        if(runq==0) Exit(getstatus());
       +        if(runq==0)
       +                Exit(getstatus());
        }
       -void Xtrue(void){
       +
       +void
       +Xtrue(void)
       +{
                if(truestatus()) runq->pc++;
       -        else runq->pc=runq->code[runq->pc].i;
       +        else runq->pc = runq->code[runq->pc].i;
        }
       -void Xif(void){
       -        ifnot=1;
       +
       +void
       +Xif(void)
       +{
       +        ifnot = 1;
                if(truestatus()) runq->pc++;
       -        else runq->pc=runq->code[runq->pc].i;
       +        else runq->pc = runq->code[runq->pc].i;
        }
       -void Xwastrue(void){
       -        ifnot=0;
       +
       +void
       +Xwastrue(void)
       +{
       +        ifnot = 0;
        }
       -void Xword(void){
       +
       +void
       +Xword(void)
       +{
                pushword(runq->code[runq->pc++].s);
        }
       -void Xwrite(void){
       +
       +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;
       +        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 = Creat(file))<0){
                        pfmt(err, "%s: ", file);
                        Xerror("can't open");
                        return;
       @@ -409,31 +491,35 @@ void Xwrite(void){
                runq->pc++;
                poplist();
        }
       -char *_list2str(word *words, int c){
       +
       +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;
       -        }
       -        if(s==value) *s='\0';
       +        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;
        }
       -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 @@ void Xmatch(void){
                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 @@ void Xcase(void){
                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 @@ void Xconc(void){
                                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 @@ void Xdol(void){
                        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 @@ void Xqdol(void){
                        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 @@ void Xqdol(void){
                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);
       -}
       -void Xsub(void){
       +        m = 0;
       +        n = 0;
       +        while('0'<=*s && *s<='9')
       +                n = n*10+ *s++ -'0';
       +        if(*s == '-'){
       +                if(*++s == 0)
       +                        m = len - n;
       +                else{
       +                        while('0'<=*s && *s<='9')
       +                                m = m*10+ *s++ -'0';
       +                        m -= n;
       +                }
       +        }
       +        if(n<1 || n>len || m<0)
       +                return a;
       +        if(n+m>len)
       +                m = len-n;
       +        while(--n > 0)
       +                val = val->next;
       +        return copynwords(val, a, m+1);
       +}
       +
       +void
       +Xsub(void)
       +{
                word *a, *v;
                char *s;
                if(count(runq->argv->next->words)!=1){
                        Xerror1("variable name not singleton!");
                        return;
                }
       -        s=runq->argv->next->words->word;
       +        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 @@ void Xcount(void){
                        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;
       -        }
       -        runq->pc=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;
       +        }
       +        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 @@ char *concstatus(char *s, char *t)
                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 @@ void Xpipewait(void){
                        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 @@ void Xrdcmds(void){
                }
                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 @@ void Xerror(char *s)
                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 @@ void Xerror1(char *s)
                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();
        }
   DIR diff --git a/rc/exec.h b/rc/exec.h
       @@ -5,6 +5,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void)
        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 @@ struct thread{
                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 *codecopy(code*);
        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 *);
   DIR diff --git a/rc/fns.h b/rc/fns.h
       @@ -7,13 +7,14 @@ int        Eintr(void);
        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        Updenv(void);
        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        pushlist(void);
        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);
   DIR diff --git a/rc/getflags.c b/rc/getflags.c
       @@ -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 @@ static int reason;
        #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;
       -                }
       -                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{
       +        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(*f=='\0'){ reason=FLAGSYN; return -1; }
       -                        }while(*f!=']');
       -                        f++;
       +                        }
       +                        if(c==fc)
       +                                return count;
                        }
       -                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 @@ void usage(char *tail)
                }
                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 @@ void usage(char *tail)
                        else if(*s=='['){
                                s++;
                                while(*s!=']' && *s!='\0') s++;
       -                        if(*s==']') s++;
       +                        if(*s==']')
       +                                s++;
                        }
                }
                if(tail){
       @@ -198,20 +218,27 @@ void usage(char *tail)
                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;
                }
        }
   DIR diff --git a/rc/glob.c b/rc/glob.c
       @@ -6,68 +6,77 @@ struct word *globv;
        /*
         * 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 @@ void globdir(char *p, char *namep)
         * 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 @@ void glob(char *p)
        /*
         * 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 @@ int equtf(char *p, char *q){
         * 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 @@ char *nextutf(char *p){
        /*
         * 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 @@ int unicode(char *p){
         * ? 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;
                }
        }
   DIR diff --git a/rc/havefork.c b/rc/havefork.c
       @@ -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 @@ void
        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 @@ Xasync(void)
                        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 @@ Xpipe(void)
                        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 @@ Xbackq(void)
                        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 @@ void
        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 @@ Xpipefd(void)
                        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 @@ Xsubshell(void)
                        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 @@ execforkexec(void)
                case -1:
                        return -1;
                case 0:
       +                clearwaitpids();
                        pushword("exec");
                        execexec();
                        strcpy(buf, "can't exec: ");
       @@ -218,5 +252,6 @@ execforkexec(void)
                        errstr(buf+n, ERRMAX-n);
                        Exit(buf);
                }
       +        addwaitpid(pid);
                return pid;
        }
   DIR diff --git a/rc/here.c b/rc/here.c
       @@ -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 @@ tree *heredoc(tree *tag)
         * 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 @@ void readhere(void){
                        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 @@ void psubst(io *f, char *s)
                        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);
                }
   DIR diff --git a/rc/io.c b/rc/io.c
       @@ -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 @@ void pdec(io *f, long n)
                                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;
        }
   DIR diff --git a/rc/io.h b/rc/io.h
       @@ -18,9 +18,9 @@ int rchr(io*);
        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*);
   DIR diff --git a/rc/lex.c b/rc/lex.c
       @@ -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 @@ int idchr(int c)
                 */
                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 @@ int yylex(void){
                 * we insert a `^' before it.
                 */
                if(lastword){
       -                lastword=0;
       +                lastword = 0;
                        if(d=='('){
                                advance();
                                strcpy(tok, "( [SUB]");
       @@ -157,15 +204,15 @@ int yylex(void){
                                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 @@ int yylex(void){
                        strcpy(tok, "$");
                        return '$';
                case '&':
       -                lastdol=0;
       +                lastdol = 0;
                        if(nextis('&')){
                                skipnl();
                                strcpy(tok, "&&");
       @@ -186,7 +233,7 @@ int yylex(void){
                        strcpy(tok, "&");
                        return '&';
                case '|':
       -                lastdol=0;
       +                lastdol = 0;
                        if(nextis(c)){
                                skipnl();
                                strcpy(tok, "||");
       @@ -194,7 +241,7 @@ int yylex(void){
                        }
                case '<':
                case '>':
       -                lastdol=0;
       +                lastdol = 0;
                        /*
                         * funny redirection tokens:
                         *        redir:        arrow | arrow '[' fd ']'
       @@ -204,121 +251,128 @@ int yylex(void){
                         * 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;
        }
       -
   DIR diff --git a/rc/pcmd.c b/rc/pcmd.c
       @@ -5,39 +5,66 @@ char nl='\n';                /* change to semicolon for bourne-proofing */
        #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 @@ void pcmd(io *f, tree *t)
                        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 @@ void pcmd(io *f, tree *t)
                        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);
   DIR diff --git a/rc/pfnc.c b/rc/pfnc.c
       @@ -5,7 +5,7 @@
        struct{
                void (*f)(void);
                char *name;
       -}fname[]={
       +}fname[] = {
                Xappend, "Xappend",
                Xasync, "Xasync",
                Xbang, "Xbang",
       @@ -18,6 +18,7 @@ struct{
                Xjump, "Xjump",
                Xmark, "Xmark",
                Xpopm, "Xpopm",
       +        Xrdwr, "Xrdwr",
                Xread, "Xread",
                Xreturn, "Xreturn",
                Xtrue, "Xtrue",
       @@ -50,18 +51,21 @@ struct{
                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);
        }
   DIR diff --git a/rc/plan9ish.c b/rc/plan9ish.c
       @@ -27,12 +27,11 @@ char *syssigname[]={
        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 @@ void Vinit(void){
                        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 @@ int Waitfor(int pid, int unused0){
                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 @@ int Waitfor(int pid, int unused0){
                                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 @@ int Waitfor(int pid, int unused0){
                        free(w);
                }
        
       -        errstr(errbuf, sizeof errbuf);
       +        rerrstr(errbuf, sizeof errbuf);
                if(strcmp(errbuf, "interrupted")==0) return -1;
                return 0;
        }
       @@ -412,9 +414,11 @@ int Opendir(char *name)
                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 @@ long Read(int fd, char *buf, long cnt)
        {
                int i;
        
       -        i = read(fd, buf, cnt);
       +        i = readnb(fd, buf, cnt);
                if(ntrap) dotrap();
                return i;
        }
       @@ -547,3 +551,54 @@ void Memcpy(char *a, char *b, long n)
        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;
       +}
   DIR diff --git a/rc/rc.1 b/rc/rc.1
       @@ -208,6 +208,11 @@ If
        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
   DIR diff --git a/rc/rc.h b/rc/rc.h
       @@ -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 @@ char tok[NTOK];
        #define        HERE        4
        #define        DUPFD        5
        #define        CLOSE        6
       +#define        RDWR        7
        struct var{
                char *name;                /* ascii name */
                word *val;        /* value */
   DIR diff --git a/rc/simple.c b/rc/simple.c
       @@ -15,22 +15,24 @@ exitnext(void){
                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 @@ void Xsimple(void){
                                        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 @@ void Xsimple(void){
                        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 @@ void doredir(redir *rp)
                                        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 @@ void execexec(void){
                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 @@ int dochdir(char *word){
                }
                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 @@ void execcd(void){
                                        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 @@ void execcd(void){
                }
                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 @@ void execshift(void){
                        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 @@ void execeval(void){
                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 @@ void execdot(void){
                        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 @@ void execdot(void){
                /* 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 @@ void execflag(void){
                }
                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 @@ void execwhatis(void){        /* mildly wrong -- should fork before writing */
                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();
        }
   DIR diff --git a/rc/subr.c b/rc/subr.c
       @@ -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 @@ void yyerror(char *m)
                        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 @@ void iacvt(int n){
                        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);
   DIR diff --git a/rc/trap.c b/rc/trap.c
       @@ -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){
                                /*
   DIR diff --git a/rc/tree.c b/rc/tree.c
       @@ -7,108 +7,140 @@ tree *treenodes;
         * 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);
        }
   DIR diff --git a/rc/unixcrap.c b/rc/unixcrap.c
       @@ -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 @@ out:
                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;
       +}
   DIR diff --git a/rc/var.c b/rc/var.c
       @@ -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 @@ struct kw{
                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 @@ void kinit(void){
                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 @@ void bigpath(var *v)
                }
                _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;
        
   DIR diff --git a/sed/sed.1 b/sed/sed.1
       @@ -4,10 +4,7 @@ sed \- stream editor
        .SH SYNOPSIS
        .B sed
        [
       -.B -n
       -]
       -[
       -.B -g
       +.B -gln
        ]
        [
        .B -e
       @@ -44,6 +41,11 @@ option suppresses the default output;
        .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:
   DIR diff --git a/sed/sed.c b/sed/sed.c
       @@ -16,7 +16,7 @@ enum {
                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 @@ typedef struct        {
                        A_DOL,
                        A_LINE,
                        A_RE,
       -                A_LAST,
       +                A_LAST
                }type;
                union {
                        long line;                /* Line # */
       @@ -137,6 +137,7 @@ Rune        *hspend = holdsp;                /* End of hold data */
        
        int        nflag;                                /* Command line flags */
        int        gflag;
       +int        lflag;
        
        int        dolflag;                        /* Set when at true EOF */
        int        sflag;                                /* Set when substitution done */
       @@ -234,6 +235,9 @@ main(int argc, char **argv)
                        case 'g':
                                gflag++;
                                continue;
       +                case 'l':
       +                        lflag++;
       +                        continue;
                        default:
                                fprint(2, "sed: Unknown flag: %c\n", ARGC());
                                continue;
       @@ -990,7 +994,7 @@ match(Reprog *pattern, Rune *buf)
                        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 @@ putline(Biobuf *bp, Rune *buf, int n)
                while (n--)
                        Bputrune(bp, *buf++);
                Bputc(bp, '\n');
       +        if(lflag)
       +                Bflush(bp);
        }
        
        int
   DIR diff --git a/sort/sort.c b/sort/sort.c
       @@ -34,7 +34,7 @@ enum
                NSzerofract,
                NSexp,
                NSexpsign,
       -        NSexpdigit,
       +        NSexpdigit
        };
        
        typedef        struct        Line        Line;
       @@ -243,8 +243,7 @@ notifyf(void *a, char *s)
                        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 @@ Rune*        month[12] =
        
        enum
        {
       -        Threshold        = 14,
       +        Threshold        = 14
        };
        
        void        rsort4(Key***, ulong, int);
   DIR diff --git a/test/test.1 b/test/test.1
       @@ -17,7 +17,7 @@ The following primitives are used to construct
        .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 @@ following operators:
        .TP "\w'\fL( \fIexpr\fL )XX'u"
        .B  !
        unary negation operator
       -.PD
       +.PD0
        .TP
        .B  -o
        binary
   DIR diff --git a/test/test.c b/test/test.c
       @@ -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 EQ(a,b)        ((tmp=a)==0?0:(strcmp(tmp,b)==0))
        
       -extern int isatty(int); /* <unistd.h> */
       +#define isatty plan9_isatty
       +
       +#define EQ(a,b)        ((tmp=a)==0?0:(strcmp(tmp,b)==0))
        
        int        ap;
        int        ac;
       @@ -23,14 +25,21 @@ void        synbad(char *, char *);
        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 @@ main(int argc, char *argv[])
                                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 @@ nxtintarg(int *pans)
        }
        
        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 @@ e2(void) {
        }
        
        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);
                }
        
       @@ -113,6 +135,9 @@ e3(void) {
                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 @@ e3(void) {
                        return(fsizep(nxtarg(0)));
        
                if(EQ(a, "-t"))
       -                if(ap>=ac || !nxtintarg(&int1))
       +                if(ap>=ac)
                                return(isatty(1));
       -                else
       +                else if(nxtintarg(&int1))
                                return(isatty(int1));
       +                else
       +                        synbad("not a valid file descriptor number ", "");
        
                if(EQ(a, "-n"))
                        return(!EQ(nxtarg(0), ""));
       @@ -166,8 +193,17 @@ e3(void) {
                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 @@ localstat(char *f, Dir *dir)
                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 @@ localfstat(int f, Dir *dir)
                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 @@ isreg(char *f)
        }
        
        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 @@ isint(char *s, int *pans)
                *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;
       +}
   DIR diff --git a/touch/touch.c b/touch/touch.c
       @@ -3,6 +3,7 @@
        
        int touch(int, char *);
        ulong now;
       +int tflag;
        
        void
        usage(void)
       @@ -20,6 +21,7 @@ main(int argc, char **argv)
                now = time(0);
                ARGBEGIN{
                case 't':
       +                tflag = 1;
                        now = strtoul(EARGF(usage()), 0, 0);
                        break;
                case 'c':
       @@ -52,11 +54,15 @@ touch(int nocreate, char *name)
                        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;
        }
   DIR diff --git a/yacc/yacc.c b/yacc/yacc.c
       @@ -98,7 +98,7 @@ enum
                EMPTY                = 1,
                WHOKNOWS        = 0,
                OK                = 1,
       -        NOMORE                = -1000,
       +        NOMORE                = -1000
        };
        
                /* macros for getting associativity and precedence levels */
       @@ -1223,7 +1223,7 @@ setup(int argc, char *argv[])
                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;