tToday's changes. More changes. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 8ad517944e46710ab832350c0dc3fc4e9239f7e2
 (DIR) parent cb27443abf3d6af6ab52377c71c843e619928433
 (HTM) Author: rsc <devnull@localhost>
       Date:   Thu, 25 Mar 2004 23:03:57 +0000
       
       Today's changes.
       More changes.
       
       Diffstat:
         M include/fmt.h                       |       1 +
         M include/lib9.h                      |     876 +------------------------------
         M include/libString.h                 |       2 +-
         M include/libc.h                      |     794 ++++++++++++++++++++++++++++++-
         M include/u.h                         |      93 +++++++++++++++++++++++++++++++
         M src/cmd/9pserve.c                   |       2 +-
         M src/cmd/9term/9term.c               |     456 +++++++++++++++++++------------
         M src/cmd/9term/9term.h               |      21 +++------------------
         M src/cmd/9term/FreeBSD.c             |      40 +++++++++++++++++++++++++------
         M src/cmd/9term/Linux.c               |      48 +++++++++++++++++++++++--------
         M src/cmd/9term/SunOS.c               |      37 +++++++++++++++++--------------
         M src/cmd/9term/mkfile                |       8 ++++----
         A src/cmd/9term/rcstart.c             |      51 +++++++++++++++++++++++++++++++
         A src/cmd/9term/term.h                |       5 +++++
         A src/cmd/9term/win.c                 |     693 +++++++++++++++++++++++++++++++
         M src/cmd/acme/acme.c                 |      24 +++++++++++++-----------
         M src/cmd/acme/dat.h                  |       1 +
         M src/cmd/acme/ecmd.c                 |       2 +-
         M src/cmd/acme/exec.c                 |       4 +++-
         M src/cmd/acme/fns.h                  |       5 ++++-
         M src/cmd/acme/fsys.c                 |      44 ++++++++++++++++++++-----------
         M src/cmd/acme/look.c                 |      12 ++++++------
         M src/cmd/acme/text.c                 |       2 +-
         M src/cmd/acme/util.c                 |      23 ++++++++++++++++++-----
         M src/cmd/acme/xfid.c                 |       3 ---
         M src/cmd/dict/dict.c                 |       2 ++
         M src/cmd/diff/diff.h                 |       2 ++
         M src/cmd/diff/main.c                 |       2 ++
         M src/cmd/fortune.c                   |       8 ++++++--
         A src/cmd/grep/comp.c                 |     277 +++++++++++++++++++++++++++++++
         A src/cmd/grep/grep.h                 |     125 +++++++++++++++++++++++++++++++
         A src/cmd/grep/grep.y                 |     226 +++++++++++++++++++++++++++++++
         A src/cmd/grep/main.c                 |     260 +++++++++++++++++++++++++++++++
         A src/cmd/grep/mkfile                 |      20 ++++++++++++++++++++
         A src/cmd/grep/sub.c                  |     317 +++++++++++++++++++++++++++++++
         M src/cmd/mkfile                      |       4 ++--
         M src/cmd/plumb/fsys.c                |       1 +
         M src/cmd/plumb/plumber.c             |       7 ++++---
         M src/cmd/plumb/rules.c               |       2 +-
         M src/cmd/rc/plan9ish.c               |      14 ++------------
         A src/cmd/rio/Imakefile               |      27 +++++++++++++++++++++++++++
         M src/cmd/rio/color.c                 |       2 +-
         M src/cmd/rio/main.c                  |      13 +++++++++----
         M src/cmd/rio/mkfile                  |       5 +++++
         M src/cmd/spell/sprog.c               |       3 +++
         D src/cmd/win.c                       |     717 -------------------------------
         M src/cmd/yacc.c                      |       2 +-
         M src/lib9/_p9translate.c             |       4 ++--
         D src/lib9/access.c                   |      19 -------------------
         M src/lib9/announce.c                 |       5 +++--
         M src/lib9/create.c                   |      10 +---------
         M src/lib9/ctime.c                    |       7 +++++++
         M src/lib9/date.c                     |      12 ++++++++++--
         M src/lib9/dirread.c                  |       4 ++--
         M src/lib9/errstr.c                   |       3 ++-
         A src/lib9/ffork-OpenBSD.c            |       1 +
         M src/lib9/getuser.c                  |       3 +--
         M src/lib9/lock.c                     |       3 ++-
         M src/lib9/mallocz.c                  |       3 ++-
         M src/lib9/mkfile                     |       4 ++--
         M src/lib9/notify.c                   |       3 +--
         M src/lib9/open.c                     |       9 +--------
         M src/lib9/rendez-Linux.c             |       2 ++
         C src/lib9/rendez-Linux.c -> src/lib… |       0 
         M src/lib9/rendez-pthread.c           |       3 ++-
         M src/lib9/time.c                     |       4 ++--
         M src/libdraw/openfont.c              |       4 +++-
         M src/libdraw/x11-init.c              |      23 +++++++++++++++++------
         M src/libdraw/x11-itrans.c            |       3 +++
         M src/libplumb/mesg.c                 |       1 -
         A src/libthread/asm-OpenBSD-386.s     |      49 +++++++++++++++++++++++++++++++
         M src/libthread/exec-unix.c           |      41 ++++++++++++++++++++++++++++---
         M src/libthread/label.h               |       2 +-
         M src/mkfile                          |       2 +-
       
       74 files changed, 3539 insertions(+), 1968 deletions(-)
       ---
 (DIR) diff --git a/include/fmt.h b/include/fmt.h
       t@@ -80,6 +80,7 @@ extern        int        fmtfdflush(Fmt*);
        extern        int        fmtstrinit(Fmt*);
        extern        char*        fmtstrflush(Fmt*);
        extern        int        runefmtstrinit(Fmt*);
       +extern        Rune*        runefmtstrflush(Fmt*);
        
        extern        int        quotestrfmt(Fmt *f);
        extern        void        quotefmtinstall(void);
 (DIR) diff --git a/include/lib9.h b/include/lib9.h
       t@@ -1,874 +1,2 @@
       -/*
       - * Lib9 is miscellany from the Plan 9 C library that doesn't
       - * fit into libutf or into libfmt, but is still missing from traditional
       - * Unix C libraries.
       - */
       -#ifndef _LIB9_H_
       -#define _LIB9_H_ 1
       -#if defined(__cplusplus)
       -extern "C" {
       -#endif                                                                          
       -
       -#define _BSD_SOURCE 1
       -#define _SVID_SOURCE 1
       -#define _XOPEN_SOURCE 1000
       -#define _XOPEN_SOURCE_EXTENDED 1
       -#define _LARGEFILE64_SOURCE 1
       -#define _FILE_OFFSET_BITS 64
       -#define __EXTENSIONS__ 1 /* SunOS */
       -
       -#include <unistd.h>
       -#include <string.h>
       -#include <stdlib.h>
       -#include <stdarg.h>
       -#include <fcntl.h>
       -#include <assert.h>
       -#include <setjmp.h>
       -#include <stddef.h>
       -#include <utf.h>
       -#include <fmt.h>
       -#include <math.h>
       -
       -/*
       - * OS-specific crap
       - */
       -#define _NEEDUCHAR 1
       -#define _NEEDUSHORT 1
       -#define _NEEDUINT 1
       -#define _NEEDULONG 1
       -
       -typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
       -
       -#if defined(__linux__)
       -#        include <sys/types.h>
       -#        if defined(__USE_MISC)
       -#                undef _NEEDUSHORT
       -#                undef _NEEDUINT
       -#                undef _NEEDULONG
       -#        endif
       -#endif
       -#if defined(__sun__)
       -#        include <sys/types.h>
       -#        undef _NEEDUSHORT
       -#        undef _NEEDUINT
       -#        undef _NEEDULONG
       -#endif
       -#if defined(__FreeBSD__)
       -#        include <sys/types.h>
       -#        if !defined(_POSIX_SOURCE)
       -#                undef _NEEDUSHORT
       -#                undef _NEEDUINT
       -#        endif
       -#endif
       -#if defined(__APPLE__)
       -#        include <sys/types.h>
       -#        undef _NEEDUSHORT
       -#        undef _NEEDUINT
       -#        define _NEEDLL 1
       -#endif
       -
       -typedef signed char schar;
       -typedef unsigned int u32int;
       -#ifdef _NEEDUCHAR
       -        typedef unsigned char uchar;
       -#endif
       -#ifdef _NEEDUSHORT
       -        typedef unsigned short ushort;
       -#endif
       -#ifdef _NEEDUINT
       -        typedef unsigned int uint;
       -#endif
       -#ifdef _NEEDULONG
       -        typedef unsigned long ulong;
       -#endif
       -typedef unsigned long long uvlong;
       -typedef long long vlong;
       -typedef uvlong u64int;
       -typedef uchar u8int;
       -typedef ushort u16int;
       -
       -#undef _NEEDUCHAR
       -#undef _NEEDUSHORT
       -#undef _NEEDUINT
       -#undef _NEEDULONG
       -
       -/*
       - * Begin usual libc.h 
       - */
       -
       -#define        nil        ((void*)0)
       -#define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
       -
       -#ifndef offsetof
       -#define offsetof(s, m)        (ulong)(&(((s*)0)->m))
       -#endif
       -
       -/*
       - * mem routines (provided by system <string.h>)
       - *
       -extern        void*        memccpy(void*, void*, int, ulong);
       -extern        void*        memset(void*, int, ulong);
       -extern        int        memcmp(void*, void*, ulong);
       -extern        void*        memcpy(void*, void*, ulong);
       -extern        void*        memmove(void*, void*, ulong);
       -extern        void*        memchr(void*, int, ulong);
       - */
       -
       -/*
       - * string routines (provided by system <string.h>)
       - *
       -extern        char*        strcat(char*, char*);
       -extern        char*        strchr(char*, int);
       -extern        int        strcmp(char*, char*);
       -extern        char*        strcpy(char*, char*);
       - */
       -extern        char*        strecpy(char*, char*, char*);
       - /*
       -extern        char*        strdup(char*);
       -extern        char*        strncat(char*, char*, long);
       -extern        char*        strncpy(char*, char*, long);
       -extern        int        strncmp(char*, char*, long);
       -extern        char*        strpbrk(char*, char*);
       -extern        char*        strrchr(char*, int);
       -extern        char*        strtok(char*, char*);
       -extern        long        strlen(char*);
       -extern        long        strspn(char*, char*);
       -extern        long        strcspn(char*, char*);
       -extern        char*        strstr(char*, char*);
       - */
       -extern        int        cistrncmp(char*, char*, int);
       -extern        int        cistrcmp(char*, char*);
       -extern        char*        cistrstr(char*, char*);
       -extern        int        tokenize(char*, char**, int);
       -
       -/*
       -enum
       -{
       -        UTFmax                = 3,
       -        Runesync        = 0x80,
       -        Runeself        = 0x80,
       -        Runeerror        = 0x80,
       -};
       -*/
       -
       -/*
       - * rune routines (provided by <utf.h>
       - *
       -extern        int        runetochar(char*, Rune*);
       -extern        int        chartorune(Rune*, char*);
       -extern        int        runelen(long);
       -extern        int        runenlen(Rune*, int);
       -extern        int        fullrune(char*, int);
       -extern        int        utflen(char*);
       -extern        int        utfnlen(char*, long);
       -extern        char*        utfrune(char*, long);
       -extern        char*        utfrrune(char*, long);
       -extern        char*        utfutf(char*, char*);
       -extern        char*        utfecpy(char*, char*, char*);
       -
       -extern        Rune*        runestrcat(Rune*, Rune*);
       -extern        Rune*        runestrchr(Rune*, Rune);
       -extern        int        runestrcmp(Rune*, Rune*);
       -extern        Rune*        runestrcpy(Rune*, Rune*);
       -extern        Rune*        runestrncpy(Rune*, Rune*, long);
       -extern        Rune*        runestrecpy(Rune*, Rune*, Rune*);
       -extern        Rune*        runestrdup(Rune*);
       -extern        Rune*        runestrncat(Rune*, Rune*, long);
       -extern        int        runestrncmp(Rune*, Rune*, long);
       -extern        Rune*        runestrrchr(Rune*, Rune);
       -extern        long        runestrlen(Rune*);
       -extern        Rune*        runestrstr(Rune*, Rune*);
       -
       -extern        Rune        tolowerrune(Rune);
       -extern        Rune        totitlerune(Rune);
       -extern        Rune        toupperrune(Rune);
       -extern        int        isalpharune(Rune);
       -extern        int        islowerrune(Rune);
       -extern        int        isspacerune(Rune);
       -extern        int        istitlerune(Rune);
       -extern        int        isupperrune(Rune);
       - */
       -
       -/*
       - * malloc (provied by system <stdlib.h>)
       - *
       -extern        void*        malloc(ulong);
       - */
       -extern        void*        p9malloc(ulong);
       -extern        void*        mallocz(ulong, int);
       -/*
       -extern        void        free(void*);
       -extern        ulong        msize(void*);
       -extern        void*        calloc(ulong, ulong);
       -extern        void*        realloc(void*, ulong);
       - */
       -extern        void                setmalloctag(void*, ulong);
       -extern        void                setrealloctag(void*, ulong);
       -extern        ulong        getmalloctag(void*);
       -extern        ulong        getrealloctag(void*);
       -/*
       -extern        void*        malloctopoolblock(void*);
       -*/
       -#ifndef NOPLAN9DEFINES
       -#define        malloc        p9malloc
       -#endif
       -
       -/*
       - * print routines (provided by <fmt.h>)
       - *
       -typedef struct Fmt        Fmt;
       -struct Fmt{
       -        uchar        runes;
       -        void        *start;
       -        void        *to;
       -        void        *stop;
       -        int        (*flush)(Fmt *);
       -        void        *farg;
       -        int        nfmt;
       -        va_list        args;
       -        int        r;
       -        int        width;
       -        int        prec;
       -        ulong        flags;
       -};
       -
       -enum{
       -        FmtWidth        = 1,
       -        FmtLeft                = FmtWidth << 1,
       -        FmtPrec                = FmtLeft << 1,
       -        FmtSharp        = FmtPrec << 1,
       -        FmtSpace        = FmtSharp << 1,
       -        FmtSign                = FmtSpace << 1,
       -        FmtZero                = FmtSign << 1,
       -        FmtUnsigned        = FmtZero << 1,
       -        FmtShort        = FmtUnsigned << 1,
       -        FmtLong                = FmtShort << 1,
       -        FmtVLong        = FmtLong << 1,
       -        FmtComma        = FmtVLong << 1,
       -        FmtByte        = FmtComma << 1,
       -
       -        FmtFlag                = FmtByte << 1
       -};
       -
       -extern        int        print(char*, ...);
       -extern        char*        seprint(char*, char*, char*, ...);
       -extern        char*        vseprint(char*, char*, char*, va_list);
       -extern        int        snprint(char*, int, char*, ...);
       -extern        int        vsnprint(char*, int, char*, va_list);
       -extern        char*        smprint(char*, ...);
       -extern        char*        vsmprint(char*, va_list);
       -extern        int        sprint(char*, char*, ...);
       -extern        int        fprint(int, char*, ...);
       -extern        int        vfprint(int, char*, va_list);
       -
       -extern        int        runesprint(Rune*, char*, ...);
       -extern        int        runesnprint(Rune*, int, char*, ...);
       -extern        int        runevsnprint(Rune*, int, char*, va_list);
       -extern        Rune*        runeseprint(Rune*, Rune*, char*, ...);
       -extern        Rune*        runevseprint(Rune*, Rune*, char*, va_list);
       -extern        Rune*        runesmprint(char*, ...);
       -extern        Rune*        runevsmprint(char*, va_list);
       -
       -extern        int        fmtfdinit(Fmt*, int, char*, int);
       -extern        int        fmtfdflush(Fmt*);
       -extern        int        fmtstrinit(Fmt*);
       -extern        char*        fmtstrflush(Fmt*);
       -extern        int        runefmtstrinit(Fmt*);
       -extern        Rune*        runefmtstrflush(Fmt*);
       -
       -extern        int        fmtinstall(int, int (*)(Fmt*));
       -extern        int        dofmt(Fmt*, char*);
       -extern        int        dorfmt(Fmt*, Rune*);
       -extern        int        fmtprint(Fmt*, char*, ...);
       -extern        int        fmtvprint(Fmt*, char*, va_list);
       -extern        int        fmtrune(Fmt*, int);
       -extern        int        fmtstrcpy(Fmt*, char*);
       -extern        int        fmtrunestrcpy(Fmt*, Rune*);
       - */
       -
       -/*
       - * error string for %r
       - * supplied on per os basis, not part of fmt library
       - *
       - * (provided by lib9, but declared in fmt.h)
       - *
       -extern        int        errfmt(Fmt *f);
       - */
       -
       -/*
       - * quoted strings
       - */
       -extern        char        *unquotestrdup(char*);
       -extern        Rune        *unquoterunestrdup(Rune*);
       -extern        char        *quotestrdup(char*);
       -extern        Rune        *quoterunestrdup(Rune*);
       -/*
       - * in fmt.h
       - *
       -extern        void        quotefmtinstall(void);
       -extern        int        quotestrfmt(Fmt*);
       -extern        int        quoterunestrfmt(Fmt*);
       - */
       -#ifndef NOPLAN9DEFINES
       -#define doquote fmtdoquote
       -#endif
       -extern        int        needsrcquote(int);
       -
       -/*
       - * random number (in <stdlib.h>)
       - *
       -extern        void        srand(long);
       -extern        int        rand(void);
       - */
       -extern        int        nrand(int);
       -extern        long        lrand(void);
       -extern        long        lnrand(long);
       -extern        double        frand(void);
       -extern        ulong        truerand(void);                        /* uses /dev/random */
       -extern        ulong        ntruerand(ulong);                /* uses /dev/random */
       -
       -/*
       - * math
       - */
       -extern        ulong        getfcr(void);
       -extern        void        setfsr(ulong);
       -extern        ulong        getfsr(void);
       -extern        void        setfcr(ulong);
       -extern        double        NaN(void);
       -extern        double        Inf(int);
       -extern        int        isNaN(double);
       -extern        int        isInf(double, int);
       -extern        ulong        umuldiv(ulong, ulong, ulong);
       -extern        long        muldiv(long, long, long);
       -
       -/*
       - * provided by math.h
       - *
       -extern        double        pow(double, double);
       -extern        double        atan2(double, double);
       -extern        double        fabs(double);
       -extern        double        atan(double);
       -extern        double        log(double);
       -extern        double        log10(double);
       -extern        double        exp(double);
       -extern        double        floor(double);
       -extern        double        ceil(double);
       -extern        double        hypot(double, double);
       -extern        double        sin(double);
       -extern        double        cos(double);
       -extern        double        tan(double);
       -extern        double        asin(double);
       -extern        double        acos(double);
       -extern        double        sinh(double);
       -extern        double        cosh(double);
       -extern        double        tanh(double);
       -extern        double        sqrt(double);
       -extern        double        fmod(double, double);
       -#define        HUGE        3.4028234e38
       -#define        PIO2        1.570796326794896619231e0
       -#define        PI        (PIO2+PIO2)
       - */
       -#define PI        M_PI
       -#define        PIO2        M_PI_2
       -
       -/*
       - * Time-of-day
       - */
       -
       -typedef
       -struct Tm
       -{
       -        int        sec;
       -        int        min;
       -        int        hour;
       -        int        mday;
       -        int        mon;
       -        int        year;
       -        int        wday;
       -        int        yday;
       -        char        zone[4];
       -        int        tzoff;
       -} Tm;
       -
       -extern        Tm*        p9gmtime(long);
       -extern        Tm*        p9localtime(long);
       -extern        char*        p9asctime(Tm*);
       -extern        char*        p9ctime(long);
       -extern        double        p9cputime(void);
       -extern        long        p9times(long*);
       -extern        long        p9tm2sec(Tm*);
       -extern        vlong        p9nsec(void);
       -
       -#ifndef NOPLAN9DEFINES
       -#define        gmtime                p9gmtime
       -#define        localtime        p9localtime
       -#define        asctime                p9asctime
       -#define        ctime                p9ctime
       -#define        cputime                p9cputime
       -#define        times                p9times
       -#define        tm2sec                p9tm2sec
       -#define        nsec                p9nsec
       -#endif
       -
       -/*
       - * one-of-a-kind
       - */
       -enum
       -{
       -        PNPROC                = 1,
       -        PNGROUP                = 2,
       -};
       -
       -/* extern        int        abs(int); <stdlib.h> */
       -extern        int        p9atexit(void(*)(void));
       -extern        void        p9atexitdont(void(*)(void));
       -extern        int        atnotify(int(*)(void*, char*), int);
       -/* 
       - * <stdlib.h>
       -extern        double        atof(char*); <stdlib.h>
       -extern        int        atoi(char*);
       -extern        long        atol(char*);
       - */
       -extern        vlong        atoll(const char*);
       -extern        double        charstod(int(*)(void*), void*);
       -extern        char*        cleanname(char*);
       -extern        int        p9decrypt(void*, void*, int);
       -extern        int        p9encrypt(void*, void*, int);
       -extern        int        dec64(uchar*, int, char*, int);
       -extern        int        enc64(char*, int, uchar*, int);
       -extern        int        dec32(uchar*, int, char*, int);
       -extern        int        enc32(char*, int, uchar*, int);
       -extern        int        dec16(uchar*, int, char*, int);
       -extern        int        enc16(char*, int, uchar*, int);
       -extern        int        encodefmt(Fmt*);
       -extern        int        dirmodefmt(Fmt*);
       -extern        void        exits(char*);
       -extern        double        frexp(double, int*);
       -extern        ulong        getcallerpc(void*);
       -extern        char*        p9getenv(char*);
       -extern        int        p9putenv(char*, char*);
       -extern        int        getfields(char*, char**, int, int, char*);
       -extern        int        gettokens(char *, char **, int, char *);
       -extern        char*        getuser(void);
       -extern        char*        p9getwd(char*, int);
       -extern        int        iounit(int);
       -/* extern        long        labs(long); <math.h> */
       -/* extern        double        ldexp(double, int); <math.h> */
       -extern        void        p9longjmp(p9jmp_buf, int);
       -extern        char*        mktemp(char*);
       -extern        int                opentemp(char*);
       -/* extern        double        modf(double, double*); <math.h> */
       -extern        int        netcrypt(void*, void*);
       -extern        void        p9notejmp(void*, p9jmp_buf, int);
       -extern        void        perror(const char*);
       -extern        int        postnote(int, int, char *);
       -extern        double        pow10(int);
       -/* extern        int        putenv(char*, char*); <stdlib.h. */
       -/* extern        void        qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
       -/* extern        int        p9setjmp(p9jmp_buf); */
       -#define p9setjmp(b)        sigsetjmp((void*)(b), 1)
       -/*
       - * <stdlib.h>
       -extern        double        strtod(char*, char**);
       -extern        long        strtol(char*, char**, int);
       -extern        ulong        strtoul(char*, char**, int);
       -extern        vlong        strtoll(char*, char**, int);
       -extern        uvlong        strtoull(char*, char**, int);
       - */
       -extern        void        sysfatal(char*, ...);
       -extern        void        p9syslog(int, char*, char*, ...);
       -extern        long        time(long*);
       -/* extern        int        tolower(int); <ctype.h> */
       -/* extern        int        toupper(int); <ctype.h> */
       -#ifndef NOPLAN9DEFINES
       -#define atexit                p9atexit
       -#define atexitdont        p9atexitdont
       -#define encrypt                p9encrypt
       -#define decrypt                p9decrypt
       -#define getenv                p9getenv
       -#define        getwd                p9getwd
       -#define        longjmp                p9longjmp
       -#undef  setjmp
       -#define setjmp                p9setjmp
       -#define putenv                p9putenv
       -#define notejmp                p9notejmp
       -#define jmp_buf                p9jmp_buf
       -#define syslog                p9syslog
       -#endif
       -
       -/*
       - *  synchronization
       - */
       -typedef
       -struct Lock {
       -        int        val;
       -} Lock;
       -
       -extern int        _tas(int*);
       -
       -extern        void        lock(Lock*);
       -extern        void        unlock(Lock*);
       -extern        int        canlock(Lock*);
       -
       -typedef struct QLp QLp;
       -struct QLp
       -{
       -        int        inuse;
       -        QLp        *next;
       -        char        state;
       -};
       -
       -typedef
       -struct QLock
       -{
       -        Lock        lock;
       -        int        locked;
       -        QLp        *head;
       -        QLp         *tail;
       -} QLock;
       -
       -extern        void        qlock(QLock*);
       -extern        void        qunlock(QLock*);
       -extern        int        canqlock(QLock*);
       -extern        void        _qlockinit(ulong (*)(ulong, ulong));        /* called only by the thread library */
       -
       -typedef
       -struct RWLock
       -{
       -        Lock        lock;
       -        int        readers;        /* number of readers */
       -        int        writer;                /* number of writers */
       -        QLp        *head;                /* list of waiting processes */
       -        QLp        *tail;
       -} RWLock;
       -
       -extern        void        rlock(RWLock*);
       -extern        void        runlock(RWLock*);
       -extern        int                canrlock(RWLock*);
       -extern        void        wlock(RWLock*);
       -extern        void        wunlock(RWLock*);
       -extern        int                canwlock(RWLock*);
       -
       -typedef
       -struct Rendez
       -{
       -        QLock *l;
       -        QLp        *head;
       -        QLp        *tail;
       -} Rendez;
       -
       -extern        void        rsleep(Rendez*);        /* unlocks r->l, sleeps, locks r->l again */
       -extern        int        rwakeup(Rendez*);
       -extern        int        rwakeupall(Rendez*);
       -extern        void**        privalloc(void);
       -extern        void        privfree(void**);
       -
       -/*
       - *  network dialing
       - */
       -#define NETPATHLEN 40
       -extern        int        p9accept(int, char*);
       -extern        int        p9announce(char*, char*);
       -extern        int        p9dial(char*, char*, char*, int*);
       -extern        void        p9setnetmtpt(char*, int, char*);
       -extern        int        p9hangup(int);
       -extern        int        p9listen(char*, char*);
       -extern        char*        p9netmkaddr(char*, char*, char*);
       -extern        int        p9reject(int, char*, char*);
       -
       -#ifndef NOPLAN9DEFINES
       -#define        accept                p9accept
       -#define        announce        p9announce
       -#define        dial                p9dial
       -#define        setnetmtpt        p9setnetmtpt
       -#define        hangup                p9hangup
       -#define        listen                p9listen
       -#define        netmkaddr        p9netmkaddr
       -#define        reject                p9reject
       -#endif
       -
       -/*
       - *  encryption
       - */
       -extern        int        pushssl(int, char*, char*, char*, int*);
       -extern        int        pushtls(int, char*, char*, int, char*, char*);
       -
       -/*
       - *  network services
       - */
       -typedef struct NetConnInfo NetConnInfo;
       -struct NetConnInfo
       -{
       -        char        *dir;                /* connection directory */
       -        char        *root;                /* network root */
       -        char        *spec;                /* binding spec */
       -        char        *lsys;                /* local system */
       -        char        *lserv;                /* local service */
       -        char        *rsys;                /* remote system */
       -        char        *rserv;                /* remote service */
       -};
       -extern        NetConnInfo*        getnetconninfo(char*, int);
       -extern        void                freenetconninfo(NetConnInfo*);
       -
       -/*
       - * system calls
       - *
       - */
       -#define        STATMAX        65535U        /* max length of machine-independent stat structure */
       -#define        DIRMAX        (sizeof(Dir)+STATMAX)        /* max length of Dir structure */
       -#define        ERRMAX        128        /* max length of error string */
       -
       -#define        MORDER        0x0003        /* mask for bits defining order of mounting */
       -#define        MREPL        0x0000        /* mount replaces object */
       -#define        MBEFORE        0x0001        /* mount goes before others in union directory */
       -#define        MAFTER        0x0002        /* mount goes after others in union directory */
       -#define        MCREATE        0x0004        /* permit creation in mounted directory */
       -#define        MCACHE        0x0010        /* cache some data */
       -#define        MMASK        0x0017        /* all bits on */
       -
       -#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        OEXCL        0x1000        /* or'ed in, exclusive use (create only) */
       -
       -#define        AEXIST        0        /* accessible: exists */
       -#define        AEXEC        1        /* execute access */
       -#define        AWRITE        2        /* write access */
       -#define        AREAD        4        /* read access */
       -
       -/* Segattch */
       -#define        SG_RONLY        0040        /* read only */
       -#define        SG_CEXEC        0100        /* detach on exec */
       -
       -#define        NCONT        0        /* continue after note */
       -#define        NDFLT        1        /* terminate after note */
       -#define        NSAVE        2        /* clear note but hold state */
       -#define        NRSTR        3        /* restore saved state */
       -
       -/* bits in Qid.type */
       -#define QTDIR                0x80                /* type bit for directories */
       -#define QTAPPEND        0x40                /* type bit for append only files */
       -#define QTEXCL                0x20                /* type bit for exclusive use files */
       -#define QTMOUNT                0x10                /* type bit for mounted channel */
       -#define QTAUTH                0x08                /* type bit for authentication file */
       -#define QTFILE                0x00                /* plain file */
       -
       -/* bits in Dir.mode */
       -#define DMDIR                0x80000000        /* mode bit for directories */
       -#define DMAPPEND        0x40000000        /* mode bit for append only files */
       -#define DMEXCL                0x20000000        /* mode bit for exclusive use files */
       -#define DMMOUNT                0x10000000        /* mode bit for mounted channel */
       -#define DMAUTH                0x08000000        /* mode bit for authentication file */
       -#define DMREAD                0x4                /* mode bit for read permission */
       -#define DMWRITE                0x2                /* mode bit for write permission */
       -#define DMEXEC                0x1                /* mode bit for execute permission */
       -
       -#if defined(__FreeBSD__)
       -#undef RFFDG
       -#undef RFNOTEG
       -#undef RFPROC
       -#undef RFMEM
       -#undef RFNOWAIT
       -#undef RFCFDG
       -#undef RFNAMEG
       -#undef RFENVG
       -#undef RFCENVG
       -#undef RFCFDG
       -#undef RFCNAMEG
       -#endif
       -
       -enum
       -{
       -        RFNAMEG                = (1<<0), 
       -        RFENVG                = (1<<1), 
       -        RFFDG                = (1<<2),
       -        RFNOTEG                = (1<<3),
       -        RFPROC                = (1<<4),
       -        RFMEM                = (1<<5),
       -        RFNOWAIT        = (1<<6),
       -        RFCNAMEG        = (1<<10), 
       -        RFCENVG                = (1<<11), 
       -        RFCFDG                = (1<<12),
       -/*        RFREND                = (1<<13), */
       -/*        RFNOMNT                = (1<<14) */
       -};
       -
       -extern int                ffork(int, void(*)(void*), void*);
       -
       -typedef
       -struct Qid
       -{
       -        uvlong        path;
       -        ulong        vers;
       -        uchar        type;
       -} Qid;
       -
       -typedef
       -struct Dir {
       -        /* system-modified data */
       -        ushort        type;        /* server type */
       -        uint        dev;        /* server subtype */
       -        /* file data */
       -        Qid        qid;        /* unique id from server */
       -        ulong        mode;        /* permissions */
       -        ulong        atime;        /* last read time */
       -        ulong        mtime;        /* last write time */
       -        vlong        length;        /* file length */
       -        char        *name;        /* last element of path */
       -        char        *uid;        /* owner name */
       -        char        *gid;        /* group name */
       -        char        *muid;        /* last modifier name */
       -} Dir;
       -
       -/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
       -typedef
       -struct Waitmsg
       -{
       -        int pid;        /* of loved one */
       -        ulong time[3];        /* of loved one & descendants */
       -        char        *msg;
       -} Waitmsg;
       -
       -typedef
       -struct IOchunk
       -{
       -        void        *addr;
       -        ulong        len;
       -} IOchunk;
       -
       -extern        void        _exits(char*);
       -
       -extern        void        abort(void);
       -extern        int        p9access(char*, int);
       -extern        long        p9alarm(ulong);
       -extern        int        await(char*, int);
       -extern        int        awaitnohang(char*, int);
       -/* extern        int        bind(char*, char*, int); give up */
       -/* extern        int        brk(void*); <unistd.h> */
       -extern        int        p9chdir(char*);
       -extern        int        close(int);
       -extern        int        p9create(char*, int, ulong);
       -extern        int        p9dup(int, int);
       -extern        int        errstr(char*, uint);
       -extern        int        p9exec(char*, char*[]);
       -/* extern        int        execl(char*, ...); <unistd.h> */
       -/* extern        int        fork(void); <unistd.h> */
       -extern        int        p9rfork(int);
       -/* not implemented 
       -extern        int        fauth(int, char*);
       -extern        int        fstat(int, uchar*, int);
       -extern        int        fwstat(int, uchar*, int);
       -extern        int        fversion(int, int, char*, int);
       -extern        int        mount(int, int, char*, int, char*);
       -extern        int        unmount(char*, char*);
       -*/
       -extern        int        noted(int);
       -extern        int        notify(void(*)(void*, char*));
       -extern        int        p9open(char*, int);
       -extern        int        fd2path(int, char*, int);
       -extern        int        p9pipe(int*);
       -/* 
       - * use defs from <unistd.h>
       -extern        long        pread(int, void*, long, vlong);
       -extern        long        preadv(int, IOchunk*, int, vlong);
       -extern        long        pwrite(int, void*, long, vlong);
       -extern        long        pwritev(int, IOchunk*, int, vlong);
       -extern        long        read(int, void*, long);
       - */
       -extern        long        readn(int, void*, long);
       -/* extern        long        readv(int, IOchunk*, int); <unistd.h> */
       -extern        int        remove(const char*);
       -/* extern        void*        sbrk(ulong); <unistd.h> */
       -/* extern        long        oseek(int, long, int); */
       -extern        vlong        p9seek(int, vlong, int);
       -/* give up
       -extern        long        segattach(int, char*, void*, ulong);
       -extern        int        segbrk(void*, void*);
       -extern        int        segdetach(void*);
       -extern        int        segflush(void*, ulong);
       -extern        int        segfree(void*, ulong);
       -*/
       -extern        int        p9sleep(long);
       -/* extern        int        stat(char*, uchar*, int); give up */
       -extern        Waitmsg*        p9wait(void);
       -extern        Waitmsg*        waitnohang(void);
       -extern        int        p9waitpid(void);
       -/* <unistd.h>
       -extern        long        write(int, void*, long);
       -extern        long        writev(int, IOchunk*, int);
       -*/
       -/* extern        int        wstat(char*, uchar*, int); give up */
       -extern        ulong        rendezvous(ulong, ulong);
       -
       -#ifndef NOPLAN9DEFINES
       -#define alarm                p9alarm
       -#define        dup                p9dup
       -#define        exec                p9exec
       -#define        seek                p9seek
       -#define sleep                p9sleep
       -#define wait                p9wait
       -#define waitpid                p9waitpid
       -#define rfork                p9rfork
       -#define access                p9access
       -#define create                p9create
       -#define open                p9open
       -#define pipe                p9pipe
       -#endif
       -
       -extern        Dir*        dirstat(char*);
       -extern        Dir*        dirfstat(int);
       -extern        int        dirwstat(char*, Dir*);
       -extern        int        dirfwstat(int, Dir*);
       -extern        long        dirread(int, Dir**);
       -extern        void        nulldir(Dir*);
       -extern        long        dirreadall(int, Dir**);
       -/* extern        int        getpid(void); <unistd.h> */
       -/* extern        int        getppid(void); */
       -extern        void        rerrstr(char*, uint);
       -extern        char*        sysname(void);
       -extern        void        werrstr(char*, ...);
       -extern        char*        getns(void);
       -extern        int        sendfd(int, int);
       -extern        int        recvfd(int);
       -extern        int        post9pservice(int, char*);
       -
       -/* external names that we don't want to step on */
       -#ifndef NOPLAN9DEFINES
       -#define main        p9main
       -#endif
       -
       -/* compiler directives on plan 9 */
       -#define        USED(x)        if(x){}else{}
       -#define        SET(x)        ((x)=0)
       -
       -/* command line */
       -extern char        *argv0;
       -extern void __fixargv0(void);
       -#define        ARGBEGIN        for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
       -                            argv[0] && argv[0][0]=='-' && argv[0][1];\
       -                            argc--, argv++) {\
       -                                char *_args, *_argt;\
       -                                Rune _argc;\
       -                                _args = &argv[0][1];\
       -                                if(_args[0]=='-' && _args[1]==0){\
       -                                        argc--; argv++; break;\
       -                                }\
       -                                _argc = 0;\
       -                                while(*_args && (_args += chartorune(&_argc, _args)))\
       -                                switch(_argc)
       -#define        ARGEND                SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
       -#define        ARGF()                (_argt=_args, _args="",\
       -                                (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
       -#define        EARGF(x)        (_argt=_args, _args="",\
       -                                (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
       -
       -#define        ARGC()                _argc
       -
       -#if defined(__cplusplus)
       -}
       -#endif
       -#endif        /* _LIB9_H_ */
       +#include <u.h>
       +#include <libc.h>
 (DIR) diff --git a/include/libString.h b/include/libString.h
       t@@ -43,4 +43,4 @@ typedef struct Sinstack Sinstack;
        extern char        *s_rdinstack(Sinstack*, String*);
        extern Sinstack        *s_allocinstack(char*);
        extern void        s_freeinstack(Sinstack*);
       -#endif BGETC
       +#endif /* BGETC */
 (DIR) diff --git a/include/libc.h b/include/libc.h
       t@@ -1,2 +1,794 @@
       -#include <lib9.h>
       +/*
       + * Lib9 is miscellany from the Plan 9 C library that doesn't
       + * fit into libutf or into libfmt, but is still missing from traditional
       + * Unix C libraries.
       + */
       +#ifndef _LIBC_H_
       +#define _LIBC_H_ 1
       +#if defined(__cplusplus)
       +extern "C" {
       +#endif                                                                          
        
       +/*
       + * Begin usual libc.h 
       + */
       +
       +#define        nil        ((void*)0)
       +#define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
       +
       +#ifndef offsetof
       +#define offsetof(s, m)        (ulong)(&(((s*)0)->m))
       +#endif
       +
       +/*
       + * mem routines (provided by system <string.h>)
       + *
       +extern        void*        memccpy(void*, void*, int, ulong);
       +extern        void*        memset(void*, int, ulong);
       +extern        int        memcmp(void*, void*, ulong);
       +extern        void*        memcpy(void*, void*, ulong);
       +extern        void*        memmove(void*, void*, ulong);
       +extern        void*        memchr(void*, int, ulong);
       + */
       +
       +/*
       + * string routines (provided by system <string.h>)
       + *
       +extern        char*        strcat(char*, char*);
       +extern        char*        strchr(char*, int);
       +extern        int        strcmp(char*, char*);
       +extern        char*        strcpy(char*, char*);
       + */
       +extern        char*        strecpy(char*, char*, char*);
       + /*
       +extern        char*        strdup(char*);
       +extern        char*        strncat(char*, char*, long);
       +extern        char*        strncpy(char*, char*, long);
       +extern        int        strncmp(char*, char*, long);
       +extern        char*        strpbrk(char*, char*);
       +extern        char*        strrchr(char*, int);
       +extern        char*        strtok(char*, char*);
       +extern        long        strlen(char*);
       +extern        long        strspn(char*, char*);
       +extern        long        strcspn(char*, char*);
       +extern        char*        strstr(char*, char*);
       + */
       +extern        int        cistrncmp(char*, char*, int);
       +extern        int        cistrcmp(char*, char*);
       +extern        char*        cistrstr(char*, char*);
       +extern        int        tokenize(char*, char**, int);
       +
       +/*
       +enum
       +{
       +        UTFmax                = 3,
       +        Runesync        = 0x80,
       +        Runeself        = 0x80,
       +        Runeerror        = 0x80,
       +};
       +*/
       +
       +/*
       + * rune routines (provided by <utf.h>
       + *
       +extern        int        runetochar(char*, Rune*);
       +extern        int        chartorune(Rune*, char*);
       +extern        int        runelen(long);
       +extern        int        runenlen(Rune*, int);
       +extern        int        fullrune(char*, int);
       +extern        int        utflen(char*);
       +extern        int        utfnlen(char*, long);
       +extern        char*        utfrune(char*, long);
       +extern        char*        utfrrune(char*, long);
       +extern        char*        utfutf(char*, char*);
       +extern        char*        utfecpy(char*, char*, char*);
       +
       +extern        Rune*        runestrcat(Rune*, Rune*);
       +extern        Rune*        runestrchr(Rune*, Rune);
       +extern        int        runestrcmp(Rune*, Rune*);
       +extern        Rune*        runestrcpy(Rune*, Rune*);
       +extern        Rune*        runestrncpy(Rune*, Rune*, long);
       +extern        Rune*        runestrecpy(Rune*, Rune*, Rune*);
       +extern        Rune*        runestrdup(Rune*);
       +extern        Rune*        runestrncat(Rune*, Rune*, long);
       +extern        int        runestrncmp(Rune*, Rune*, long);
       +extern        Rune*        runestrrchr(Rune*, Rune);
       +extern        long        runestrlen(Rune*);
       +extern        Rune*        runestrstr(Rune*, Rune*);
       +
       +extern        Rune        tolowerrune(Rune);
       +extern        Rune        totitlerune(Rune);
       +extern        Rune        toupperrune(Rune);
       +extern        int        isalpharune(Rune);
       +extern        int        islowerrune(Rune);
       +extern        int        isspacerune(Rune);
       +extern        int        istitlerune(Rune);
       +extern        int        isupperrune(Rune);
       + */
       +
       +/*
       + * malloc (provied by system <stdlib.h>)
       + *
       +extern        void*        malloc(ulong);
       + */
       +extern        void*        p9malloc(ulong);
       +extern        void*        mallocz(ulong, int);
       +/*
       +extern        void        free(void*);
       +extern        ulong        msize(void*);
       +extern        void*        calloc(ulong, ulong);
       +extern        void*        realloc(void*, ulong);
       + */
       +extern        void                setmalloctag(void*, ulong);
       +extern        void                setrealloctag(void*, ulong);
       +extern        ulong        getmalloctag(void*);
       +extern        ulong        getrealloctag(void*);
       +/*
       +extern        void*        malloctopoolblock(void*);
       +*/
       +#ifndef NOPLAN9DEFINES
       +#define        malloc        p9malloc
       +#endif
       +
       +/*
       + * print routines (provided by <fmt.h>)
       + *
       +typedef struct Fmt        Fmt;
       +struct Fmt{
       +        uchar        runes;
       +        void        *start;
       +        void        *to;
       +        void        *stop;
       +        int        (*flush)(Fmt *);
       +        void        *farg;
       +        int        nfmt;
       +        va_list        args;
       +        int        r;
       +        int        width;
       +        int        prec;
       +        ulong        flags;
       +};
       +
       +enum{
       +        FmtWidth        = 1,
       +        FmtLeft                = FmtWidth << 1,
       +        FmtPrec                = FmtLeft << 1,
       +        FmtSharp        = FmtPrec << 1,
       +        FmtSpace        = FmtSharp << 1,
       +        FmtSign                = FmtSpace << 1,
       +        FmtZero                = FmtSign << 1,
       +        FmtUnsigned        = FmtZero << 1,
       +        FmtShort        = FmtUnsigned << 1,
       +        FmtLong                = FmtShort << 1,
       +        FmtVLong        = FmtLong << 1,
       +        FmtComma        = FmtVLong << 1,
       +        FmtByte        = FmtComma << 1,
       +
       +        FmtFlag                = FmtByte << 1
       +};
       +
       +extern        int        print(char*, ...);
       +extern        char*        seprint(char*, char*, char*, ...);
       +extern        char*        vseprint(char*, char*, char*, va_list);
       +extern        int        snprint(char*, int, char*, ...);
       +extern        int        vsnprint(char*, int, char*, va_list);
       +extern        char*        smprint(char*, ...);
       +extern        char*        vsmprint(char*, va_list);
       +extern        int        sprint(char*, char*, ...);
       +extern        int        fprint(int, char*, ...);
       +extern        int        vfprint(int, char*, va_list);
       +
       +extern        int        runesprint(Rune*, char*, ...);
       +extern        int        runesnprint(Rune*, int, char*, ...);
       +extern        int        runevsnprint(Rune*, int, char*, va_list);
       +extern        Rune*        runeseprint(Rune*, Rune*, char*, ...);
       +extern        Rune*        runevseprint(Rune*, Rune*, char*, va_list);
       +extern        Rune*        runesmprint(char*, ...);
       +extern        Rune*        runevsmprint(char*, va_list);
       +
       +extern        int        fmtfdinit(Fmt*, int, char*, int);
       +extern        int        fmtfdflush(Fmt*);
       +extern        int        fmtstrinit(Fmt*);
       +extern        char*        fmtstrflush(Fmt*);
       +extern        int        runefmtstrinit(Fmt*);
       +extern        Rune*        runefmtstrflush(Fmt*);
       +
       +extern        int        fmtinstall(int, int (*)(Fmt*));
       +extern        int        dofmt(Fmt*, char*);
       +extern        int        dorfmt(Fmt*, Rune*);
       +extern        int        fmtprint(Fmt*, char*, ...);
       +extern        int        fmtvprint(Fmt*, char*, va_list);
       +extern        int        fmtrune(Fmt*, int);
       +extern        int        fmtstrcpy(Fmt*, char*);
       +extern        int        fmtrunestrcpy(Fmt*, Rune*);
       + */
       +
       +/*
       + * error string for %r
       + * supplied on per os basis, not part of fmt library
       + *
       + * (provided by lib9, but declared in fmt.h)
       + *
       +extern        int        errfmt(Fmt *f);
       + */
       +
       +/*
       + * quoted strings
       + */
       +extern        char        *unquotestrdup(char*);
       +extern        Rune        *unquoterunestrdup(Rune*);
       +extern        char        *quotestrdup(char*);
       +extern        Rune        *quoterunestrdup(Rune*);
       +/*
       + * in fmt.h
       + *
       +extern        void        quotefmtinstall(void);
       +extern        int        quotestrfmt(Fmt*);
       +extern        int        quoterunestrfmt(Fmt*);
       + */
       +#ifndef NOPLAN9DEFINES
       +#define doquote fmtdoquote
       +#endif
       +extern        int        needsrcquote(int);
       +
       +/*
       + * random number (in <stdlib.h>)
       + *
       +extern        void        srand(long);
       +extern        int        rand(void);
       + */
       +extern        int        nrand(int);
       +extern        long        lrand(void);
       +extern        long        lnrand(long);
       +extern        double        frand(void);
       +extern        ulong        truerand(void);                        /* uses /dev/random */
       +extern        ulong        ntruerand(ulong);                /* uses /dev/random */
       +
       +/*
       + * math
       + */
       +extern        ulong        getfcr(void);
       +extern        void        setfsr(ulong);
       +extern        ulong        getfsr(void);
       +extern        void        setfcr(ulong);
       +extern        double        NaN(void);
       +extern        double        Inf(int);
       +extern        int        isNaN(double);
       +extern        int        isInf(double, int);
       +extern        ulong        umuldiv(ulong, ulong, ulong);
       +extern        long        muldiv(long, long, long);
       +
       +/*
       + * provided by math.h
       + *
       +extern        double        pow(double, double);
       +extern        double        atan2(double, double);
       +extern        double        fabs(double);
       +extern        double        atan(double);
       +extern        double        log(double);
       +extern        double        log10(double);
       +extern        double        exp(double);
       +extern        double        floor(double);
       +extern        double        ceil(double);
       +extern        double        hypot(double, double);
       +extern        double        sin(double);
       +extern        double        cos(double);
       +extern        double        tan(double);
       +extern        double        asin(double);
       +extern        double        acos(double);
       +extern        double        sinh(double);
       +extern        double        cosh(double);
       +extern        double        tanh(double);
       +extern        double        sqrt(double);
       +extern        double        fmod(double, double);
       +#define        HUGE        3.4028234e38
       +#define        PIO2        1.570796326794896619231e0
       +#define        PI        (PIO2+PIO2)
       + */
       +#define PI        M_PI
       +#define        PIO2        M_PI_2
       +
       +/*
       + * Time-of-day
       + */
       +
       +typedef
       +struct Tm
       +{
       +        int        sec;
       +        int        min;
       +        int        hour;
       +        int        mday;
       +        int        mon;
       +        int        year;
       +        int        wday;
       +        int        yday;
       +        char        zone[4];
       +        int        tzoff;
       +} Tm;
       +
       +extern        Tm*        p9gmtime(long);
       +extern        Tm*        p9localtime(long);
       +extern        char*        p9asctime(Tm*);
       +extern        char*        p9ctime(long);
       +extern        double        p9cputime(void);
       +extern        long        p9times(long*);
       +extern        long        p9tm2sec(Tm*);
       +extern        vlong        p9nsec(void);
       +
       +#ifndef NOPLAN9DEFINES
       +#define        gmtime                p9gmtime
       +#define        localtime        p9localtime
       +#define        asctime                p9asctime
       +#define        ctime                p9ctime
       +#define        cputime                p9cputime
       +#define        times                p9times
       +#define        tm2sec                p9tm2sec
       +#define        nsec                p9nsec
       +#endif
       +
       +/*
       + * one-of-a-kind
       + */
       +enum
       +{
       +        PNPROC                = 1,
       +        PNGROUP                = 2,
       +};
       +
       +/* extern        int        abs(int); <stdlib.h> */
       +extern        int        p9atexit(void(*)(void));
       +extern        void        p9atexitdont(void(*)(void));
       +extern        int        atnotify(int(*)(void*, char*), int);
       +/* 
       + * <stdlib.h>
       +extern        double        atof(char*); <stdlib.h>
       +extern        int        atoi(char*);
       +extern        long        atol(char*);
       + */
       +extern        vlong        atoll(const char*);
       +extern        double        charstod(int(*)(void*), void*);
       +extern        char*        cleanname(char*);
       +extern        int        p9decrypt(void*, void*, int);
       +extern        int        p9encrypt(void*, void*, int);
       +extern        int        dec64(uchar*, int, char*, int);
       +extern        int        enc64(char*, int, uchar*, int);
       +extern        int        dec32(uchar*, int, char*, int);
       +extern        int        enc32(char*, int, uchar*, int);
       +extern        int        dec16(uchar*, int, char*, int);
       +extern        int        enc16(char*, int, uchar*, int);
       +extern        int        encodefmt(Fmt*);
       +extern        int        dirmodefmt(Fmt*);
       +extern        void        exits(char*);
       +extern        double        frexp(double, int*);
       +extern        ulong        getcallerpc(void*);
       +extern        char*        p9getenv(char*);
       +extern        int        p9putenv(char*, char*);
       +extern        int        getfields(char*, char**, int, int, char*);
       +extern        int        gettokens(char *, char **, int, char *);
       +extern        char*        getuser(void);
       +extern        char*        p9getwd(char*, int);
       +extern        int        iounit(int);
       +/* extern        long        labs(long); <math.h> */
       +/* extern        double        ldexp(double, int); <math.h> */
       +extern        void        p9longjmp(p9jmp_buf, int);
       +extern        char*        mktemp(char*);
       +extern        int                opentemp(char*);
       +/* extern        double        modf(double, double*); <math.h> */
       +extern        int        netcrypt(void*, void*);
       +extern        void        p9notejmp(void*, p9jmp_buf, int);
       +extern        void        perror(const char*);
       +extern        int        postnote(int, int, char *);
       +extern        double        pow10(int);
       +/* extern        int        putenv(char*, char*); <stdlib.h. */
       +/* extern        void        qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
       +/* extern        int        p9setjmp(p9jmp_buf); */
       +#define p9setjmp(b)        sigsetjmp((void*)(b), 1)
       +/*
       + * <stdlib.h>
       +extern        double        strtod(char*, char**);
       +extern        long        strtol(char*, char**, int);
       +extern        ulong        strtoul(char*, char**, int);
       +extern        vlong        strtoll(char*, char**, int);
       +extern        uvlong        strtoull(char*, char**, int);
       + */
       +extern        void        sysfatal(char*, ...);
       +extern        void        p9syslog(int, char*, char*, ...);
       +extern        long        p9time(long*);
       +/* extern        int        tolower(int); <ctype.h> */
       +/* extern        int        toupper(int); <ctype.h> */
       +#ifndef NOPLAN9DEFINES
       +#define atexit                p9atexit
       +#define atexitdont        p9atexitdont
       +#define encrypt                p9encrypt
       +#define decrypt                p9decrypt
       +#define getenv                p9getenv
       +#define        getwd                p9getwd
       +#define        longjmp                p9longjmp
       +#undef  setjmp
       +#define setjmp                p9setjmp
       +#define putenv                p9putenv
       +#define notejmp                p9notejmp
       +#define jmp_buf                p9jmp_buf
       +#define syslog                p9syslog
       +#define time                p9time
       +#endif
       +
       +/*
       + *  synchronization
       + */
       +typedef
       +struct Lock {
       +        int        val;
       +} Lock;
       +
       +extern int        _tas(int*);
       +
       +extern        void        lock(Lock*);
       +extern        void        unlock(Lock*);
       +extern        int        canlock(Lock*);
       +
       +typedef struct QLp QLp;
       +struct QLp
       +{
       +        int        inuse;
       +        QLp        *next;
       +        char        state;
       +};
       +
       +typedef
       +struct QLock
       +{
       +        Lock        lock;
       +        int        locked;
       +        QLp        *head;
       +        QLp         *tail;
       +} QLock;
       +
       +extern        void        qlock(QLock*);
       +extern        void        qunlock(QLock*);
       +extern        int        canqlock(QLock*);
       +extern        void        _qlockinit(ulong (*)(ulong, ulong));        /* called only by the thread library */
       +
       +typedef
       +struct RWLock
       +{
       +        Lock        lock;
       +        int        readers;        /* number of readers */
       +        int        writer;                /* number of writers */
       +        QLp        *head;                /* list of waiting processes */
       +        QLp        *tail;
       +} RWLock;
       +
       +extern        void        rlock(RWLock*);
       +extern        void        runlock(RWLock*);
       +extern        int                canrlock(RWLock*);
       +extern        void        wlock(RWLock*);
       +extern        void        wunlock(RWLock*);
       +extern        int                canwlock(RWLock*);
       +
       +typedef
       +struct Rendez
       +{
       +        QLock *l;
       +        QLp        *head;
       +        QLp        *tail;
       +} Rendez;
       +
       +extern        void        rsleep(Rendez*);        /* unlocks r->l, sleeps, locks r->l again */
       +extern        int        rwakeup(Rendez*);
       +extern        int        rwakeupall(Rendez*);
       +extern        void**        privalloc(void);
       +extern        void        privfree(void**);
       +
       +/*
       + *  network dialing
       + */
       +#define NETPATHLEN 40
       +extern        int        p9accept(int, char*);
       +extern        int        p9announce(char*, char*);
       +extern        int        p9dial(char*, char*, char*, int*);
       +extern        void        p9setnetmtpt(char*, int, char*);
       +extern        int        p9hangup(int);
       +extern        int        p9listen(char*, char*);
       +extern        char*        p9netmkaddr(char*, char*, char*);
       +extern        int        p9reject(int, char*, char*);
       +
       +#ifndef NOPLAN9DEFINES
       +#define        accept                p9accept
       +#define        announce        p9announce
       +#define        dial                p9dial
       +#define        setnetmtpt        p9setnetmtpt
       +#define        hangup                p9hangup
       +#define        listen                p9listen
       +#define        netmkaddr        p9netmkaddr
       +#define        reject                p9reject
       +#endif
       +
       +/*
       + *  encryption
       + */
       +extern        int        pushssl(int, char*, char*, char*, int*);
       +extern        int        pushtls(int, char*, char*, int, char*, char*);
       +
       +/*
       + *  network services
       + */
       +typedef struct NetConnInfo NetConnInfo;
       +struct NetConnInfo
       +{
       +        char        *dir;                /* connection directory */
       +        char        *root;                /* network root */
       +        char        *spec;                /* binding spec */
       +        char        *lsys;                /* local system */
       +        char        *lserv;                /* local service */
       +        char        *rsys;                /* remote system */
       +        char        *rserv;                /* remote service */
       +};
       +extern        NetConnInfo*        getnetconninfo(char*, int);
       +extern        void                freenetconninfo(NetConnInfo*);
       +
       +/*
       + * system calls
       + *
       + */
       +#define        STATMAX        65535U        /* max length of machine-independent stat structure */
       +#define        DIRMAX        (sizeof(Dir)+STATMAX)        /* max length of Dir structure */
       +#define        ERRMAX        128        /* max length of error string */
       +
       +#define        MORDER        0x0003        /* mask for bits defining order of mounting */
       +#define        MREPL        0x0000        /* mount replaces object */
       +#define        MBEFORE        0x0001        /* mount goes before others in union directory */
       +#define        MAFTER        0x0002        /* mount goes after others in union directory */
       +#define        MCREATE        0x0004        /* permit creation in mounted directory */
       +#define        MCACHE        0x0010        /* cache some data */
       +#define        MMASK        0x0017        /* all bits on */
       +
       +#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        OEXCL        0x1000        /* or'ed in, exclusive use (create only) */
       +
       +#define        AEXIST        0        /* accessible: exists */
       +#define        AEXEC        1        /* execute access */
       +#define        AWRITE        2        /* write access */
       +#define        AREAD        4        /* read access */
       +
       +/* Segattch */
       +#define        SG_RONLY        0040        /* read only */
       +#define        SG_CEXEC        0100        /* detach on exec */
       +
       +#define        NCONT        0        /* continue after note */
       +#define        NDFLT        1        /* terminate after note */
       +#define        NSAVE        2        /* clear note but hold state */
       +#define        NRSTR        3        /* restore saved state */
       +
       +/* bits in Qid.type */
       +#define QTDIR                0x80                /* type bit for directories */
       +#define QTAPPEND        0x40                /* type bit for append only files */
       +#define QTEXCL                0x20                /* type bit for exclusive use files */
       +#define QTMOUNT                0x10                /* type bit for mounted channel */
       +#define QTAUTH                0x08                /* type bit for authentication file */
       +#define QTFILE                0x00                /* plain file */
       +
       +/* bits in Dir.mode */
       +#define DMDIR                0x80000000        /* mode bit for directories */
       +#define DMAPPEND        0x40000000        /* mode bit for append only files */
       +#define DMEXCL                0x20000000        /* mode bit for exclusive use files */
       +#define DMMOUNT                0x10000000        /* mode bit for mounted channel */
       +#define DMAUTH                0x08000000        /* mode bit for authentication file */
       +#define DMREAD                0x4                /* mode bit for read permission */
       +#define DMWRITE                0x2                /* mode bit for write permission */
       +#define DMEXEC                0x1                /* mode bit for execute permission */
       +
       +#if defined(__FreeBSD__)
       +#undef RFFDG
       +#undef RFNOTEG
       +#undef RFPROC
       +#undef RFMEM
       +#undef RFNOWAIT
       +#undef RFCFDG
       +#undef RFNAMEG
       +#undef RFENVG
       +#undef RFCENVG
       +#undef RFCFDG
       +#undef RFCNAMEG
       +#endif
       +
       +enum
       +{
       +        RFNAMEG                = (1<<0), 
       +        RFENVG                = (1<<1), 
       +        RFFDG                = (1<<2),
       +        RFNOTEG                = (1<<3),
       +        RFPROC                = (1<<4),
       +        RFMEM                = (1<<5),
       +        RFNOWAIT        = (1<<6),
       +        RFCNAMEG        = (1<<10), 
       +        RFCENVG                = (1<<11), 
       +        RFCFDG                = (1<<12),
       +/*        RFREND                = (1<<13), */
       +/*        RFNOMNT                = (1<<14) */
       +};
       +
       +extern int                ffork(int, void(*)(void*), void*);
       +
       +typedef
       +struct Qid
       +{
       +        uvlong        path;
       +        ulong        vers;
       +        uchar        type;
       +} Qid;
       +
       +typedef
       +struct Dir {
       +        /* system-modified data */
       +        ushort        type;        /* server type */
       +        uint        dev;        /* server subtype */
       +        /* file data */
       +        Qid        qid;        /* unique id from server */
       +        ulong        mode;        /* permissions */
       +        ulong        atime;        /* last read time */
       +        ulong        mtime;        /* last write time */
       +        vlong        length;        /* file length */
       +        char        *name;        /* last element of path */
       +        char        *uid;        /* owner name */
       +        char        *gid;        /* group name */
       +        char        *muid;        /* last modifier name */
       +} Dir;
       +
       +/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
       +typedef
       +struct Waitmsg
       +{
       +        int pid;        /* of loved one */
       +        ulong time[3];        /* of loved one & descendants */
       +        char        *msg;
       +} Waitmsg;
       +
       +typedef
       +struct IOchunk
       +{
       +        void        *addr;
       +        ulong        len;
       +} IOchunk;
       +
       +extern        void        _exits(char*);
       +
       +extern        void        abort(void);
       +extern        int        p9access(char*, int);
       +extern        long        p9alarm(ulong);
       +extern        int        await(char*, int);
       +extern        int        awaitnohang(char*, int);
       +/* extern        int        bind(char*, char*, int); give up */
       +/* extern        int        brk(void*); <unistd.h> */
       +extern        int        p9chdir(char*);
       +extern        int        close(int);
       +extern        int        p9create(char*, int, ulong);
       +extern        int        p9dup(int, int);
       +extern        int        errstr(char*, uint);
       +extern        int        p9exec(char*, char*[]);
       +/* extern        int        execl(char*, ...); <unistd.h> */
       +/* extern        int        fork(void); <unistd.h> */
       +extern        int        p9rfork(int);
       +/* not implemented 
       +extern        int        fauth(int, char*);
       +extern        int        fstat(int, uchar*, int);
       +extern        int        fwstat(int, uchar*, int);
       +extern        int        fversion(int, int, char*, int);
       +extern        int        mount(int, int, char*, int, char*);
       +extern        int        unmount(char*, char*);
       +*/
       +extern        int        noted(int);
       +extern        int        notify(void(*)(void*, char*));
       +extern        int        p9open(char*, int);
       +extern        int        fd2path(int, char*, int);
       +extern        int        p9pipe(int*);
       +/* 
       + * use defs from <unistd.h>
       +extern        long        pread(int, void*, long, vlong);
       +extern        long        preadv(int, IOchunk*, int, vlong);
       +extern        long        pwrite(int, void*, long, vlong);
       +extern        long        pwritev(int, IOchunk*, int, vlong);
       +extern        long        read(int, void*, long);
       + */
       +extern        long        readn(int, void*, long);
       +/* extern        long        readv(int, IOchunk*, int); <unistd.h> */
       +extern        int        remove(const char*);
       +/* extern        void*        sbrk(ulong); <unistd.h> */
       +/* extern        long        oseek(int, long, int); */
       +extern        vlong        p9seek(int, vlong, int);
       +/* give up
       +extern        long        segattach(int, char*, void*, ulong);
       +extern        int        segbrk(void*, void*);
       +extern        int        segdetach(void*);
       +extern        int        segflush(void*, ulong);
       +extern        int        segfree(void*, ulong);
       +*/
       +extern        int        p9sleep(long);
       +/* extern        int        stat(char*, uchar*, int); give up */
       +extern        Waitmsg*        p9wait(void);
       +extern        Waitmsg*        waitnohang(void);
       +extern        int        p9waitpid(void);
       +/* <unistd.h>
       +extern        long        write(int, void*, long);
       +extern        long        writev(int, IOchunk*, int);
       +*/
       +/* extern        int        wstat(char*, uchar*, int); give up */
       +extern        ulong        rendezvous(ulong, ulong);
       +
       +#ifndef NOPLAN9DEFINES
       +#define alarm                p9alarm
       +#define        dup                p9dup
       +#define        exec                p9exec
       +#define        seek                p9seek
       +#define sleep                p9sleep
       +#define wait                p9wait
       +#define waitpid                p9waitpid
       +#define rfork                p9rfork
       +#define access                p9access
       +#define create                p9create
       +#define open                p9open
       +#define pipe                p9pipe
       +#endif
       +
       +extern        Dir*        dirstat(char*);
       +extern        Dir*        dirfstat(int);
       +extern        int        dirwstat(char*, Dir*);
       +extern        int        dirfwstat(int, Dir*);
       +extern        long        dirread(int, Dir**);
       +extern        void        nulldir(Dir*);
       +extern        long        dirreadall(int, Dir**);
       +/* extern        int        getpid(void); <unistd.h> */
       +/* extern        int        getppid(void); */
       +extern        void        rerrstr(char*, uint);
       +extern        char*        sysname(void);
       +extern        void        werrstr(char*, ...);
       +extern        char*        getns(void);
       +extern        char*        get9root(void);
       +extern        char*        unsharp(char*);
       +extern        int        sendfd(int, int);
       +extern        int        recvfd(int);
       +extern        int        post9pservice(int, char*);
       +
       +/* external names that we don't want to step on */
       +#ifndef NOPLAN9DEFINES
       +#define main        p9main
       +#endif
       +
       +/* compiler directives on plan 9 */
       +#define        USED(x)        if(x){}else{}
       +#define        SET(x)        ((x)=0)
       +
       +/* command line */
       +extern char        *argv0;
       +extern void __fixargv0(void);
       +#define        ARGBEGIN        for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
       +                            argv[0] && argv[0][0]=='-' && argv[0][1];\
       +                            argc--, argv++) {\
       +                                char *_args, *_argt;\
       +                                Rune _argc;\
       +                                _args = &argv[0][1];\
       +                                if(_args[0]=='-' && _args[1]==0){\
       +                                        argc--; argv++; break;\
       +                                }\
       +                                _argc = 0;\
       +                                while(*_args && (_args += chartorune(&_argc, _args)))\
       +                                switch(_argc)
       +#define        ARGEND                SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
       +#define        ARGF()                (_argt=_args, _args="",\
       +                                (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
       +#define        EARGF(x)        (_argt=_args, _args="",\
       +                                (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
       +
       +#define        ARGC()                _argc
       +
       +#if defined(__cplusplus)
       +}
       +#endif
       +#endif        /* _LIB9_H_ */
 (DIR) diff --git a/include/u.h b/include/u.h
       t@@ -0,0 +1,93 @@
       +#ifndef _U_H_
       +#define _U_H_ 1
       +#if defined(__cplusplus)
       +extern "C" {
       +#endif
       +
       +#define _BSD_SOURCE 1
       +#define _SVID_SOURCE 1
       +#define _XOPEN_SOURCE 1000
       +#define _XOPEN_SOURCE_EXTENDED 1
       +#define _LARGEFILE64_SOURCE 1
       +#define _FILE_OFFSET_BITS 64
       +#define __EXTENSIONS__ 1 /* SunOS */
       +
       +#include <unistd.h>
       +#include <string.h>
       +#include <stdlib.h>
       +#include <stdarg.h>
       +#include <fcntl.h>
       +#include <assert.h>
       +#include <setjmp.h>
       +#include <stddef.h>
       +#include <utf.h>
       +#include <fmt.h>
       +#include <math.h>
       +
       +/*
       + * OS-specific crap
       + */
       +#define _NEEDUCHAR 1
       +#define _NEEDUSHORT 1
       +#define _NEEDUINT 1
       +#define _NEEDULONG 1
       +
       +typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
       +
       +#if defined(__linux__)
       +#        include <sys/types.h>
       +#        if defined(__USE_MISC)
       +#                undef _NEEDUSHORT
       +#                undef _NEEDUINT
       +#                undef _NEEDULONG
       +#        endif
       +#endif
       +#if defined(__sun__)
       +#        include <sys/types.h>
       +#        undef _NEEDUSHORT
       +#        undef _NEEDUINT
       +#        undef _NEEDULONG
       +#endif
       +#if defined(__FreeBSD__)
       +#        include <sys/types.h>
       +#        if !defined(_POSIX_SOURCE)
       +#                undef _NEEDUSHORT
       +#                undef _NEEDUINT
       +#        endif
       +#endif
       +#if defined(__APPLE__)
       +#        include <sys/types.h>
       +#        undef _NEEDUSHORT
       +#        undef _NEEDUINT
       +#        define _NEEDLL 1
       +#endif
       +
       +typedef signed char schar;
       +typedef unsigned int u32int;
       +#ifdef _NEEDUCHAR
       +        typedef unsigned char uchar;
       +#endif
       +#ifdef _NEEDUSHORT
       +        typedef unsigned short ushort;
       +#endif
       +#ifdef _NEEDUINT
       +        typedef unsigned int uint;
       +#endif
       +#ifdef _NEEDULONG
       +        typedef unsigned long ulong;
       +#endif
       +typedef unsigned long long uvlong;
       +typedef long long vlong;
       +typedef uvlong u64int;
       +typedef uchar u8int;
       +typedef ushort u16int;
       +
       +#undef _NEEDUCHAR
       +#undef _NEEDUSHORT
       +#undef _NEEDUINT
       +#undef _NEEDULONG
       +
       +#if defined(__cplusplus)
       +}
       +#endif
       +#endif
 (DIR) diff --git a/src/cmd/9pserve.c b/src/cmd/9pserve.c
       t@@ -1150,7 +1150,7 @@ rewritehdr(Fcall *f, uchar *pkt)
                }
        }
        
       -#ifdef _LIB9_H_
       +#ifdef _LIBC_H_
        /* unix select-based polling */
        struct Ioproc
        {
 (DIR) diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
       t@@ -1,15 +1,24 @@
       -#include "9term.h"
       -
       -#define fatal        sysfatal
       +#include <u.h>
       +#include <libc.h>
       +#include <ctype.h>
       +#include <draw.h>
       +#include <thread.h>
       +#include <mouse.h>
       +#include <cursor.h>
       +#include <keyboard.h>
       +#include <frame.h>
       +#include <plumb.h>
       +#include <complete.h>
       +#include "term.h"
        
        typedef struct Text        Text;
        typedef struct Readbuf        Readbuf;
        
        enum
        {
       -        /* these are chosen to use malloc()'s properties well */
                HiWater        = 640000,        /* max size of history */
       -        LoWater        = 330000,        /* min size of history after max'ed */
       +        LoWater        = 400000,        /* min size of history after max'ed */
       +        MinWater        = 20000,
        };
        
        /* various geometric paramters */
       t@@ -30,21 +39,22 @@ enum
                Scroll,
        };
        
       -
       -#define        SCROLLKEY        Kdown
        #define        ESC                0x1B
       -#define CUT                0x18        /* ctrl-x */                
       -#define COPY                0x03        /* crtl-c */
       -#define PASTE                0x16        /* crtl-v */
       -#define BACKSCROLLKEY        Kup
       +#define        CUT                0x18        /* ctrl-x */                
       +#define        COPY                0x03        /* crtl-c */
       +#define        PASTE                0x16        /* crtl-v */
        
        #define        READBUFSIZE 8192
       +#define TRUE 1
       +#define FALSE 0
       +
        
        struct Text
        {
                Frame                *f;                /* frame ofr terminal */
                Mouse                m;
                uint                nr;                /* num of runes in term */
       +        uint                maxr;        /* max num of runes in r */
                Rune                *r;                /* runes for term */
                uint                nraw;                /* num of runes in raw buffer */
                Rune                *raw;                /* raw buffer */
       t@@ -72,7 +82,6 @@ void        fill(void);
        void        tcheck(void);
        void        updatesel(void);
        void        doreshape(void);
       -void        rcstart(int fd[2], int, char**);
        void        runewrite(Rune*, int);
        void        consread(void);
        void        conswrite(char*, int);
       t@@ -99,11 +108,10 @@ void        scrdraw(void);
        void        scroll(int);
        void        hostproc(void *arg);
        void        hoststart(void);
       -int        getchildwd(int, char*, int);
        void        plumbstart(void);
        void        plumb(uint, uint);
        void        plumbclick(uint*, uint*);
       -int        getpts(int fd[], char *slave);
       +uint        insert(Rune*, int, uint, int);
        
        #define        runemalloc(n)                malloc((n)*sizeof(Rune))
        #define        runerealloc(a, n)        realloc(a, (n)*sizeof(Rune))
       t@@ -115,7 +123,7 @@ int                rawon;                /* raw mode */
        int                scrolling;        /* window scrolls */
        int                clickmsec;        /* time of last click */
        uint                clickq0;        /* point of last click */
       -int                rcfd[2];
       +int                rcfd;
        int                rcpid;
        int                maxtab;
        int                use9wm;
       t@@ -211,7 +219,7 @@ threadmain(int argc, char *argv[])
        
                mc = initmouse(nil, screen);
                kc = initkeyboard(nil);
       -        rcstart(rcfd, argc, argv);
       +        rcpid = rcstart(argc, argv, &rcfd);
                hoststart();
                plumbstart();
        
       t@@ -265,8 +273,9 @@ hostproc(void *arg)
        
                i = 0;
                for(;;){
       +                /* Let typing have a go -- maybe there's a rubout waiting. */
                        i = 1-i;        /* toggle */
       -                n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
       +                n = threadread(rcfd, rcbuf[i].data, sizeof rcbuf[i].data);
                        if(n <= 0){
                                if(n < 0)
                                        fprint(2, "9term: host read error: %r\n");
       t@@ -308,7 +317,7 @@ loop(void)
                                a[2].op = CHANNOP;;
                        switch(alt(a)) {
                        default:
       -                        fatal("impossible");
       +                        sysfatal("impossible");
                        case 0:
                                t.m = mc->m;
                                mouse();
       t@@ -330,23 +339,23 @@ void
        doreshape(void)
        {
                if(getwindow(display, Refnone) < 0)
       -                fatal("can't reattach to window");
       +                sysfatal("can't reattach to window");
                draw(screen, screen->r, cols[BACK], nil, ZP);
                geom();
                scrdraw();
        }
        
       -struct winsize ows;
       -
        void
        geom(void)
        {
       -        struct winsize ws;
                Point p;
                Rectangle r;
        
                r = screen->r;
       -        scrollr = screen->r;
       +        r.min.y++;
       +        r.max.y--;
       +
       +        scrollr = r;
                scrollr.max.x = r.min.x+Scrollwid;
                lastsr = Rect(0,0,0,0);
        
       t@@ -362,13 +371,7 @@ geom(void)
                if(p.x == 0 || p.y == 0)
                        return;
        
       -        ws.ws_row = Dy(r)/p.y;
       -        ws.ws_col = Dx(r)/p.x;
       -        ws.ws_xpixel = Dx(r);
       -        ws.ws_ypixel = Dy(r);
       -        if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
       -        if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
       -                fprint(2, "ioctl: %r\n");
       +        updatewinsize(Dy(r)/p.y, Dx(r)/p.x, Dx(r), Dy(r));
        }
        
        void
       t@@ -585,7 +588,10 @@ domenu2(int but)
                                show(t.q0);
                        break;
                case Send:
       -                snarf();
       +                if(t.q0 != t.q1)
       +                        snarf();
       +                else
       +                        snarfupdate();
                        t.q0 = t.q1 = t.nr;
                        updatesel();
                        paste(t.snarf, t.nsnarf, 1);
       t@@ -605,37 +611,182 @@ domenu2(int but)
                        plumb(t.q0, t.q1);
                        break;
                default:
       -                fatal("bad menu item");
       +                sysfatal("bad menu item");
       +        }
       +}
       +
       +int
       +windfilewidth(uint q0, int oneelement)
       +{
       +        uint q;
       +        Rune r;
       +
       +        q = q0;
       +        while(q > 0){
       +                r = t.r[q-1];
       +                if(r<=' ')
       +                        break;
       +                if(oneelement && r=='/')
       +                        break;
       +                --q;
       +        }
       +        return q0-q;
       +}
       +
       +void
       +showcandidates(Completion *c)
       +{
       +        int i;
       +        Fmt f;
       +        Rune *rp;
       +        uint nr, qline, q0;
       +        char *s;
       +
       +        runefmtstrinit(&f);
       +        if (c->nmatch == 0)
       +                s = "[no matches in ";
       +        else
       +                s = "[";
       +        if(c->nfile > 32)
       +                fmtprint(&f, "%s%d files]\n", s, c->nfile);
       +        else{
       +                fmtprint(&f, "%s", s);
       +                for(i=0; i<c->nfile; i++){
       +                        if(i > 0)
       +                                fmtprint(&f, " ");
       +                        fmtprint(&f, "%s", c->filename[i]);
       +                }
       +                fmtprint(&f, "]\n");
       +        }
       +        /* place text at beginning of line before host point */
       +        qline = t.qh;
       +        while(qline>0 && t.r[qline-1] != '\n')
       +                qline--;
       +
       +        rp = runefmtstrflush(&f);
       +        nr = runestrlen(rp);
       +
       +        q0 = t.q0;
       +        q0 += insert(rp, nr, qline, 0) - qline;
       +        free(rp);
       +        t.q0 = q0+nr;
       +        t.q1 = q0+nr;
       +        updatesel();
       +}
       +
       +Rune*
       +namecomplete(void)
       +{
       +        int nstr, npath;
       +        Rune *rp, *path, *str;
       +        Completion *c;
       +        char *s, *dir, *root;
       +
       +        /* control-f: filename completion; works back to white space or / */
       +        if(t.q0<t.nr && t.r[t.q0]>' ')        /* must be at end of word */
       +                return nil;
       +        nstr = windfilewidth(t.q0, TRUE);
       +        str = runemalloc(nstr);
       +        runemove(str, t.r+(t.q0-nstr), nstr);
       +        npath = windfilewidth(t.q0-nstr, FALSE);
       +        path = runemalloc(npath);
       +        runemove(path, t.r+(t.q0-nstr-npath), npath);
       +        rp = nil;
       +
       +        /* is path rooted? if not, we need to make it relative to window path */
       +        if(npath>0 && path[0]=='/'){
       +                dir = malloc(UTFmax*npath+1);
       +                sprint(dir, "%.*S", npath, path);
       +        }else{
       +                if(strcmp(wdir, "") == 0)
       +                        root = ".";
       +                else
       +                        root = wdir;
       +                dir = malloc(strlen(root)+1+UTFmax*npath+1);
       +                sprint(dir, "%s/%.*S", root, npath, path);
                }
       +        dir = cleanname(dir);
       +
       +        s = smprint("%.*S", nstr, str);
       +        c = complete(dir, s);
       +        free(s);
       +        if(c == nil)
       +                goto Return;
       +
       +        if(!c->advance)
       +                showcandidates(c);
       +
       +        if(c->advance)
       +                rp = runesmprint("%s", c->string);
       +
       +  Return:
       +        freecompletion(c);
       +        free(dir);
       +        free(path);
       +        free(str);
       +        return rp;
        }
        
        void
        key(Rune r)
        {
       -        uint sig;
       +        Rune *rp;
       +        int nr;
        
                if(r == 0)
                        return;
       -        if(r==SCROLLKEY){        /* scroll key */
       +        switch(r){
       +        case Kpgup:
       +                setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
       +                return;
       +        case Kpgdown:
                        setorigin(line2q(t.f->maxlines*2/3), 1);
                        if(t.qh<=t.org+t.f->nchars)
                                consread();
                        return;
       -        }else if(r == BACKSCROLLKEY){
       -                setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
       +        case Kup:
       +                setorigin(backnl(t.org, t.f->maxlines/3), 1);
       +                return;
       +        case Kdown:
       +                setorigin(line2q(t.f->maxlines/3), 1);
       +                if(t.qh<=t.org+t.f->nchars)
       +                        consread();
                        return;
       -        }else if(r == CUT){
       +        case Kleft:
       +                if(t.q0 > 0){
       +                        t.q0--;
       +                        t.q1 = t.q0;
       +                        updatesel();
       +                        show(t.q0);
       +                }
       +                return;
       +        case Kright:
       +                if(t.q1 < t.nr){
       +                        t.q1++;
       +                        t.q0 = t.q1;
       +                        updatesel();
       +                        show(t.q1);
       +                }
       +                return;
       +        case Khome:
       +                show(0);
       +                return;
       +        case Kend:
       +        case 0x05:
       +                show(t.nr);
       +                return;
       +        case CUT:
                        snarf();
                        cut();
                        if(scrolling)
                                show(t.q0);
                        return;
       -        }else if(r == COPY){
       +        case COPY:
                        snarf();
                        if(scrolling)
                                show(t.q0);
                        return;
       -        }else if(r == PASTE){
       +        case PASTE:
                        snarfupdate();
                        paste(t.snarf, t.nsnarf, 0);
                        if(scrolling)
       t@@ -661,19 +812,21 @@ key(Rune r)
                snarf();
        
                switch(r) {
       +        case 0x03:        /* ^C: send interrupt */
                case 0x7F:        /* DEL: send interrupt */
                        t.qh = t.q0 = t.q1 = t.nr;
                        show(t.q0);
       -                goto Default;
       -fprint(2, "send interrupt to %d group\n", rcpid);
       -#ifdef TIOCSIG
       -                sig = 2; /* SIGINT */
       -                if(ioctl(rcfd[0], TIOCSIG, &sig) < 0)
       -                        fprint(2, "sending interrupt: %r\n");
       -#else
       -                postnote(PNGROUP, rcpid, "interrupt");
       -#endif
       +                write(rcfd, "\x7F", 1);
                        break;
       +        case 0x06:        /* ^F: file name completion */
       +        case Kins:                /* Insert: file name completion */
       +                rp = namecomplete();
       +                if(rp == nil)
       +                        return;
       +                nr = runestrlen(rp);
       +                paste(rp, nr, 1);
       +                free(rp);
       +                return;
                case 0x08:        /* ^H: erase character */
                case 0x15:        /* ^U: erase line */
                case 0x17:        /* ^W: erase word */
       t@@ -682,7 +835,6 @@ fprint(2, "send interrupt to %d group\n", rcpid);
                        cut();
                        break;
                default:
       -        Default:
                        paste(&r, 1, 1);
                        break;
                }
       t@@ -773,7 +925,7 @@ consread(void)
                        }
                        /* take out control-d when not doing a zero length write */
                        n = p-buf;
       -                if(write(rcfd[1], buf, n) < 0)
       +                if(write(rcfd, buf, n) < 0)
                                exits(0);
        /*                mallocstats(); */
                }
       t@@ -833,7 +985,6 @@ conswrite(char *p, int n)
        void
        runewrite(Rune *r, int n)
        {
       -        uint m;
                int i;
                uint initial;
                uint q0, q1;
       t@@ -896,37 +1047,7 @@ runewrite(Rune *r, int n)
                        updatesel();
                }
        
       -        if(t.nr>HiWater && t.qh>=t.org){
       -                m = HiWater-LoWater;
       -                if(m > t.org);
       -                        m = t.org;
       -                t.org -= m;
       -                t.qh -= m;
       -                if(t.q0 > m)
       -                        t.q0 -= m;
       -                else
       -                        t.q0 = 0;
       -                if(t.q1 > m)
       -                        t.q1 -= m;
       -                else
       -                        t.q1 = 0;
       -                t.nr -= m;
       -                runemove(t.r, t.r+m, t.nr);
       -        }
       -        t.r = runerealloc(t.r, t.nr+n);
       -        runemove(t.r+t.qh+n, t.r+t.qh, t.nr-t.qh);
       -        runemove(t.r+t.qh, r, n);
       -        t.nr += n;
       -        if(t.qh < t.org)
       -                t.org += n;
       -        else if(t.qh <= t.f->nchars+t.org)
       -                frinsert(t.f, r, r+n, t.qh-t.org);
       -        if (t.qh <= t.q0)
       -                t.q0 += n;
       -        if (t.qh <= t.q1)
       -                t.q1 += n;
       -        t.qh += n;
       -        updatesel();
       +        insert(r, n, t.qh, 1);
        }
        
        
       t@@ -1009,12 +1130,83 @@ snarf(void)
                putsnarf(sbuf);
        }
        
       +uint
       +min(uint x, uint y)
       +{
       +        if(x < y)
       +                return x;
       +        return y;
       +}
       +
       +uint
       +max(uint x, uint y)
       +{
       +        if(x > y)
       +                return x;
       +        return y;
       +}
       +
       +uint
       +insert(Rune *r, int n, uint q0, int hostwrite)
       +{
       +        uint m;
       +
       +        if(n == 0)
       +                return q0;
       +        if(t.nr+n>HiWater && q0>=t.org && q0>=t.qh){
       +                m = min(HiWater-LoWater, min(t.org, t.qh));
       +                t.org -= m;
       +                t.qh -= m;
       +                if(t.q0 > m)
       +                        t.q0 -= m;
       +                else
       +                        t.q0 = 0;
       +                if(t.q1 > m)
       +                        t.q1 -= m;
       +                else
       +                        t.q1 = 0;
       +                t.nr -= m;
       +                runemove(t.r, t.r+m, t.nr);
       +                q0 -= m;
       +        }
       +        if(t.nr+n > t.maxr){
       +                /*
       +                 * Minimize realloc breakage:
       +                 *        Allocate at least MinWater
       +                 *         Double allocation size each time
       +                 *        But don't go much above HiWater
       +                 */
       +                m = max(min(2*(t.nr+n), HiWater), t.nr+n)+MinWater;
       +                if(m > HiWater)
       +                        m = max(HiWater+MinWater, t.nr+n);
       +                if(m > t.maxr){
       +                        t.r = runerealloc(t.r, m);
       +                        t.maxr = m;
       +                }
       +        }
       +        runemove(t.r+q0+n, t.r+q0, t.nr-q0);
       +        runemove(t.r+q0, r, n);
       +        t.nr += n;
       +        /* if output touches, advance selection, not qh; works best for keyboard and output */
       +        if(q0 <= t.q1)
       +                t.q1 += n;
       +        if(q0 <= t.q0)
       +                t.q0 += n;
       +        if(q0 < t.qh || (q0==t.qh && hostwrite))
       +                t.qh += n;
       +        else
       +                consread();
       +        if(q0 < t.org)
       +                t.org += n;
       +        else if(q0 <= t.org+t.f->nchars)
       +                frinsert(t.f, r, r+n, q0-t.org);
       +        return q0;
       +}
       +
        void
        paste(Rune *r, int n, int advance)
        {
                Rune *rbuf;
       -        uint m;
       -        uint q0;
        
                if(rawon && t.q0==t.nr){
                        addraw(r, n);
       t@@ -1024,6 +1216,7 @@ paste(Rune *r, int n, int advance)
                cut();
                if(n == 0)
                        return;
       +
                /*
                 * if this is a button2 execute then we might have been passed
                 * runes inside the buffer.  must save them before realloc.
       t@@ -1035,36 +1228,7 @@ paste(Rune *r, int n, int advance)
                        r = rbuf;
                }
        
       -        if(t.nr>HiWater && t.q0>=t.org && t.q0>=t.qh){
       -                m = HiWater-LoWater;
       -                if(m > t.org)
       -                        m = t.org;
       -                if(m > t.qh);
       -                        m = t.qh;
       -                t.org -= m;
       -                t.qh -= m;
       -                t.q0 -= m;
       -                t.q1 -= m;
       -                t.nr -= m;
       -                runemove(t.r, t.r+m, t.nr);
       -        }
       -
       -        t.r = runerealloc(t.r, t.nr+n);
       -        q0 = t.q0;
       -        runemove(t.r+q0+n, t.r+q0, t.nr-q0);
       -        runemove(t.r+q0, r, n);
       -        t.nr += n;
       -        if(q0 < t.qh)
       -                t.qh += n;
       -        else
       -                consread();
       -        if(q0 < t.org)
       -                t.org += n;
       -        else if(q0 <= t.f->nchars+t.org)
       -                frinsert(t.f, r, r+n, q0-t.org);
       -        if(advance)
       -                t.q0 += n;
       -        t.q1 += n;
       +        insert(r, n, t.q0, 0);
                updatesel();
                free(rbuf);
        }
       t@@ -1322,61 +1486,6 @@ clickmatch(int cl, int cr, int dir, uint *q)
        }
        
        void
       -rcstart(int fd[2], int argc, char **argv)
       -{
       -        int pid;
       -        char *xargv[3];
       -        char slave[256];
       -        int sfd;
       -
       -        if(argc == 0){
       -                argc = 2;
       -                argv = xargv;
       -                argv[0] = getenv("SHELL");
       -                if(argv[0] == 0)
       -                        argv[0] = "rc";
       -                argv[1] = "-i";
       -                argv[2] = 0;
       -        }
       -        /*
       -         * fd0 is slave (tty), fd1 is master (pty)
       -         */
       -        fd[0] = fd[1] = -1;
       -        if(getpts(fd, slave) < 0)
       -                fprint(2, "getpts: %r\n");
       -
       -        switch(pid = fork()) {
       -        case 0:
       -                putenv("TERM", "9term");
       -                close(fd[1]);
       -                setsid();
       -//                tcsetpgrp(0, pid);
       -                sfd = open(slave, ORDWR);
       -                if(sfd < 0)
       -                        fprint(2, "open %s: %r\n", slave);
       -                if(ioctl(sfd, TIOCSCTTY, 0) < 0)
       -                        fprint(2, "ioctl TIOCSCTTY: %r\n");
       -//                ioctl(sfd, I_PUSH, "ptem");
       -//                ioctl(sfd, I_PUSH, "ldterm");
       -                dup(sfd, 0);
       -                dup(sfd, 1);
       -                dup(sfd, 2);
       -                system("stty tabs -onlcr -echo erase ^h intr ^?");
       -                execvp(argv[0], argv);
       -                fprint(2, "exec %s failed: %r\n", argv[0]);
       -                _exits("oops");
       -                break;
       -        case -1:
       -                fatal("proc failed: %r");
       -                break;
       -        }
       -        close(fd[0]);
       -        fd[0] = fd[1];
       -
       -        rcpid = pid;
       -}
       -
       -void
        tcheck(void)
        {
                Frame *f;
       t@@ -1421,7 +1530,7 @@ scrdraw(void)
                                freeimage(scrx);
                        scrx = allocimage(display, Rect(0, 0, 32, r.max.y), screen->chan, 1, DPaleyellow);
                        if(scrx == 0)
       -                        fatal("scroll balloc");
       +                        sysfatal("scroll balloc");
                }
                r1.min.x = 0;
                r1.max.x = Dx(r);
       t@@ -1525,16 +1634,11 @@ plumb(uint q0, uint q1)
                char *p;
                int i, p0, n;
                char cbuf[100];
       -        char *w;
        
       -        if(getchildwd(rcpid, childwdir, sizeof childwdir) == 0)
       -                w = childwdir;
       -        else
       -                w = wdir;
                pm = malloc(sizeof(Plumbmsg));
                pm->src = strdup("9term");
                pm->dst = 0;
       -        pm->wdir = strdup(w);
       +        pm->wdir = strdup(wdir);
                pm->type = strdup("text");
                pm->data = nil;
                if(q1 > q0)
 (DIR) diff --git a/src/cmd/9term/9term.h b/src/cmd/9term/9term.h
       t@@ -1,19 +1,4 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <ctype.h>
       -#include <draw.h>
       -#include <thread.h>
       -#include <mouse.h>
       -#include <cursor.h>
       -#include <keyboard.h>
       -#include <frame.h>
       -#include <plumb.h>
       -#include <termios.h>
       -#include <sys/termios.h>
       -#ifdef __linux__
       -#include <pty.h>
       -#endif
       -
       -extern int getchildwd(int, char*, int);
        extern int getpts(int[], char*);
       -
       +extern int childpty(int[], char*);
       +extern void updatewinsize(int, int, int, int);
       +extern int rcfd[];
 (DIR) diff --git a/src/cmd/9term/FreeBSD.c b/src/cmd/9term/FreeBSD.c
       t@@ -1,17 +1,43 @@
        #include "9term.h"
       +#include <termios.h>
       +#include <sys/termios.h>
        #include <libutil.h>
        
        int
       -getchildwd(int pid, char *wdir, int bufn)
       +getpts(int fd[], char *slave)
        {
       -        USED(pid);
       -        USED(wdir);
       -        USED(bufn);
       -        return -1;
       +        return openpty(&fd[1], &fd[0], slave, 0, 0);
        }
        
        int
       -getpts(int fd[], char *slave)
       +childpty(int fd[], char *slave)
        {
       -        return openpty(&fd[1], &fd[0], slave, 0, 0);
       +        int sfd;
       +
       +        close(fd[1]);
       +        setsid();
       +        sfd = open(slave, ORDWR);
       +        if(sfd < 0)
       +                sysfatal("open %s: %r\n", slave);
       +        if(ioctl(sfd, TIOCSCTTY, 0) < 0)
       +                fprint(2, "ioctl TIOCSCTTY: %r\n");
       +        return sfd;
        }
       +
       +struct winsize ows;
       +
       +void
       +updatewinsize(int row, int col, int dx, int dy)
       +{
       +        struct winsize ws;
       +
       +        ws.ws_row = row;
       +        ws.ws_col = col;
       +        ws.ws_xpixel = dx;
       +        ws.ws_ypixel = dy;
       +        if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
       +        if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
       +                fprint(2, "ioctl: %r\n");
       +        ows = ws;
       +}
       +
 (DIR) diff --git a/src/cmd/9term/Linux.c b/src/cmd/9term/Linux.c
       t@@ -1,22 +1,46 @@
       +#include <u.h>
       +#include <termios.h>
       +#include <sys/termios.h>
       +#include <pty.h>
       +#include <libc.h>
        #include "9term.h"
        
        int
       -getchildwd(int pid, char *wdir, int bufn)
       +getpts(int fd[], char *slave)
        {
       -        char path[256];
       -        int n;
       -
       -        snprint(path, sizeof path, "/proc/%d/cwd", pid);
       -        n = readlink(path, wdir, bufn);
       -        if(n < 0)
       -                return -1;
       -        wdir[n] = '\0';
       +        openpty(&fd[1], &fd[0], slave, 0, 0);
                return 0;
        }
        
        int
       -getpts(int fd[], char *slave)
       +childpty(int fd[], char *slave)
        {
       -        openpty(&fd[1], &fd[0], slave, 0, 0);
       -        return 0;
       +        int sfd;
       +
       +        close(fd[1]);
       +        setsid();
       +        sfd = open(slave, ORDWR);
       +        if(sfd < 0)
       +                sysfatal("open %s: %r\n", slave);
       +        if(ioctl(sfd, TIOCSCTTY, 0) < 0)
       +                fprint(2, "ioctl TIOCSCTTY: %r\n");
       +        return sfd;
        }
       +
       +struct winsize ows;
       +
       +void
       +updatewinsize(int row, int col, int dx, int dy)
       +{
       +        struct winsize ws;
       +
       +        ws.ws_row = row;
       +        ws.ws_col = col;
       +        ws.ws_xpixel = dx;
       +        ws.ws_ypixel = dy;
       +        if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
       +        if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
       +                fprint(2, "ioctl: %r\n");
       +        ows = ws;
       +}
       +
 (DIR) diff --git a/src/cmd/9term/SunOS.c b/src/cmd/9term/SunOS.c
       t@@ -1,21 +1,6 @@
        #include "9term.h"
       -
       -int
       -getchildwd(int pid, char *wdir, int bufn)
       -{
       -        char path[256];
       -        char cwd[256];
       -
       -        if(getcwd(cwd, sizeof cwd) < 0)
       -                return -1;
       -        snprint(path, sizeof path, "/proc/%d/cwd", pid);
       -        if(chdir(path) < 0)
       -                return -1;
       -        if(getcwd(wdir, bufn) < 0)
       -                return -1;
       -        chdir(cwd);
       -        return 0;
       -}
       +#include <termios.h>
       +#include <sys/termios.h>
        
        int
        getpts(int fd[], char *slave)
       t@@ -28,3 +13,21 @@ getpts(int fd[], char *slave)
                fd[0] = open(slave, OREAD);
                return 0;
        }
       +
       +struct winsize ows;
       +
       +void
       +updatewinsize(int row, int col, int dx, int dy)
       +{
       +        struct winsize ws;
       +
       +        ws.ws_row = row;
       +        ws.ws_col = col;
       +        ws.ws_xpixel = dx;
       +        ws.ws_ypixel = dy;
       +        if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
       +        if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
       +                fprint(2, "ioctl: %r\n");
       +        ows = ws;
       +}
       +
 (DIR) diff --git a/src/cmd/9term/mkfile b/src/cmd/9term/mkfile
       t@@ -1,15 +1,15 @@
        PLAN9=../../..
        <$PLAN9/src/mkhdr
        
       -TARG=9term
       +TARG=9term win
        
        OFILES=\
       -        9term.$O\
       +        rcstart.$O\
                $SYSNAME.$O\
        
       -SHORTLIB=frame draw plumb fs mux thread 9
       +SHORTLIB=complete frame draw plumb fs mux thread 9
        
       -<$PLAN9/src/mkone
       +<$PLAN9/src/mkmany
        
        LDFLAGS=-L$X11/lib -lX11 -lutil
        
 (DIR) diff --git a/src/cmd/9term/rcstart.c b/src/cmd/9term/rcstart.c
       t@@ -0,0 +1,51 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "term.h"
       +
       +int
       +rcstart(int argc, char **argv, int *pfd)
       +{
       +        int pid;
       +        int fd[2];
       +        char *xargv[3];
       +        char slave[256];
       +        int sfd;
       +
       +        if(argc == 0){
       +                argc = 2;
       +                argv = xargv;
       +                argv[0] = getenv("SHELL");
       +                if(argv[0] == 0)
       +                        argv[0] = "rc";
       +                argv[1] = "-i";
       +                argv[2] = 0;
       +        }
       +        /*
       +         * fd0 is slave (tty), fd1 is master (pty)
       +         */
       +        fd[0] = fd[1] = -1;
       +        if(getpts(fd, slave) < 0)
       +                fprint(2, "getpts: %r\n");
       +
       +
       +        switch(pid = fork()) {
       +        case 0:
       +                putenv("TERM", "9term");
       +                sfd = childpty(fd, slave);
       +                dup(sfd, 0);
       +                dup(sfd, 1);
       +                dup(sfd, 2);
       +                system("stty tabs -onlcr -echo erase ^h intr ^?");
       +                execvp(argv[0], argv);
       +                fprint(2, "exec %s failed: %r\n", argv[0]);
       +                _exits("oops");
       +                break;
       +        case -1:
       +                sysfatal("proc failed: %r");
       +                break;
       +        }
       +        close(fd[0]);
       +        *pfd = fd[1];
       +        return pid;
       +}
       +
 (DIR) diff --git a/src/cmd/9term/term.h b/src/cmd/9term/term.h
       t@@ -0,0 +1,5 @@
       +extern int getpts(int[], char*);
       +extern int childpty(int[], char*);
       +extern void updatewinsize(int, int, int, int);
       +extern int rcfd;
       +extern int rcstart(int, char*[], int*);
 (DIR) diff --git a/src/cmd/9term/win.c b/src/cmd/9term/win.c
       t@@ -0,0 +1,693 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <thread.h>
       +#include <fcall.h>
       +#include <fs.h>
       +#include "term.h"
       +
       +#define        EVENTSIZE        256
       +#define        STACK        32768
       +
       +typedef struct Event Event;
       +typedef struct Q Q;
       +
       +struct Event
       +{
       +        int        c1;
       +        int        c2;
       +        int        q0;
       +        int        q1;
       +        int        flag;
       +        int        nb;
       +        int        nr;
       +        char        b[EVENTSIZE*UTFmax+1];
       +        Rune        r[EVENTSIZE+1];
       +};
       +
       +Event blank = {
       +        'M',
       +        'X',
       +        0, 0, 0, 1, 1,
       +        { ' ', 0 },
       +        { ' ', 0 },
       +};
       +
       +struct Q
       +{
       +        QLock        lk;
       +        int                p;
       +        int                k;
       +};
       +
       +Q        q;
       +
       +Fid *eventfd;
       +Fid *addrfd;
       +Fid *datafd;
       +Fid *ctlfd;
       +// int bodyfd;
       +
       +char        *typing;
       +int        ntypeb;
       +int        ntyper;
       +int        ntypebreak;
       +int        debug;
       +int        rcfd;
       +
       +char *name;
       +
       +char **prog;
       +Channel *cwait;
       +int pid = -1;
       +
       +int        label(char*, int);
       +void        error(char*);
       +void        stdinproc(void*);
       +void        stdoutproc(void*);
       +void        type(Event*, int, Fid*, Fid*);
       +void        sende(Event*, int, Fid*, Fid*, Fid*, int);
       +char        *onestring(int, char**);
       +int        delete(Event*);
       +void        deltype(uint, uint);
       +void        runproc(void*);
       +
       +int
       +fsfidprint(Fid *fid, char *fmt, ...)
       +{
       +        char buf[256];
       +        va_list arg;
       +        int n;
       +
       +        va_start(arg, fmt);
       +        n = vsnprint(buf, sizeof buf, fmt, arg);
       +        va_end(arg);
       +        return fswrite(fid, buf, n);
       +}
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: win cmd args...\n");
       +        threadexitsall("usage");
       +}
       +
       +int
       +nopipes(void *v, char *msg)
       +{
       +        USED(v);
       +        if(strcmp(msg, "sys: write on closed pipe") == 0)
       +                return 1;
       +        return 0;
       +}
       +
       +void
       +waitthread(void *v)
       +{
       +        recvp(cwait);
       +        threadexitsall(nil);
       +}
       +
       +void
       +threadmain(int argc, char **argv)
       +{
       +        int fd, id;
       +        char buf[256];
       +        char buf1[128];
       +        Fsys *fs;
       +
       +        ARGBEGIN{
       +        case 'd':
       +                debug = 1;
       +                break;
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        prog = argv;
       +
       +        if(argc > 0){
       +                name = argv[0];
       +                argc--;
       +                argv++;
       +        }else
       +                name = "gnot";
       +
       +        threadnotify(nopipes, 1);
       +        if((fs = nsmount("acme", "")) < 0)
       +                sysfatal("nsmount acme: %r");
       +        ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
       +        if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
       +                sysfatal("ctl: %r");
       +        id = atoi(buf);
       +        sprint(buf, "%d/tag", id);
       +        fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
       +        write(fd, " Send Delete", 12);
       +        close(fd);
       +        sprint(buf, "%d/event", id);
       +        eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
       +        sprint(buf, "%d/addr", id);
       +        addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
       +        sprint(buf, "%d/data", id);
       +        datafd = fsopen(fs, buf, ORDWR|OCEXEC);
       +        sprint(buf, "%d/body", id);
       +/*        bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
       +        if(eventfd==nil || addrfd==nil || datafd==nil)
       +                sysfatal("data files: %r");
       +/*
       +        if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
       +                sysfatal("data files: %r");
       +*/
       +        fsunmount(fs);
       +
       +        cwait = threadwaitchan();
       +        threadcreate(waitthread, nil, STACK);
       +        pid = rcstart(argc, argv, &rcfd);
       +        if(pid == -1)
       +                sysfatal("exec failed");
       +
       +        getwd(buf1, sizeof buf1);
       +        sprint(buf, "name %s/-%s\n0\n", buf1, name);
       +        fswrite(ctlfd, buf, strlen(buf));
       +        sprint(buf, "dumpdir %s/\n", buf1);
       +        fswrite(ctlfd, buf, strlen(buf));
       +        sprint(buf, "dump %s\n", onestring(argc, argv));
       +        fswrite(ctlfd, buf, strlen(buf));
       +        
       +        threadcreate(stdoutproc, nil, STACK);
       +        stdinproc(nil);
       +}
       +
       +void
       +error(char *s)
       +{
       +        if(s)
       +                fprint(2, "win: %s: %r\n", s);
       +        else
       +                s = "kill";
       +        if(pid != -1)
       +                postnote(PNGROUP, pid, "hangup");
       +        threadexitsall(s);
       +}
       +
       +char*
       +onestring(int argc, char **argv)
       +{
       +        char *p;
       +        int i, n;
       +        static char buf[1024];
       +
       +        if(argc == 0)
       +                return "";
       +        p = buf;
       +        for(i=0; i<argc; i++){
       +                n = strlen(argv[i]);
       +                if(p+n+1 >= buf+sizeof buf)
       +                        break;
       +                memmove(p, argv[i], n);
       +                p += n;
       +                *p++ = ' ';
       +        }
       +        p[-1] = 0;
       +        return buf;
       +}
       +
       +int
       +getec(Fid *efd)
       +{
       +        static char buf[8192];
       +        static char *bufp;
       +        static int nbuf;
       +
       +        if(nbuf == 0){
       +                nbuf = fsread(efd, buf, sizeof buf);
       +                if(nbuf <= 0)
       +                        error(nil);
       +                bufp = buf;
       +        }
       +        --nbuf;
       +        return *bufp++;
       +}
       +
       +int
       +geten(Fid *efd)
       +{
       +        int n, c;
       +
       +        n = 0;
       +        while('0'<=(c=getec(efd)) && c<='9')
       +                n = n*10+(c-'0');
       +        if(c != ' ')
       +                error("event number syntax");
       +        return n;
       +}
       +
       +int
       +geter(Fid *efd, char *buf, int *nb)
       +{
       +        Rune r;
       +        int n;
       +
       +        r = getec(efd);
       +        buf[0] = r;
       +        n = 1;
       +        if(r < Runeself)
       +                goto Return;
       +        while(!fullrune(buf, n))
       +                buf[n++] = getec(efd);
       +        chartorune(&r, buf);
       +    Return:
       +        *nb = n;
       +        return r;
       +}
       +
       +void
       +gete(Fid *efd, Event *e)
       +{
       +        int i, nb;
       +
       +        e->c1 = getec(efd);
       +        e->c2 = getec(efd);
       +        e->q0 = geten(efd);
       +        e->q1 = geten(efd);
       +        e->flag = geten(efd);
       +        e->nr = geten(efd);
       +        if(e->nr > EVENTSIZE)
       +                error("event string too long");
       +        e->nb = 0;
       +        for(i=0; i<e->nr; i++){
       +                e->r[i] = geter(efd, e->b+e->nb, &nb);
       +                e->nb += nb;
       +        }
       +        e->r[e->nr] = 0;
       +        e->b[e->nb] = 0;
       +        if(getec(efd) != '\n')
       +                error("event syntax 2");
       +}
       +
       +int
       +nrunes(char *s, int nb)
       +{
       +        int i, n;
       +        Rune r;
       +
       +        n = 0;
       +        for(i=0; i<nb; n++)
       +                i += chartorune(&r, s+i);
       +        return n;
       +}
       +
       +void
       +stdinproc(void *v)
       +{
       +        Fid *cfd = ctlfd;
       +        Fid *efd = eventfd;
       +        Fid *dfd = datafd;
       +        Fid *afd = addrfd;
       +        int fd0 = rcfd;
       +        Event e, e2, e3, e4;
       +
       +        USED(v);
       +
       +        for(;;){
       +                if(debug)
       +                        fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
       +                gete(efd, &e);
       +                if(debug)
       +                        fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
       +                qlock(&q.lk);
       +                switch(e.c1){
       +                default:
       +                Unknown:
       +                        print("unknown message %c%c\n", e.c1, e.c2);
       +                        break;
       +
       +                case 'E':        /* write to body; can't affect us */
       +                        if(debug)
       +                                fprint(2, "shift typing %d... ", e.q1-e.q0);
       +                        q.p += e.q1-e.q0;
       +                        break;
       +
       +                case 'F':        /* generated by our actions; ignore */
       +                        break;
       +
       +                case 'K':
       +                case 'M':
       +                        switch(e.c2){
       +                        case 'I':
       +                                if(e.q0 < q.p){
       +                                        if(debug)
       +                                                fprint(2, "shift typing %d... ", e.q1-e.q0);
       +                                        q.p += e.q1-e.q0;
       +                                }
       +                                else if(e.q0 <= q.p+ntyper){
       +                                        if(debug)
       +                                                fprint(2, "type... ");
       +                                        type(&e, fd0, afd, dfd);
       +                                }
       +                                break;
       +
       +                        case 'D':
       +                                q.p -= delete(&e);
       +                                break;
       +
       +                        case 'x':
       +                        case 'X':
       +                                if(e.flag & 2)
       +                                        gete(efd, &e2);
       +                                if(e.flag & 8){
       +                                        gete(efd, &e3);
       +                                        gete(efd, &e4);
       +                                }
       +                                if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
       +                                        /* send it straight back */
       +                                        fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
       +                                        break;
       +                                }
       +                                if(e.q0==e.q1 && (e.flag&2)){
       +                                        e2.flag = e.flag;
       +                                        e = e2;
       +                                }
       +                                if(e.flag & 8){
       +                                        if(e.q1 != e.q0){
       +                                                sende(&e, fd0, cfd, afd, dfd, 0);
       +                                                sende(&blank, fd0, cfd, afd, dfd, 0);
       +                                        }
       +                                        sende(&e3, fd0, cfd, afd, dfd, 1);
       +                                }else         if(e.q1 != e.q0)
       +                                        sende(&e, fd0, cfd, afd, dfd, 1);
       +                                break;
       +
       +                        case 'l':
       +                        case 'L':
       +                                /* just send it back */
       +                                if(e.flag & 2)
       +                                        gete(efd, &e2);
       +                                fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
       +                                break;
       +
       +                        case 'd':
       +                        case 'i':
       +                                break;
       +
       +                        default:
       +                                goto Unknown;
       +                        }
       +                }
       +                qunlock(&q.lk);
       +        }
       +}
       +
       +void
       +stdoutproc(void *v)
       +{
       +        int fd1 = rcfd;
       +        Fid *afd = addrfd;
       +        Fid *dfd = datafd;
       +        int n, m, w, npart;
       +        char *buf, *s, *t;
       +        Rune r;
       +        char x[16], hold[UTFmax];
       +
       +        USED(v);
       +        threadnotify(nopipes, 1);
       +        buf = malloc(8192+UTFmax+1);
       +        npart = 0;
       +        for(;;){
       +                /* Let typing have a go -- maybe there's a rubout waiting. */
       +                yield();
       +                n = threadread(fd1, buf+npart, 8192);
       +                if(n < 0)
       +                        error(nil);
       +                if(n == 0)
       +                        continue;
       +
       +                /* squash NULs */
       +                s = memchr(buf+npart, 0, n);
       +                if(s){
       +                        for(t=s; s<buf+npart+n; s++)
       +                                if(*t = *s)        /* assign = */
       +                                        t++;
       +                        n = t-(buf+npart);
       +                }
       +
       +                n += npart;
       +
       +                /* hold on to final partial rune */
       +                npart = 0;
       +                while(n>0 && (buf[n-1]&0xC0)){
       +                        --n;
       +                        npart++;
       +                        if((buf[n]&0xC0)!=0x80){
       +                                if(fullrune(buf+n, npart)){
       +                                        w = chartorune(&r, buf+n);
       +                                        n += w;
       +                                        npart -= w;
       +                                }
       +                                break;
       +                        }
       +                }
       +                if(n > 0){
       +                        memmove(hold, buf+n, npart);
       +                        buf[n] = 0;
       +                        n = label(buf, n);
       +                        buf[n] = 0;
       +                        qlock(&q.lk);
       +                        m = sprint(x, "#%d", q.p);
       +                        if(fswrite(afd, x, m) != m)
       +                                error("stdout writing address");
       +                        if(fswrite(dfd, buf, n) != n)
       +                                error("stdout writing body");
       +                        q.p += nrunes(buf, n);
       +                        qunlock(&q.lk);
       +                        memmove(buf, hold, npart);
       +                }
       +        }
       +}
       +
       +char wdir[256];
       +int
       +label(char *sr, int n)
       +{
       +        char *sl, *el, *er, *r;
       +
       +        er = sr+n;
       +        for(r=er-1; r>=sr; r--)
       +                if(*r == '\007')
       +                        break;
       +        if(r < sr)
       +                return n;
       +
       +        el = r+1;
       +        if(el-sr > sizeof wdir)
       +                sr = el - sizeof wdir;
       +        for(sl=el-3; sl>=sr; sl--)
       +                if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
       +                        break;
       +        if(sl < sr)
       +                return n;
       +
       +        *r = 0;
       +        snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
       +        fswrite(ctlfd, wdir, strlen(wdir));
       +
       +        memmove(sl, el, er-el);
       +        n -= (el-sl);
       +        return n;
       +}
       +
       +int
       +delete(Event *e)
       +{
       +        uint q0, q1;
       +        int deltap;
       +
       +        q0 = e->q0;
       +        q1 = e->q1;
       +        if(q1 <= q.p)
       +                return e->q1-e->q0;
       +        if(q0 >= q.p+ntyper)
       +                return 0;
       +        deltap = 0;
       +        if(q0 < q.p){
       +                deltap = q.p-q0;
       +                q0 = 0;
       +        }else
       +                q0 -= q.p;
       +        if(q1 > q.p+ntyper)
       +                q1 = ntyper;
       +        else
       +                q1 -= q.p;
       +        deltype(q0, q1);
       +        return deltap;
       +}
       +
       +void
       +addtype(int c, uint p0, char *b, int nb, int nr)
       +{
       +        int i, w;
       +        Rune r;
       +        uint p;
       +        char *b0;
       +
       +        for(i=0; i<nb; i+=w){
       +                w = chartorune(&r, b+i);
       +                if((r==0x7F||r==3) && c=='K'){
       +                        write(rcfd, "\x7F", 1);
       +                        /* toss all typing */
       +                        q.p += ntyper+nr;
       +                        ntypebreak = 0;
       +                        ntypeb = 0;
       +                        ntyper = 0;
       +                        /* buglet:  more than one delete ignored */
       +                        return;
       +                }
       +                if(r=='\n' || r==0x04)
       +                        ntypebreak++;
       +        }
       +        typing = realloc(typing, ntypeb+nb);
       +        if(typing == nil)
       +                error("realloc");
       +        if(p0 == ntyper)
       +                memmove(typing+ntypeb, b, nb);
       +        else{
       +                b0 = typing;
       +                for(p=0; p<p0 && b0<typing+ntypeb; p++){
       +                        w = chartorune(&r, b0+i);
       +                        b0 += w;
       +                }
       +                if(p != p0)
       +                        error("typing: findrune");
       +                memmove(b0+nb, b0, (typing+ntypeb)-b0);
       +                memmove(b0, b, nb);
       +        }
       +        ntypeb += nb;
       +        ntyper += nr;
       +}
       +
       +void
       +sendtype(int fd0)
       +{
       +        int i, n, nr;
       +
       +        while(ntypebreak){
       +                for(i=0; i<ntypeb; i++)
       +                        if(typing[i]=='\n' || typing[i]==0x04){
       +                                n = i + (typing[i] == '\n');
       +                                i++;
       +                                if(write(fd0, typing, n) != n)
       +                                        error("sending to program");
       +                                nr = nrunes(typing, i);
       +                                q.p += nr;
       +                                ntyper -= nr;
       +                                ntypeb -= i;
       +                                memmove(typing, typing+i, ntypeb);
       +                                ntypebreak--;
       +                                goto cont2;
       +                        }
       +                print("no breakchar\n");
       +                ntypebreak = 0;
       +cont2:;
       +        }
       +}
       +
       +void
       +deltype(uint p0, uint p1)
       +{
       +        int w;
       +        uint p, b0, b1;
       +        Rune r;
       +
       +        /* advance to p0 */
       +        b0 = 0;
       +        for(p=0; p<p0 && b0<ntypeb; p++){
       +                w = chartorune(&r, typing+b0);
       +                b0 += w;
       +        }
       +        if(p != p0)
       +                error("deltype 1");
       +        /* advance to p1 */
       +        b1 = b0;
       +        for(; p<p1 && b1<ntypeb; p++){
       +                w = chartorune(&r, typing+b1);
       +                b1 += w;
       +                if(r=='\n' || r==0x04)
       +                        ntypebreak--;
       +        }
       +        if(p != p1)
       +                error("deltype 2");
       +        memmove(typing+b0, typing+b1, ntypeb-b1);
       +        ntypeb -= b1-b0;
       +        ntyper -= p1-p0;
       +}
       +
       +void
       +type(Event *e, int fd0, Fid *afd, Fid *dfd)
       +{
       +        int m, n, nr;
       +        char buf[128];
       +
       +        if(e->nr > 0)
       +                addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
       +        else{
       +                m = e->q0;
       +                while(m < e->q1){
       +                        n = sprint(buf, "#%d", m);
       +                        fswrite(afd, buf, n);
       +                        n = fsread(dfd, buf, sizeof buf);
       +                        nr = nrunes(buf, n);
       +                        while(m+nr > e->q1){
       +                                do; while(n>0 && (buf[--n]&0xC0)==0x80);
       +                                --nr;
       +                        }
       +                        if(n == 0)
       +                                break;
       +                        addtype(e->c1, m-q.p, buf, n, nr);
       +                        m += nr;
       +                }
       +        }
       +        sendtype(fd0);
       +}
       +
       +void
       +sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
       +{
       +        int l, m, n, nr, lastc, end;
       +        char abuf[16], buf[128];
       +
       +        end = q.p+ntyper;
       +        l = sprint(abuf, "#%d", end);
       +        fswrite(afd, abuf, l);
       +        if(e->nr > 0){
       +                fswrite(dfd, e->b, e->nb);
       +                addtype(e->c1, ntyper, e->b, e->nb, e->nr);
       +                lastc = e->r[e->nr-1];
       +        }else{
       +                m = e->q0;
       +                lastc = 0;
       +                while(m < e->q1){
       +                        n = sprint(buf, "#%d", m);
       +                        fswrite(afd, buf, n);
       +                        n = fsread(dfd, buf, sizeof buf);
       +                        nr = nrunes(buf, n);
       +                        while(m+nr > e->q1){
       +                                do; while(n>0 && (buf[--n]&0xC0)==0x80);
       +                                --nr;
       +                        }
       +                        if(n == 0)
       +                                break;
       +                        l = sprint(abuf, "#%d", end);
       +                        fswrite(afd, abuf, l);
       +                        fswrite(dfd, buf, n);
       +                        addtype(e->c1, ntyper, buf, n, nr);
       +                        lastc = buf[n-1];
       +                        m += nr;
       +                        end += nr;
       +                }
       +        }
       +        if(donl && lastc!='\n'){
       +                fswrite(dfd, "\n", 1);
       +                addtype(e->c1, ntyper, "\n", 1, 1);
       +        }
       +        fswrite(cfd, "dot=addr", 8);
       +        sendtype(fd0);
       +}
 (DIR) diff --git a/src/cmd/acme/acme.c b/src/cmd/acme/acme.c
       t@@ -161,7 +161,8 @@ threadmain(int argc, char *argv[])
                cerr = chancreate(sizeof(char*), 0);
                cedit = chancreate(sizeof(int), 0);
                cexit = chancreate(sizeof(int), 0);
       -        if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil){
       +        cwarn = chancreate(sizeof(void*), 1);
       +        if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil || cwarn==nil){
                        fprint(2, "acme: can't create initial channels: %r\n");
                        exits("channels");
                }
       t@@ -251,7 +252,7 @@ readfile(Column *c, char *s)
        
                w = coladd(c, nil, nil, -1);
                cvttorunes(s, strlen(s), rb, &nb, &nr, nil);
       -        rs = cleanrname((Runestr){rb, nr});
       +        rs = cleanrname(runestr(rb, nr));
                winsetname(w, rs.r, rs.nr);
                textload(&w->body, 0, s, 1);
                w->body.file->mod = FALSE;
       t@@ -403,7 +404,6 @@ keyboardthread(void *v)
                                        winlock(t->w, 'K');
                                        wincommit(t->w, t);
                                        winunlock(t->w);
       -                                flushwarnings(1);
                                        flushimage(display, 1);
                                }
                                alts[KTimer].c = nil;
       t@@ -430,7 +430,6 @@ keyboardthread(void *v)
                                }
                                if(nbrecv(keyboardctl->c, &r) > 0)
                                        goto casekeyboard;
       -                        flushwarnings(1);
                                flushimage(display, 1);
                                break;
                        }
       t@@ -447,7 +446,7 @@ mousethread(void *v)
                Plumbmsg *pm;
                Mouse m;
                char *act;
       -        enum { MResize, MMouse, MPlumb, NMALT };
       +        enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
                static Alt alts[NMALT+1];
        
                USED(v);
       t@@ -461,11 +460,18 @@ mousethread(void *v)
                alts[MPlumb].c = cplumb;
                alts[MPlumb].v = &pm;
                alts[MPlumb].op = CHANRCV;
       +        alts[MWarnings].c = cwarn;
       +        alts[MWarnings].v = nil;
       +        alts[MWarnings].op = CHANRCV;
                if(cplumb == nil)
                        alts[MPlumb].op = CHANNOP;
                alts[NMALT].op = CHANEND;
                
                for(;;){
       +                qlock(&row.lk);
       +                flushwarnings();
       +                qunlock(&row.lk);
       +                flushimage(display, 1);
                        switch(alt(alts)){
                        case MResize:
                                if(getwindow(display, Refnone) < 0)
       t@@ -473,8 +479,6 @@ mousethread(void *v)
                                draw(screen, screen->r, display->white, nil, ZP);
                                scrlresize();
                                rowresize(&row, screen->clipr);
       -                        flushwarnings(1);
       -                        flushimage(display, 1);
                                break;
                        case MPlumb:
                                if(strcmp(pm->type, "text") == 0){
       t@@ -484,10 +488,10 @@ mousethread(void *v)
                                        else if(strcmp(act, "showdata")==0)
                                                plumbshow(pm);
                                }
       -                        flushwarnings(1);
       -                        flushimage(display, 1);
                                plumbfree(pm);
                                break;
       +                case MWarnings:
       +                        break;
                        case MMouse:
                                /*
                                 * Make a copy so decisions are consistent; mousectl changes
       t@@ -570,8 +574,6 @@ mousethread(void *v)
                                        goto Continue;
                                }
            Continue:
       -                        flushwarnings(0);
       -                        flushimage(display, 1);
                                qunlock(&row.lk);
                                break;
                        }
 (DIR) diff --git a/src/cmd/acme/dat.h b/src/cmd/acme/dat.h
       t@@ -543,5 +543,6 @@ Channel        *mouseexit1;        /* chan(int) */
        Channel        *cexit;                /* chan(int) */
        Channel        *cerr;                /* chan(char*) */
        Channel        *cedit;                /* chan(int) */
       +Channel        *cwarn;                /* chan(void*)[1] (really chan(unit)[1]) */
        
        #define        STACK        32768
 (DIR) diff --git a/src/cmd/acme/ecmd.c b/src/cmd/acme/ecmd.c
       t@@ -268,7 +268,7 @@ D_cmd(Text *t, Cmd *cp)
                                runemove(n, dir.r, dir.nr);
                                n[dir.nr] = '/';
                                runemove(n+dir.nr+1, r, nn);
       -                        rs = cleanrname((Runestr){n, dir.nr+1+nn});
       +                        rs = cleanrname(runestr(n, dir.nr+1+nn));
                        }
                        w = lookfile(rs.r, rs.nr);
                        if(w == nil){
 (DIR) diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
       t@@ -25,6 +25,7 @@ void        fontx(Text*, Text*, Text*, int, int, Rune*, int);
        void        get(Text*, Text*, Text*, int, int, Rune*, int);
        void        id(Text*, Text*, Text*, int, int, Rune*, int);
        void        incl(Text*, Text*, Text*, int, int, Rune*, int);
       +void        indent(Text*, Text*, Text*, int, int, Rune*, int);
        void        xkill(Text*, Text*, Text*, int, int, Rune*, int);
        void        local(Text*, Text*, Text*, int, int, Rune*, int);
        void        look(Text*, Text*, Text*, int, int, Rune*, int);
       t@@ -58,6 +59,7 @@ static Rune LFont[] = { 'F', 'o', 'n', 't', 0 };
        static Rune LGet[] = { 'G', 'e', 't', 0 };
        static Rune LID[] = { 'I', 'D', 0 };
        static Rune LIncl[] = { 'I', 'n', 'c', 'l', 0 };
       +static Rune LIndent[] = { 'I', 'n', 'd', 'e', 'n', 't', 0 };
        static Rune LKill[] = { 'K', 'i', 'l', 'l', 0 };
        static Rune LLoad[] = { 'L', 'o', 'a', 'd', 0 };
        static Rune LLocal[] = { 'L', 'o', 'c', 'a', 'l', 0 };
       t@@ -87,6 +89,7 @@ Exectab exectab[] = {
                { LGet,                get,                FALSE,        TRUE,        XXX                },
                { LID,                id,                FALSE,        XXX,                XXX                },
                { LIncl,                incl,                FALSE,        XXX,                XXX                },
       +        { LIndent,                indent,        FALSE,        XXX,                XXX                },
                { LKill,                xkill,                FALSE,        XXX,                XXX                },
                { LLoad,                dump,        FALSE,        FALSE,        XXX                },
                { LLocal,                local,        FALSE,        XXX,                XXX                },
       t@@ -1443,7 +1446,6 @@ runproc(void *argvp)
                goto Fail;
        
        Hard:
       -
                /*
                 * ugly: set path = (. $cputype /bin)
                 * should honor $path if unusual.
 (DIR) diff --git a/src/cmd/acme/fns.h b/src/cmd/acme/fns.h
       t@@ -69,6 +69,7 @@ Rune*        bytetorune(char*, int*);
        void        fsysinit(void);
        Mntdir*        fsysmount(Rune*, int, Rune**, int);
        void                fsysdelid(Mntdir*);
       +void                fsysincid(Mntdir*);
        Xfid*                respond(Xfid*, Fcall*, char*);
        int                rxcompile(Rune*);
        int                rgetc(void*, uint);
       t@@ -86,9 +87,11 @@ int        expand(Text*, uint, uint, Expand*);
        Rune*        skipbl(Rune*, int, int*);
        Rune*        findbl(Rune*, int, int*);
        char*        edittext(Window*, int, Rune*, int);
       -void                flushwarnings(int);
       +void                flushwarnings(void);
        void                startplumbing(void);
        
       +Runestr        runestr(Rune*, uint);
       +
        #define        runemalloc(a)                (Rune*)emalloc((a)*sizeof(Rune))
        #define        runerealloc(a, b)        (Rune*)erealloc((a), (b)*sizeof(Rune))
        #define        runemove(a, b, c)        memmove((a), (b), (c)*sizeof(Rune))
 (DIR) diff --git a/src/cmd/acme/fsys.c b/src/cmd/acme/fsys.c
       t@@ -37,22 +37,25 @@ static        Xfid*        fsysremove(Xfid*, Fid*);
        static        Xfid*        fsysstat(Xfid*, Fid*);
        static        Xfid*        fsyswstat(Xfid*, Fid*);
        
       -Xfid*         (*fcall[Tmax])(Xfid*, Fid*) =
       +Xfid*         (*fcall[Tmax])(Xfid*, Fid*);
       +
       +static void
       +initfcall(void)
        {
       -        [Tflush]        = fsysflush,
       -        [Tversion]        = fsysversion,
       -        [Tauth]        = fsysauth,
       -        [Tattach]        = fsysattach,
       -        [Twalk]        = fsyswalk,
       -        [Topen]        = fsysopen,
       -        [Tcreate]        = fsyscreate,
       -        [Tread]        = fsysread,
       -        [Twrite]        = fsyswrite,
       -        [Tclunk]        = fsysclunk,
       -        [Tremove]= fsysremove,
       -        [Tstat]        = fsysstat,
       -        [Twstat]        = fsyswstat,
       -};
       +        fcall[Tflush]        = fsysflush;
       +        fcall[Tversion]        = fsysversion;
       +        fcall[Tauth]        = fsysauth;
       +        fcall[Tattach]        = fsysattach;
       +        fcall[Twalk]        = fsyswalk;
       +        fcall[Topen]        = fsysopen;
       +        fcall[Tcreate]        = fsyscreate;
       +        fcall[Tread]        = fsysread;
       +        fcall[Twrite]        = fsyswrite;
       +        fcall[Tclunk]        = fsysclunk;
       +        fcall[Tremove]= fsysremove;
       +        fcall[Tstat]        = fsysstat;
       +        fcall[Twstat]        = fsyswstat;
       +}
        
        char Eperm[] = "permission denied";
        char Eexist[] = "file does not exist";
       t@@ -113,6 +116,7 @@ fsysinit(void)
                int p[2];
                char *u;
        
       +        initfcall();
                if(pipe(p) < 0)
                        error("can't create pipe");
                if(post9pservice(p[0], "acme") < 0)
       t@@ -187,6 +191,14 @@ fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
        }
        
        void
       +fsysincid(Mntdir *m)
       +{
       +        qlock(&mnt.lk);
       +        m->ref++;
       +        qunlock(&mnt.lk);
       +}
       +
       +void
        fsysdelid(Mntdir *idm)
        {
                Mntdir *m, *prev;
       t@@ -331,7 +343,7 @@ fsysattach(Xfid *x, Fid *f)
                                m->ref++;
                                break;
                        }
       -        if(m == nil){
       +        if(m == nil && x->fcall.aname[0]){
                        snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
                        sendp(cerr, estrdup(buf));
                }
 (DIR) diff --git a/src/cmd/acme/look.c b/src/cmd/acme/look.c
       t@@ -259,7 +259,7 @@ plumbshow(Plumbmsg *m)
                }
                cvttorunes(name, strlen(name), rb, &nb, &nr, nil);
                free(p);
       -        rs = cleanrname((Runestr){rb, nr});
       +        rs = cleanrname(runestr(rb, nr));
                winsetname(w, rs.r, rs.nr);
                r = runemalloc(m->ndata);
                cvttorunes(m->data, m->ndata, r, &nb, &nr, nil);
       t@@ -385,13 +385,13 @@ includefile(Rune *dir, Rune *file, int nfile)
                n = access(a, 0);
                free(a);
                if(n < 0)
       -                return (Runestr){nil, 0};
       +                return runestr(nil, 0);
                r = runemalloc(m+1+nfile);
                runemove(r, dir, m);
                runemove(r+m, Lslash, 1);
                runemove(r+m+1, file, nfile);
                free(file);
       -        return cleanrname((Runestr){r, m+1+nfile});
       +        return cleanrname(runestr(r, m+1+nfile));
        }
        
        static        Rune        *objdir;
       t@@ -442,7 +442,7 @@ includename(Text *t, Rune *r, int n)
                return file;
        
            Rescue:
       -        return (Runestr){r, n};
       +        return runestr(r, n);
        }
        
        Runestr
       t@@ -475,11 +475,11 @@ dirname(Text *t, Rune *r, int n)
                        goto Rescue;
                runemove(b+slash+1, r, n);
                free(r);
       -        return cleanrname((Runestr){b, slash+1+n});
       +        return cleanrname(runestr(b, slash+1+n));
        
            Rescue:
                free(b);
       -        tmp = (Runestr){r, n};
       +        tmp = runestr(r, n);
                if(r)
                        return cleanrname(tmp);
                return tmp;
 (DIR) diff --git a/src/cmd/acme/text.c b/src/cmd/acme/text.c
       t@@ -578,7 +578,7 @@ textcomplete(Text *t)
                        path[i] = textreadc(t, q++);
                /* is path rooted? if not, we need to make it relative to window path */
                if(npath>0 && path[0]=='/')
       -                dir = (Runestr){path, npath};
       +                dir = runestr(path, npath);
                else{
                        dir = dirname(t, nil, 0);
                        if(dir.nr + 1 + npath > nelem(tmp)){
 (DIR) diff --git a/src/cmd/acme/util.c b/src/cmd/acme/util.c
       t@@ -14,6 +14,16 @@
        static        Point                prevmouse;
        static        Window        *mousew;
        
       +Runestr
       +runestr(Rune *r, uint n)
       +{
       +        Runestr rs;
       +
       +        rs.r = r;
       +        rs.nr = n;
       +        return rs;
       +}
       +
        void
        cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
        {
       t@@ -133,12 +143,17 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
                }
                warn = emalloc(sizeof(Warning));
                warn->next = warnings;
       +        warn->md = md;
       +        if(md)
       +                fsysincid(md);
                warnings = warn;
                bufinsert(&warn->buf, 0, r, nr);
       +        nbsendp(cwarn, 0);
        }
        
       +/* called while row is locked */
        void
       -flushwarnings(int dolock)
       +flushwarnings(void)
        {
                Warning *warn, *next;
                Window *w;
       t@@ -146,8 +161,6 @@ flushwarnings(int dolock)
                int owner, nr, q0, n;
                Rune *r;
        
       -        if(dolock)
       -                qlock(&row.lk);
                if(row.ncol == 0){        /* really early error */
                        rowinit(&row, screen->clipr);
                        rowadd(&row, nil, -1);
       t@@ -189,11 +202,11 @@ flushwarnings(int dolock)
                        winunlock(w);
                        bufclose(&warn->buf);
                        next = warn->next;
       +                if(warn->md)
       +                        fsysdelid(warn->md);
                        free(warn);
                }
                warnings = nil;
       -        if(dolock)
       -                qunlock(&row.lk);
        }
        
        void
 (DIR) diff --git a/src/cmd/acme/xfid.c b/src/cmd/acme/xfid.c
       t@@ -543,7 +543,6 @@ xfidwrite(Xfid *x)
                }
                if(w)
                        winunlock(w);
       -        flushwarnings(1);
        }
        
        void
       t@@ -814,7 +813,6 @@ xfideventwrite(Xfid *x, Window *w)
                                qunlock(&row.lk);
                                goto Rescue;
                        }
       -                flushwarnings(0);
                        qunlock(&row.lk);
        
                }
       t@@ -1032,7 +1030,6 @@ xfidindexread(Xfid *x)
                                b[n++] = '\n';
                        }
                }
       -        flushwarnings(0);
                qunlock(&row.lk);
                off = x->fcall.offset;
                cnt = x->fcall.count;
 (DIR) diff --git a/src/cmd/dict/dict.c b/src/cmd/dict/dict.c
       t@@ -119,6 +119,8 @@ main(int argc, char **argv)
                        line = malloc(strlen(p)+5);
                        sprint(line, "/%s/P\n", p);
                }
       +        dict->path = unsharp(dict->path);
       +        dict->indexpath = unsharp(dict->indexpath);
                bdict = Bopen(dict->path, OREAD);
                if(!bdict) {
                        err("can't open dictionary %s", dict->path);
 (DIR) diff --git a/src/cmd/diff/diff.h b/src/cmd/diff/diff.h
       t@@ -1,3 +1,5 @@
       +#define stdout bstdout
       +
        char mode;                        /* '\0', 'e', 'f', 'h' */
        char bflag;                        /* ignore multiple and trailing blanks */
        char rflag;                        /* recurse down directory trees */
 (DIR) diff --git a/src/cmd/diff/main.c b/src/cmd/diff/main.c
       t@@ -26,6 +26,8 @@ void
        done(int status)
        {
                rmtmpfiles();
       +Bflush(&stdout);
       +Bterm(&stdout);
                switch(status)
                {
                case 0:
 (DIR) diff --git a/src/cmd/fortune.c b/src/cmd/fortune.c
       t@@ -4,8 +4,8 @@
        
        #define index findex
        char choice[2048];
       -char index[] = "/sys/games/lib/fortunes.index";
       -char fortunes[] = "/sys/games/lib/fortunes";
       +char *index = "#9/lib/fortunes.index";
       +char *fortunes = "#9/lib/fortunes";
        
        #define lrand rand
        
       t@@ -21,6 +21,9 @@ main(int argc, char *argv[])
                Dir *fbuf, *ixbuf;
                Biobuf *f, g;
        
       +        index = unsharp(index);
       +        fortunes = unsharp(index);
       +
                newindex = 0;
                oldindex = 0;
                ix = offs = 0;
       t@@ -55,6 +58,7 @@ main(int argc, char *argv[])
                        }
                }
                if(oldindex){
       +                srand(getpid());
                        seek(ix, lrand()%(ixbuf->length/sizeof(offs))*sizeof(offs), 0);
                        read(ix, off, sizeof(off));
                        Bseek(f, off[0]|(off[1]<<8)|(off[2]<<16)|(off[3]<<24), 0);
 (DIR) diff --git a/src/cmd/grep/comp.c b/src/cmd/grep/comp.c
       t@@ -0,0 +1,277 @@
       +#include        "grep.h"
       +
       +/*
       + * incremental compiler.
       + * add the branch c to the
       + * state s.
       + */
       +void
       +increment(State *s, int c)
       +{
       +        int i;
       +        State *t, **tt;
       +        Re *re1, *re2;
       +
       +        nfollow = 0;
       +        gen++;
       +        matched = 0;
       +        for(i=0; i<s->count; i++)
       +                fol1(s->re[i], c);
       +        qsort(follow, nfollow, sizeof(*follow), fcmp);
       +        for(tt=&state0; t = *tt;) {
       +                if(t->count > nfollow) {
       +                        tt = &t->linkleft;
       +                        goto cont;
       +                }
       +                if(t->count < nfollow) {
       +                        tt = &t->linkright;
       +                        goto cont;
       +                }
       +                for(i=0; i<nfollow; i++) {
       +                        re1 = t->re[i];
       +                        re2 = follow[i];
       +                        if(re1 > re2) {
       +                                tt = &t->linkleft;
       +                                goto cont;
       +                        }
       +                        if(re1 < re2) {
       +                                tt = &t->linkright;
       +                                goto cont;
       +                        }
       +                }
       +                if(!!matched && !t->match) {
       +                        tt = &t->linkleft;
       +                        goto cont;
       +                }
       +                if(!matched && !!t->match) {
       +                        tt = &t->linkright;
       +                        goto cont;
       +                }
       +                s->next[c] = t;
       +                return;
       +        cont:;
       +        }
       +
       +        t = sal(nfollow);
       +        *tt = t;
       +        for(i=0; i<nfollow; i++) {
       +                re1 = follow[i];
       +                t->re[i] = re1;
       +        }
       +        s->next[c] = t;
       +        t->match = matched;
       +}
       +
       +int
       +fcmp(const void *va, const void *vb)
       +{
       +        Re **aa, **bb;
       +        Re *a, *b;
       +
       +        aa = (Re**)va;
       +        bb = (Re**)vb;
       +        a = *aa;
       +        b = *bb;
       +        if(a > b)
       +                return 1;
       +        if(a < b)
       +                return -1;
       +        return 0;
       +}
       +
       +void
       +fol1(Re *r, int c)
       +{
       +        Re *r1;
       +
       +loop:
       +        if(r->gen == gen)
       +                return;
       +        if(nfollow >= maxfollow)
       +                error("nfollow");
       +        r->gen = gen;
       +        switch(r->type) {
       +        default:
       +                error("fol1");
       +
       +        case Tcase:
       +                if(c >= 0 && c < 256)
       +                if(r1 = r->cases[c])
       +                        follow[nfollow++] = r1;
       +                if(r = r->next)
       +                        goto loop;
       +                break;
       +
       +        case Talt:
       +        case Tor:
       +                fol1(r->alt, c);
       +                r = r->next;
       +                goto loop;
       +
       +        case Tbegin:
       +                if(c == '\n' || c == Cbegin)
       +                        follow[nfollow++] = r->next;
       +                break;
       +
       +        case Tend:
       +                if(c == '\n')
       +                        matched = 1;
       +                break;
       +
       +        case Tclass:
       +                if(c >= r->lo && c <= r->hi)
       +                        follow[nfollow++] = r->next;
       +                break;
       +        }
       +}
       +
       +Rune        tab1[] =
       +{
       +        0x007f,
       +        0x07ff,
       +};
       +Rune        tab2[] =
       +{
       +        0x003f,
       +        0x0fff,
       +};
       +
       +Re2
       +rclass(Rune p0, Rune p1)
       +{
       +        char xc0[6], xc1[6];
       +        int i, n, m;
       +        Re2 x;
       +
       +        if(p0 > p1)
       +                return re2char(0xff, 0xff);        // no match
       +
       +        /*
       +         * bust range into same length
       +         * character sequences
       +         */
       +        for(i=0; i<nelem(tab1); i++) {
       +                m = tab1[i];
       +                if(p0 <= m && p1 > m)
       +                        return re2or(rclass(p0, m), rclass(m+1, p1));
       +        }
       +
       +        /*
       +         * bust range into part of a single page
       +         * or into full pages
       +         */
       +        for(i=0; i<nelem(tab2); i++) {
       +                m = tab2[i];
       +                if((p0 & ~m) != (p1 & ~m)) {
       +                        if((p0 & m) != 0)
       +                                return re2or(rclass(p0, p0|m), rclass((p0|m)+1, p1));
       +                        if((p1 & m) != m)
       +                                return re2or(rclass(p0, (p1&~m)-1), rclass(p1&~m, p1));
       +                }
       +        }
       +
       +        n = runetochar(xc0, &p0);
       +        i = runetochar(xc1, &p1);
       +        if(i != n)
       +                error("length");
       +
       +        x = re2char(xc0[0], xc1[0]);
       +        for(i=1; i<n; i++)
       +                x = re2cat(x, re2char(xc0[i], xc1[i]));
       +        return x;
       +}
       +
       +int
       +pcmp(const void *va, const void *vb)
       +{
       +        int n;
       +        Rune *a, *b;
       +
       +        a = (Rune*)va;
       +        b = (Rune*)vb;
       +
       +        n = a[0] - b[0];
       +        if(n)
       +                return n;
       +        return a[1] - b[1];
       +}
       +
       +/*
       + * convert character chass into
       + * run-pair ranges of matches.
       + * this is 10646/utf specific and
       + * needs to be changed for some
       + * other input character set.
       + * this is the key to a fast
       + * regular search of characters
       + * by looking at sequential bytes.
       + */
       +Re2
       +re2class(char *s)
       +{
       +        Rune pairs[200], *p, *q, ov;
       +        int nc;
       +        Re2 x;
       +
       +        nc = 0;
       +        if(*s == '^') {
       +                nc = 1;
       +                s++;
       +        }
       +
       +        p = pairs;
       +        s += chartorune(p, s);
       +        for(;;) {
       +                if(*p == '\\')
       +                        s += chartorune(p, s);
       +                if(*p == 0)
       +                        break;
       +                p[1] = *p;
       +                p += 2;
       +                s += chartorune(p, s);
       +                if(*p != '-')
       +                        continue;
       +                s += chartorune(p, s);
       +                if(*p == '\\')
       +                        s += chartorune(p, s);
       +                if(*p == 0)
       +                        break;
       +                p[-1] = *p;
       +                s += chartorune(p, s);
       +        }
       +        *p = 0;
       +        qsort(pairs, (p-pairs)/2, 2*sizeof(*pairs), pcmp);
       +
       +        q = pairs;
       +        for(p=pairs+2; *p; p+=2) {
       +                if(p[0] > p[1])
       +                        continue;
       +                if(p[0] > q[1] || p[1] < q[0]) {
       +                        q[2] = p[0];
       +                        q[3] = p[1];
       +                        q += 2;
       +                        continue;
       +                }
       +                if(p[0] < q[0])
       +                        q[0] = p[0];
       +                if(p[1] > q[1])
       +                        q[1] = p[1];
       +        }
       +        q[2] = 0;
       +
       +        p = pairs;
       +        if(nc) {
       +                x = rclass(0, p[0]-1);
       +                ov = p[1]+1;
       +                for(p+=2; *p; p+=2) {
       +                        x = re2or(x, rclass(ov, p[0]-1));
       +                        ov = p[1]+1;
       +                }
       +                x = re2or(x, rclass(ov, 0xffff));
       +        } else {
       +                x = rclass(p[0], p[1]);
       +                for(p+=2; *p; p+=2)
       +                        x = re2or(x, rclass(p[0], p[1]));
       +        }
       +        return x;
       +}
 (DIR) diff --git a/src/cmd/grep/grep.h b/src/cmd/grep/grep.h
       t@@ -0,0 +1,125 @@
       +#include        <u.h>
       +#include        <libc.h>
       +#include        <bio.h>
       +
       +#ifndef        EXTERN
       +#define        EXTERN        extern
       +#endif
       +
       +typedef        struct        Re        Re;
       +typedef        struct        Re2        Re2;
       +typedef        struct        State        State;
       +
       +struct        State
       +{
       +        int        count;
       +        int        match;
       +        Re**        re;
       +        State*        linkleft;
       +        State*        linkright;
       +        State*        next[256];
       +};
       +struct        Re2
       +{
       +        Re*        beg;
       +        Re*        end;
       +};
       +struct        Re
       +{
       +        uchar        type;
       +        ushort        gen;
       +        union
       +        {
       +                Re*        alt;        /* Talt */
       +                Re**        cases;        /* case */
       +                struct                /* class */
       +                {
       +                        Rune        lo;
       +                        Rune        hi;
       +                };        
       +                Rune        val;        /* char */
       +        };
       +        Re*        next;
       +};
       +
       +enum
       +{
       +        Talt                = 1,
       +        Tbegin,
       +        Tcase,
       +        Tclass,
       +        Tend,
       +        Tor,
       +
       +        Caselim                = 7,
       +        Nhunk                = 1<<16,
       +        Cbegin                = 0x10000,
       +        Flshcnt                = (1<<9)-1,
       +
       +        Cflag                = 1<<0,
       +        Hflag                = 1<<1,
       +        Iflag                = 1<<2,
       +        Llflag                = 1<<3,
       +        LLflag                = 1<<4,
       +        Nflag                = 1<<5,
       +        Sflag                = 1<<6,
       +        Vflag                = 1<<7,
       +        Bflag                = 1<<8
       +};
       +
       +EXTERN        union
       +{
       +        char        string[16*1024];
       +        struct
       +        {
       +                /*
       +                 * if a line requires multiple reads, we keep shifting
       +                 * buf down into pre and then do another read into
       +                 * buf.  so you'll get the last 16-32k of the matching line.
       +                 * if pre were smaller than buf you'd get a suffix of the
       +                 * line with a hole cut out.
       +                 */
       +                uchar        pre[16*1024];        /* to save to previous '\n' */
       +                uchar        buf[16*1024];        /* input buffer */
       +        };
       +} u;
       +
       +EXTERN        char        *filename;
       +EXTERN        Biobuf        bout;
       +EXTERN        char        flags[256];
       +EXTERN        Re**        follow;
       +EXTERN        ushort        gen;
       +EXTERN        char*        input;
       +EXTERN        long        lineno;
       +EXTERN        int        literal;
       +EXTERN        int        matched;
       +EXTERN        long        maxfollow;
       +EXTERN        long        nfollow;
       +EXTERN        int        peekc;
       +EXTERN        Biobuf*        rein;
       +EXTERN        State*        state0;
       +EXTERN        Re2        topre;
       +
       +extern        Re*        addcase(Re*);
       +extern        void        appendnext(Re*, Re*);
       +extern        void        error(char*);
       +extern        int        fcmp(const void*, const void*);         /* (Re**, Re**) */
       +extern        void        fol1(Re*, int);
       +extern        int        getrec(void);
       +extern        void        increment(State*, int);
       +#define initstate grepinitstate
       +extern        State*        initstate(Re*);
       +extern        void*        mal(int);
       +extern        void        patchnext(Re*, Re*);
       +extern        Re*        ral(int);
       +extern        Re2        re2cat(Re2, Re2);
       +extern        Re2        re2class(char*);
       +extern        Re2        re2or(Re2, Re2);
       +extern        Re2        re2char(int, int);
       +extern        Re2        re2star(Re2);
       +extern        State*        sal(int);
       +extern        int        search(char*, int);
       +extern        void        str2top(char*);
       +extern        int        yyparse(void);
       +extern        void        reprint(char*, Re*);
       +extern        void        yyerror(char*, ...);
 (DIR) diff --git a/src/cmd/grep/grep.y b/src/cmd/grep/grep.y
       t@@ -0,0 +1,226 @@
       +%{
       +#include        "grep.h"
       +%}
       +
       +%union
       +{
       +        int        val;
       +        char*        str;
       +        Re2        re;
       +}
       +
       +%type        <re>        expr prog
       +%type        <re>        expr0 expr1 expr2 expr3 expr4
       +%token        <str>        LCLASS
       +%token        <val>        LCHAR
       +%token                LLPAREN LRPAREN LALT LSTAR LPLUS LQUES
       +%token                LBEGIN LEND LDOT LBAD LNEWLINE
       +%%
       +
       +prog:
       +        expr newlines
       +        {
       +                $$.beg = ral(Tend);
       +                $$.end = $$.beg;
       +                $$ = re2cat(re2star(re2or(re2char(0x00, '\n'-1), re2char('\n'+1, 0xff))), $$);
       +                $$ = re2cat($1, $$);
       +                $$ = re2cat(re2star(re2char(0x00, 0xff)), $$);
       +                topre = $$;
       +        }
       +
       +expr:
       +        expr0
       +|        expr newlines expr0
       +        {
       +                $$ = re2or($1, $3);
       +        }
       +
       +expr0:
       +        expr1
       +|        LSTAR { literal = 1; } expr1
       +        {
       +                $$ = $3;
       +        }
       +
       +expr1:
       +        expr2
       +|        expr1 LALT expr2
       +        {
       +                $$ = re2or($1, $3);
       +        }
       +
       +expr2:
       +        expr3
       +|        expr2 expr3
       +        {
       +                $$ = re2cat($1, $2);
       +        }
       +
       +expr3:
       +        expr4
       +|        expr3 LSTAR
       +        {
       +                $$ = re2star($1);
       +        }
       +|        expr3 LPLUS
       +        {
       +                $$.beg = ral(Talt);
       +                patchnext($1.end, $$.beg);
       +                $$.beg->alt = $1.beg;
       +                $$.end = $$.beg;
       +                $$.beg = $1.beg;
       +        }
       +|        expr3 LQUES
       +        {
       +                $$.beg = ral(Talt);
       +                $$.beg->alt = $1.beg;
       +                $$.end = $1.end;
       +                appendnext($$.end,  $$.beg);
       +        }
       +
       +expr4:
       +        LCHAR
       +        {
       +                $$.beg = ral(Tclass);
       +                $$.beg->lo = $1;
       +                $$.beg->hi = $1;
       +                $$.end = $$.beg;
       +        }
       +|        LBEGIN
       +        {
       +                $$.beg = ral(Tbegin);
       +                $$.end = $$.beg;
       +        }
       +|        LEND
       +        {
       +                $$.beg = ral(Tend);
       +                $$.end = $$.beg;
       +        }
       +|        LDOT
       +        {
       +                $$ = re2class("^\n");
       +        }
       +|        LCLASS
       +        {
       +                $$ = re2class($1);
       +        }
       +|        LLPAREN expr1 LRPAREN
       +        {
       +                $$ = $2;
       +        }
       +
       +newlines:
       +        LNEWLINE
       +|        newlines LNEWLINE
       +%%
       +
       +void
       +yyerror(char *e, ...)
       +{
       +        if(filename)
       +                fprint(2, "grep: %s:%ld: %s\n", filename, lineno, e);
       +        else
       +                fprint(2, "grep: %s\n", e);
       +        exits("syntax");
       +}
       +
       +long
       +yylex(void)
       +{
       +        char *q, *eq;
       +        int c, s;
       +
       +        if(peekc) {
       +                s = peekc;
       +                peekc = 0;
       +                return s;
       +        }
       +        c = getrec();
       +        if(literal) {
       +                if(c != 0 && c != '\n') {
       +                        yylval.val = c;
       +                        return LCHAR;
       +                }
       +                literal = 0;
       +        }
       +        switch(c) {
       +        default:
       +                yylval.val = c;
       +                s = LCHAR;
       +                break;
       +        case '\\':
       +                c = getrec();
       +                yylval.val = c;
       +                s = LCHAR;
       +                if(c == '\n')
       +                        s = LNEWLINE;
       +                break;
       +        case '[':
       +                goto getclass;
       +        case '(':
       +                s = LLPAREN;
       +                break;
       +        case ')':
       +                s = LRPAREN;
       +                break;
       +        case '|':
       +                s = LALT;
       +                break;
       +        case '*':
       +                s = LSTAR;
       +                break;
       +        case '+':
       +                s = LPLUS;
       +                break;
       +        case '?':
       +                s = LQUES;
       +                break;
       +        case '^':
       +                s = LBEGIN;
       +                break;
       +        case '$':
       +                s = LEND;
       +                break;
       +        case '.':
       +                s = LDOT;
       +                break;
       +        case 0:
       +                peekc = -1;
       +        case '\n':
       +                s = LNEWLINE;
       +                break;
       +        }
       +        return s;
       +
       +getclass:
       +        q = u.string;
       +        eq = q + nelem(u.string) - 5;
       +        c = getrec();
       +        if(c == '^') {
       +                q[0] = '^';
       +                q[1] = '\n';
       +                q[2] = '-';
       +                q[3] = '\n';
       +                q += 4;
       +                c = getrec();
       +        }
       +        for(;;) {
       +                if(q >= eq)
       +                        error("class too long");
       +                if(c == ']' || c == 0)
       +                        break;
       +                if(c == '\\') {
       +                        *q++ = c;
       +                        c = getrec();
       +                        if(c == 0)
       +                                break;
       +                }
       +                *q++ = c;
       +                c = getrec();
       +        }
       +        *q = 0;
       +        if(c == 0)
       +                return LBAD;
       +        yylval.str = u.string;
       +        return LCLASS;
       +}
 (DIR) diff --git a/src/cmd/grep/main.c b/src/cmd/grep/main.c
       t@@ -0,0 +1,260 @@
       +#define        EXTERN
       +#include        "grep.h"
       +
       +char *validflags = "bchiLlnsv";
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        int i, status;
       +
       +        ARGBEGIN {
       +        default:
       +                if(utfrune(validflags, ARGC()) == nil)
       +                        usage();
       +                flags[ARGC()]++;
       +                break;
       +
       +        case 'e':
       +                flags['e']++;
       +                lineno = 0;
       +                str2top(ARGF());
       +                break;
       +
       +        case 'f':
       +                flags['f']++;
       +                filename = ARGF();
       +                rein = Bopen(filename, OREAD);
       +                if(rein == 0) {
       +                        fprint(2, "grep: can't open %s: %r\n", filename);
       +                        exits("open");
       +                }
       +                lineno = 1;
       +                str2top(filename);
       +                break;
       +        } ARGEND
       +
       +        if(flags['f'] == 0 && flags['e'] == 0) {
       +                if(argc <= 0)
       +                        usage();
       +                str2top(argv[0]);
       +                argc--;
       +                argv++;
       +        }
       +
       +        follow = mal(maxfollow*sizeof(*follow));
       +        state0 = initstate(topre.beg);
       +
       +        Binit(&bout, 1, OWRITE);
       +        switch(argc) {
       +        case 0:
       +                status = search(0, 0);
       +                break;
       +        case 1:
       +                status = search(argv[0], 0);
       +                break;
       +        default:
       +                status = 0;
       +                for(i=0; i<argc; i++)
       +                        status |= search(argv[i], Hflag);
       +                break;
       +        }
       +        if(status)
       +                exits(0);
       +        exits("no matches");
       +}
       +
       +int
       +search(char *file, int flag)
       +{
       +        State *s, *ns;
       +        int c, fid, eof, nl, empty;
       +        long count, lineno, n;
       +        uchar *elp, *lp, *bol;
       +
       +        if(file == 0) {
       +                file = "stdin";
       +                fid = 0;
       +                flag |= Bflag;
       +        } else
       +                fid = open(file, OREAD);
       +
       +        if(fid < 0) {
       +                fprint(2, "grep: can't open %s: %r\n", file);
       +                return 0;
       +        }
       +
       +        if(flags['b'])
       +                flag ^= Bflag;                /* dont buffer output */
       +        if(flags['c'])
       +                flag |= Cflag;                /* count */
       +        if(flags['h'])
       +                flag &= ~Hflag;                /* do not print file name in output */
       +        if(flags['i'])
       +                flag |= Iflag;                /* fold upper-lower */
       +        if(flags['l'])
       +                flag |= Llflag;                /* print only name of file if any match */
       +        if(flags['L'])
       +                flag |= LLflag;                /* print only name of file if any non match */
       +        if(flags['n'])
       +                flag |= Nflag;                /* count only */
       +        if(flags['s'])
       +                flag |= Sflag;                /* status only */
       +        if(flags['v'])
       +                flag |= Vflag;                /* inverse match */
       +
       +        s = state0;
       +        lineno = 0;
       +        count = 0;
       +        eof = 0;
       +        empty = 1;
       +        nl = 0;
       +        lp = u.buf;
       +        bol = lp;
       +
       +loop0:
       +        n = lp-bol;
       +        if(n > sizeof(u.pre))
       +                n = sizeof(u.pre);
       +        memmove(u.buf-n, bol, n);
       +        bol = u.buf-n;
       +        n = read(fid, u.buf, sizeof(u.buf));
       +        /* if file has no final newline, simulate one to emit matches to last line */
       +        if(n > 0) {
       +                empty = 0;
       +                nl = u.buf[n-1]=='\n';
       +        } else {
       +                if(n < 0){
       +                        fprint(2, "grep: read error on %s: %r\n", file);
       +                        return count != 0;
       +                }
       +                if(!eof && !nl && !empty) {
       +                        u.buf[0] = '\n';
       +                        n = 1;
       +                        eof = 1;
       +                }
       +        }
       +        if(n <= 0) {
       +                close(fid);
       +                if(flag & Cflag) {
       +                        if(flag & Hflag)
       +                                Bprint(&bout, "%s:", file);
       +                        Bprint(&bout, "%ld\n", count);
       +                }
       +                if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
       +                        Bprint(&bout, "%s\n", file);
       +                Bflush(&bout);
       +                return count != 0;
       +        }
       +        lp = u.buf;
       +        elp = lp+n;
       +        if(flag & Iflag)
       +                goto loopi;
       +
       +/*
       + * normal character loop
       + */
       +loop:
       +        c = *lp;
       +        ns = s->next[c];
       +        if(ns == 0) {
       +                increment(s, c);
       +                goto loop;
       +        }
       +//        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') {
       +                lineno++;
       +                if(!!s->match == !(flag&Vflag)) {
       +                        count++;
       +                        if(flag & (Cflag|Sflag|Llflag|LLflag))
       +                                goto cont;
       +                        if(flag & Hflag)
       +                                Bprint(&bout, "%s:", file);
       +                        if(flag & Nflag)
       +                                Bprint(&bout, "%ld: ", lineno);
       +                        /* suppress extra newline at EOF unless we are labeling matches with file name */
       +                        Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
       +                        if(flag & Bflag)
       +                                Bflush(&bout);
       +                }
       +                if((lineno & Flshcnt) == 0)
       +                        Bflush(&bout);
       +        cont:
       +                bol = lp;
       +        }
       +        if(lp != elp)
       +                goto loop;
       +        goto loop0;
       +
       +/*
       + * character loop for -i flag
       + * for speed
       + */
       +loopi:
       +        c = *lp;
       +        if(c >= 'A' && c <= 'Z')
       +                c += 'a'-'A';
       +        ns = s->next[c];
       +        if(ns == 0) {
       +                increment(s, c);
       +                goto loopi;
       +        }
       +        lp++;
       +        s = ns;
       +        if(c == '\n') {
       +                lineno++;
       +                if(!!s->match == !(flag&Vflag)) {
       +                        count++;
       +                        if(flag & (Cflag|Sflag|Llflag|LLflag))
       +                                goto conti;
       +                        if(flag & Hflag)
       +                                Bprint(&bout, "%s:", file);
       +                        if(flag & Nflag)
       +                                Bprint(&bout, "%ld: ", lineno);
       +                        /* suppress extra newline at EOF unless we are labeling matches with file name */
       +                        Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
       +                        if(flag & Bflag)
       +                                Bflush(&bout);
       +                }
       +                if((lineno & Flshcnt) == 0)
       +                        Bflush(&bout);
       +        conti:
       +                bol = lp;
       +        }
       +        if(lp != elp)
       +                goto loopi;
       +        goto loop0;
       +}
       +
       +State*
       +initstate(Re *r)
       +{
       +        State *s;
       +        int i;
       +
       +        addcase(r);
       +        if(flags['1'])
       +                reprint("r", r);
       +        nfollow = 0;
       +        gen++;
       +        fol1(r, Cbegin);
       +        follow[nfollow++] = r;
       +        qsort(follow, nfollow, sizeof(*follow), fcmp);
       +
       +        s = sal(nfollow);
       +        for(i=0; i<nfollow; i++)
       +                s->re[i] = follow[i];
       +        return s;
       +}
 (DIR) diff --git a/src/cmd/grep/mkfile b/src/cmd/grep/mkfile
       t@@ -0,0 +1,20 @@
       +PLAN9=../../..
       +<$PLAN9/src/mkhdr
       +
       +# Calling this grep breaks a LOT.  Like egrep on Linux.
       +# And probably configure.
       +
       +TARG=9grep
       +HFILES=\
       +        grep.h\
       +
       +OFILES=\
       +        y.tab.$O\
       +        main.$O\
       +        comp.$O\
       +        sub.$O\
       +
       +YFILES=grep.y\
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
 (DIR) diff --git a/src/cmd/grep/sub.c b/src/cmd/grep/sub.c
       t@@ -0,0 +1,317 @@
       +#include        "grep.h"
       +
       +void*
       +mal(int n)
       +{
       +        static char *s;
       +        static int m = 0;
       +        void *v;
       +
       +        n = (n+3) & ~3;
       +        if(m < n) {
       +                if(n > Nhunk) {
       +                        v = sbrk(n);
       +                        memset(v, 0, n);
       +                        return v;
       +                }
       +                s = sbrk(Nhunk);
       +                m = Nhunk;
       +        }
       +        v = s;
       +        s += n;
       +        m -= n;
       +        memset(v, 0, n);
       +        return v;
       +}
       +
       +State*
       +sal(int n)
       +{
       +        State *s;
       +
       +        s = mal(sizeof(*s));
       +//        s->next = mal(256*sizeof(*s->next));
       +        s->count = n;
       +        s->re = mal(n*sizeof(*state0->re));
       +        return s;
       +}
       +
       +Re*
       +ral(int type)
       +{
       +        Re *r;
       +
       +        r = mal(sizeof(*r));
       +        r->type = type;
       +        maxfollow++;
       +        return r;
       +}
       +
       +void
       +error(char *s)
       +{
       +        fprint(2, "grep: internal error: %s\n", s);
       +        exits(s);
       +}
       +
       +int
       +countor(Re *r)
       +{
       +        int n;
       +
       +        n = 0;
       +loop:
       +        switch(r->type) {
       +        case Tor:
       +                n += countor(r->alt);
       +                r = r->next;
       +                goto loop;
       +        case Tclass:
       +                return n + r->hi - r->lo + 1;
       +        }
       +        return n;
       +}
       +
       +Re*
       +oralloc(int t, Re *r, Re *b)
       +{
       +        Re *a;
       +
       +        if(b == 0)
       +                return r;
       +        a = ral(t);
       +        a->alt = r;
       +        a->next = b;
       +        return a;
       +}
       +
       +void
       +case1(Re *c, Re *r)
       +{
       +        int n;
       +
       +loop:
       +        switch(r->type) {
       +        case Tor:
       +                case1(c, r->alt);
       +                r = r->next;
       +                goto loop;
       +
       +        case Tclass:        /* add to character */
       +                for(n=r->lo; n<=r->hi; n++)
       +                        c->cases[n] = oralloc(Tor, r->next, c->cases[n]);
       +                break;
       +
       +        default:        /* add everything unknown to next */
       +                c->next = oralloc(Talt, r, c->next);
       +                break;
       +        }
       +}
       +
       +Re*
       +addcase(Re *r)
       +{
       +        int i, n;
       +        Re *a;
       +
       +        if(r->gen == gen)
       +                return r;
       +        r->gen = gen;
       +        switch(r->type) {
       +        default:
       +                error("addcase");
       +
       +        case Tor:
       +                n = countor(r);
       +                if(n >= Caselim) {
       +                        a = ral(Tcase);
       +                        a->cases = mal(256*sizeof(*a->cases));
       +                        case1(a, r);
       +                        for(i=0; i<256; i++)
       +                                if(a->cases[i]) {
       +                                        r = a->cases[i];
       +                                        if(countor(r) < n)
       +                                                a->cases[i] = addcase(r);
       +                                }
       +                        return a;
       +                }
       +                return r;
       +
       +        case Talt:
       +                r->next = addcase(r->next);
       +                r->alt = addcase(r->alt);
       +                return r;
       +
       +        case Tbegin:
       +        case Tend:
       +        case Tclass:
       +                return r;
       +        }
       +}
       +
       +void
       +str2top(char *p)
       +{
       +        Re2 oldtop;
       +
       +        oldtop = topre;
       +        input = p;
       +        topre.beg = 0;
       +        topre.end = 0;
       +        yyparse();
       +        gen++;
       +        if(topre.beg == 0)
       +                yyerror("syntax");
       +        if(oldtop.beg)
       +                topre = re2or(oldtop, topre);
       +}
       +
       +void
       +appendnext(Re *a, Re *b)
       +{
       +        Re *n;
       +
       +        while(n = a->next)
       +                a = n;
       +        a->next = b;
       +}
       +
       +void
       +patchnext(Re *a, Re *b)
       +{
       +        Re *n;
       +
       +        while(a) {
       +                n = a->next;
       +                a->next = b;
       +                a = n;
       +        }
       +}
       +
       +int
       +getrec(void)
       +{
       +        int c;
       +
       +        if(flags['f']) {
       +                c = Bgetc(rein);
       +                if(c <= 0)
       +                        return 0;
       +        } else
       +                c = *input++ & 0xff;
       +        if(flags['i'] && c >= 'A' && c <= 'Z')
       +                c += 'a'-'A';
       +        if(c == '\n')
       +                lineno++;
       +        return c;
       +}
       +
       +Re2
       +re2cat(Re2 a, Re2 b)
       +{
       +        Re2 c;
       +
       +        c.beg = a.beg;
       +        c.end = b.end;
       +        patchnext(a.end, b.beg);
       +        return c;
       +}
       +
       +Re2
       +re2star(Re2 a)
       +{
       +        Re2 c;
       +
       +        c.beg = ral(Talt);
       +        c.beg->alt = a.beg;
       +        patchnext(a.end, c.beg);
       +        c.end = c.beg;
       +        return c;
       +}
       +
       +Re2
       +re2or(Re2 a, Re2 b)
       +{
       +        Re2 c;
       +
       +        c.beg = ral(Tor);
       +        c.beg->alt = b.beg;
       +        c.beg->next = a.beg;
       +        c.end = b.end;
       +        appendnext(c.end,  a.end);
       +        return c;
       +}
       +
       +Re2
       +re2char(int c0, int c1)
       +{
       +        Re2 c;
       +
       +        c.beg = ral(Tclass);
       +        c.beg->lo = c0 & 0xff;
       +        c.beg->hi = c1 & 0xff;
       +        c.end = c.beg;
       +        return c;
       +}
       +
       +void
       +reprint1(Re *a)
       +{
       +        int i, j;
       +
       +loop:
       +        if(a == 0)
       +                return;
       +        if(a->gen == gen)
       +                return;
       +        a->gen = gen;
       +        print("%p: ", a);
       +        switch(a->type) {
       +        default:
       +                print("type %d\n", a->type);
       +                error("print1 type");
       +
       +        case Tcase:
       +                print("case ->%p\n", a->next);
       +                for(i=0; i<256; i++)
       +                        if(a->cases[i]) {
       +                                for(j=i+1; j<256; j++)
       +                                        if(a->cases[i] != a->cases[j])
       +                                                break;
       +                                print("        [%.2x-%.2x] ->%p\n", i, j-1, a->cases[i]);
       +                                i = j-1;
       +                        }
       +                for(i=0; i<256; i++)
       +                        reprint1(a->cases[i]);
       +                break;
       +
       +        case Tbegin:
       +                print("^ ->%p\n", a->next);
       +                break;
       +
       +        case Tend:
       +                print("$ ->%p\n", a->next);
       +                break;
       +
       +        case Tclass:
       +                print("[%.2x-%.2x] ->%p\n", a->lo, a->hi, a->next);
       +                break;
       +
       +        case Tor:
       +        case Talt:
       +                print("| %p ->%p\n", a->alt, a->next);
       +                reprint1(a->alt);
       +                break;
       +        }
       +        a = a->next;
       +        goto loop;
       +}
       +
       +void
       +reprint(char *s, Re *r)
       +{
       +        print("%s:\n", s);
       +        gen++;
       +        reprint1(r);
       +        print("\n\n");
       +}
 (DIR) diff --git a/src/cmd/mkfile b/src/cmd/mkfile
       t@@ -3,11 +3,11 @@ PLAN9=../..
        
        TARG=`ls *.c | sed 's/\.c//'`
        LDFLAGS=$LDFLAGS
       -SHORTLIB=sec fs mux regexp9 thread bio 9
       +SHORTLIB=mach sec fs mux regexp9 thread bio 9
        
        <$PLAN9/src/mkmany
        
       -BUGGERED='CVS|9term|faces|factotum|htmlfmt|mk|rio|upas|vac|venti'
       +BUGGERED='CVS|faces|factotum|htmlfmt|mk|upas|vac|venti'
        DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
        
        <$PLAN9/src/mkdirs
 (DIR) diff --git a/src/cmd/plumb/fsys.c b/src/cmd/plumb/fsys.c
       t@@ -97,6 +97,7 @@ static Dirtab dir[NDIR] =
        static int        ndir = NQID;
        
        static int                srvfd;
       +#define clock plumbclock        /* SunOS name clash */
        static int                clock;
        static Fid                *fids[Nhash];
        static QLock        readlock;
 (DIR) diff --git a/src/cmd/plumb/plumber.c b/src/cmd/plumb/plumber.c
       t@@ -54,9 +54,10 @@ threadmain(int argc, char *argv[])
                        error("can't initialize $user or $home: %r");
                if(plumbfile == nil){
                        sprint(buf, "%s/lib/plumbing", home);
       -                if(access(buf, 0) < 0)
       -                        sprint(buf, "#9/plumb/initial.plumbing");
       -                plumbfile = estrdup(buf);
       +                if(access(buf, 0) >= 0)
       +                        plumbfile = estrdup(buf);
       +                else
       +                        plumbfile = unsharp("#9/plumb/initial.plumbing");
                }
        
                fd = open(plumbfile, OREAD);
 (DIR) diff --git a/src/cmd/plumb/rules.c b/src/cmd/plumb/rules.c
       t@@ -415,7 +415,7 @@ include(char *s)
                fd = open(t, OREAD);
                if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
                        snprint(buf, sizeof buf, "#9/plumb/%s", t);
       -                t = buf;
       +                t = unsharp(buf);
                        fd = open(t, OREAD);
                }
                if(fd < 0)
 (DIR) diff --git a/src/cmd/rc/plan9ish.c b/src/cmd/rc/plan9ish.c
       t@@ -27,20 +27,10 @@ char *syssigname[]={
        char*
        Rcmain(void)
        {
       -        return "#9/rcmain";
       -/*
       -        static char buf[256];
       -        char *root;
       -
       -        root = getenv("PLAN9");
       -        if(root == nil)
       -                root = "/usr/local/plan9";
       -        snprint(buf, sizeof buf, "%s/rcmain", root);
       -        return buf;
       -*/
       +        return unsharp("#9/rcmain");
        }
        
       -char Fdprefix[]="#d/";
       +char Fdprefix[]="/dev/fd/";
        void execfinit(void);
        void execbind(void);
        void execmount(void);
 (DIR) diff --git a/src/cmd/rio/Imakefile b/src/cmd/rio/Imakefile
       t@@ -0,0 +1,27 @@
       +INCLUDES = -I$(TOP)
       +DEPLIBS = $(DEPXLIB)
       +LOCAL_LIBRARIES = $(XLIB)
       +DEFINES = -DSHAPE # -g3 -DDEBUG -DDEBUG_EV
       +SRCS = main.c event.c manage.c menu.c client.c grab.c cursor.c error.c color.c
       +OBJS = main.o event.o manage.o menu.o client.o grab.o cursor.o error.o color.o
       +HFILES = dat.h fns.h patchlevel.h
       +MFILES = README 9wm.man Imakefile Makefile.no-imake
       +
       +ComplexProgramTarget(rio)
       +
       +bun:
       +        bundle $(MFILES) $(SRCS) $(HFILES) >bun
       +
       +dist:
       +        bundle $(MFILES) main.c event.c manage.c >bun1
       +        bundle menu.c client.c grab.c cursor.c error.c $(HFILES) >bun2
       +
       +trout: 9wm.man
       +        troff -man 9wm.man >trout
       +
       +vu: trout
       +        xditview trout
       +
       +clean::
       +        $(RM) bun bun[12] trout core
       +
 (DIR) diff --git a/src/cmd/rio/color.c b/src/cmd/rio/color.c
       t@@ -8,7 +8,7 @@
        #include "fns.h"
        
        unsigned long
       -colorpixel(Display *dpy, int depth, ulong rgb)
       +colorpixel(Display *dpy, int depth, unsigned long rgb)
        {
                int r, g, b;
        
 (DIR) diff --git a/src/cmd/rio/main.c b/src/cmd/rio/main.c
       t@@ -9,6 +9,9 @@
        #include <X11/Xlib.h>
        #include <X11/Xutil.h>
        #include <X11/Xatom.h>
       +#ifdef SHAPE
       +#include <X11/extensions/shape.h>
       +#endif
        #include "dat.h"
        #include "fns.h"
        #include "patchlevel.h"
       t@@ -70,12 +73,15 @@ main(int argc, char *argv[])
                int i, background, do_exit, do_restart;
                char *fname;
                int shape_event;
       +#ifdef SHAPE
       +        int dummy;
       +#endif
        
                shape_event = 0;
                myargv = argv;                        /* for restart */
        
                do_exit = do_restart = 0;
       -        background = 1;
       +        background = 0;
                font = 0;
                fname = 0;
                for (i = 1; i < argc; i++)
       t@@ -289,12 +295,11 @@ initscreen(ScreenInfo *s, int i, int background)
                XSync(dpy, False);
        
                if (background) {
       -/*
                        XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
                        XClearWindow(dpy, s->root);
       -*/
       +        } else
                        system("xsetroot -solid grey30");
       -        }
       +
                s->menuwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 2, colorpixel(dpy, s->depth, 0x88CC88), colorpixel(dpy, s->depth, 0xE9FFE9));
                s->sweepwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 4, s->red, colorpixel(dpy, s->depth, 0xEEEEEE));
        }
 (DIR) diff --git a/src/cmd/rio/mkfile b/src/cmd/rio/mkfile
       t@@ -1,3 +1,4 @@
       +PLAN9=../../..
        <$PLAN9/src/mkhdr
        
        OFILES=\
       t@@ -18,3 +19,7 @@ TARG=rio
        LDFLAGS=-L$X11/lib -lXext -lX11
        
        <$PLAN9/src/mkone
       +
       +CFLAGS=$CFLAGS -DSHAPE -I$X11/include
       +
       +
 (DIR) diff --git a/src/cmd/spell/sprog.c b/src/cmd/spell/sprog.c
       t@@ -460,6 +460,9 @@ main(int argc, char *argv[])
                int low;
                Bits h;
        
       +        codefile = unsharp(codefile);
       +        brfile = unsharp(brfile);
       +
                Binit(&bin, 0, OREAD);
                Binit(&bout, 1, OWRITE);
                for(i=0; c = "aeiouyAEIOUY"[i]; i++)
 (DIR) diff --git a/src/cmd/win.c b/src/cmd/win.c
       t@@ -1,717 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include <fcall.h>
       -#include <fs.h>
       -
       -#define        EVENTSIZE        256
       -#define        STACK        32768
       -
       -typedef struct Event Event;
       -typedef struct Q Q;
       -
       -struct Event
       -{
       -        int        c1;
       -        int        c2;
       -        int        q0;
       -        int        q1;
       -        int        flag;
       -        int        nb;
       -        int        nr;
       -        char        b[EVENTSIZE*UTFmax+1];
       -        Rune        r[EVENTSIZE+1];
       -};
       -
       -Event blank = {
       -        'M',
       -        'X',
       -        0, 0, 0, 1, 1,
       -        { ' ', 0 },
       -        { ' ', 0 },
       -};
       -
       -struct Q
       -{
       -        QLock        lk;
       -        int                p;
       -        int                k;
       -};
       -
       -Q        q;
       -
       -Fid *eventfd;
       -Fid *addrfd;
       -Fid *datafd;
       -Fid *ctlfd;
       -// int bodyfd;
       -
       -char        *typing;
       -int        ntypeb;
       -int        ntyper;
       -int        ntypebreak;
       -int        debug;
       -char *name;
       -
       -char **prog;
       -int p[2];
       -Channel *cpid;
       -Channel *cwait;
       -int pid = -1;
       -
       -int        label(char*, int);
       -void        error(char*);
       -void        stdinproc(void*);
       -void        stdoutproc(void*);
       -void        type(Event*, int, Fid*, Fid*);
       -void        sende(Event*, int, Fid*, Fid*, Fid*, int);
       -char        *onestring(int, char**);
       -int        delete(Event*);
       -void        deltype(uint, uint);
       -void        runproc(void*);
       -
       -int
       -fsfidprint(Fid *fid, char *fmt, ...)
       -{
       -        char buf[256];
       -        va_list arg;
       -        int n;
       -
       -        va_start(arg, fmt);
       -        n = vsnprint(buf, sizeof buf, fmt, arg);
       -        va_end(arg);
       -        return fswrite(fid, buf, n);
       -}
       -
       -void
       -usage(void)
       -{
       -        fprint(2, "usage: win cmd args...\n");
       -        threadexitsall("usage");
       -}
       -
       -int
       -nopipes(void *v, char *msg)
       -{
       -        USED(v);
       -        if(strcmp(msg, "sys: write on closed pipe") == 0)
       -                return 1;
       -        return 0;
       -}
       -
       -void
       -waitthread(void *v)
       -{
       -        recvp(cwait);
       -        threadexitsall(nil);
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        int fd, id;
       -        char buf[256];
       -        char buf1[128];
       -        Fsys *fs;
       -
       -        ARGBEGIN{
       -        case 'd':
       -                debug = 1;
       -                break;
       -        default:
       -                usage();
       -        }ARGEND
       -
       -        prog = argv;
       -
       -        if(argc > 0)
       -                name = argv[0];
       -        else
       -                name = "gnot";
       -
       -        threadnotify(nopipes, 1);
       -        if((fs = nsmount("acme", "")) < 0)
       -                sysfatal("nsmount acme: %r");
       -        ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
       -        if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
       -                sysfatal("ctl: %r");
       -        id = atoi(buf);
       -        sprint(buf, "%d/tag", id);
       -        fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
       -        write(fd, " Send Delete", 12);
       -        close(fd);
       -        sprint(buf, "%d/event", id);
       -        eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
       -        sprint(buf, "%d/addr", id);
       -        addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
       -        sprint(buf, "%d/data", id);
       -        datafd = fsopen(fs, buf, ORDWR|OCEXEC);
       -        sprint(buf, "%d/body", id);
       -/*        bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
       -        if(eventfd==nil || addrfd==nil || datafd==nil)
       -                sysfatal("data files: %r");
       -/*
       -        if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
       -                sysfatal("data files: %r");
       -*/
       -        fsunmount(fs);
       -
       -        if(pipe(p) < 0)
       -                sysfatal("pipe: %r");
       -
       -        cpid = chancreate(sizeof(ulong), 1);
       -        cwait = threadwaitchan();
       -        threadcreate(waitthread, nil, STACK);
       -        threadcreate(runproc, nil, STACK);
       -        pid = recvul(cpid);
       -        if(pid == -1)
       -                sysfatal("exec failed");
       -
       -        getwd(buf1, sizeof buf1);
       -        sprint(buf, "name %s/-%s\n0\n", buf1, name);
       -        fswrite(ctlfd, buf, strlen(buf));
       -        sprint(buf, "dumpdir %s/\n", buf1);
       -        fswrite(ctlfd, buf, strlen(buf));
       -        sprint(buf, "dump %s\n", onestring(argc, argv));
       -        fswrite(ctlfd, buf, strlen(buf));
       -        
       -        threadcreate(stdoutproc, nil, STACK);
       -        stdinproc(nil);
       -}
       -
       -char *shell[] = { "rc", "-i", 0 };
       -void
       -runproc(void *v)
       -{
       -        int fd[3];
       -        char *sh;
       -
       -        USED(v);
       -
       -        fd[0] = p[1];
       -//        fd[1] = bodyfd;
       -//        fd[2] = bodyfd;
       -        fd[1] = p[1];
       -        fd[2] = p[1];
       -
       -        if(prog[0] == nil){
       -                prog = shell;
       -                if((sh = getenv("SHELL")) != nil)
       -                        shell[0] = sh;
       -        }
       -        threadexec(cpid, fd, prog[0], prog);
       -        threadexits(nil);
       -}
       -
       -void
       -error(char *s)
       -{
       -        if(s)
       -                fprint(2, "win: %s: %r\n", s);
       -        else
       -                s = "kill";
       -        if(pid != -1)
       -                postnote(PNGROUP, pid, "hangup");
       -        threadexitsall(s);
       -}
       -
       -char*
       -onestring(int argc, char **argv)
       -{
       -        char *p;
       -        int i, n;
       -        static char buf[1024];
       -
       -        if(argc == 0)
       -                return "";
       -        p = buf;
       -        for(i=0; i<argc; i++){
       -                n = strlen(argv[i]);
       -                if(p+n+1 >= buf+sizeof buf)
       -                        break;
       -                memmove(p, argv[i], n);
       -                p += n;
       -                *p++ = ' ';
       -        }
       -        p[-1] = 0;
       -        return buf;
       -}
       -
       -int
       -getec(Fid *efd)
       -{
       -        static char buf[8192];
       -        static char *bufp;
       -        static int nbuf;
       -
       -        if(nbuf == 0){
       -                nbuf = fsread(efd, buf, sizeof buf);
       -                if(nbuf <= 0)
       -                        error(nil);
       -                bufp = buf;
       -        }
       -        --nbuf;
       -        return *bufp++;
       -}
       -
       -int
       -geten(Fid *efd)
       -{
       -        int n, c;
       -
       -        n = 0;
       -        while('0'<=(c=getec(efd)) && c<='9')
       -                n = n*10+(c-'0');
       -        if(c != ' ')
       -                error("event number syntax");
       -        return n;
       -}
       -
       -int
       -geter(Fid *efd, char *buf, int *nb)
       -{
       -        Rune r;
       -        int n;
       -
       -        r = getec(efd);
       -        buf[0] = r;
       -        n = 1;
       -        if(r < Runeself)
       -                goto Return;
       -        while(!fullrune(buf, n))
       -                buf[n++] = getec(efd);
       -        chartorune(&r, buf);
       -    Return:
       -        *nb = n;
       -        return r;
       -}
       -
       -void
       -gete(Fid *efd, Event *e)
       -{
       -        int i, nb;
       -
       -        e->c1 = getec(efd);
       -        e->c2 = getec(efd);
       -        e->q0 = geten(efd);
       -        e->q1 = geten(efd);
       -        e->flag = geten(efd);
       -        e->nr = geten(efd);
       -        if(e->nr > EVENTSIZE)
       -                error("event string too long");
       -        e->nb = 0;
       -        for(i=0; i<e->nr; i++){
       -                e->r[i] = geter(efd, e->b+e->nb, &nb);
       -                e->nb += nb;
       -        }
       -        e->r[e->nr] = 0;
       -        e->b[e->nb] = 0;
       -        if(getec(efd) != '\n')
       -                error("event syntax 2");
       -}
       -
       -int
       -nrunes(char *s, int nb)
       -{
       -        int i, n;
       -        Rune r;
       -
       -        n = 0;
       -        for(i=0; i<nb; n++)
       -                i += chartorune(&r, s+i);
       -        return n;
       -}
       -
       -void
       -stdinproc(void *v)
       -{
       -        Fid *cfd = ctlfd;
       -        Fid *efd = eventfd;
       -        Fid *dfd = datafd;
       -        Fid *afd = addrfd;
       -        int fd0 = p[0];
       -        Event e, e2, e3, e4;
       -
       -        USED(v);
       -
       -        for(;;){
       -                if(debug)
       -                        fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
       -                gete(efd, &e);
       -                if(debug)
       -                        fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
       -                qlock(&q.lk);
       -                switch(e.c1){
       -                default:
       -                Unknown:
       -                        print("unknown message %c%c\n", e.c1, e.c2);
       -                        break;
       -
       -                case 'E':        /* write to body; can't affect us */
       -                        if(debug)
       -                                fprint(2, "shift typing %d... ", e.q1-e.q0);
       -                        q.p += e.q1-e.q0;
       -                        break;
       -
       -                case 'F':        /* generated by our actions; ignore */
       -                        break;
       -
       -                case 'K':
       -                case 'M':
       -                        switch(e.c2){
       -                        case 'I':
       -                                if(e.q0 < q.p){
       -                                        if(debug)
       -                                                fprint(2, "shift typing %d... ", e.q1-e.q0);
       -                                        q.p += e.q1-e.q0;
       -                                }
       -                                else if(e.q0 <= q.p+ntyper){
       -                                        if(debug)
       -                                                fprint(2, "type... ");
       -                                        type(&e, fd0, afd, dfd);
       -                                }
       -                                break;
       -
       -                        case 'D':
       -                                q.p -= delete(&e);
       -                                break;
       -
       -                        case 'x':
       -                        case 'X':
       -                                if(e.flag & 2)
       -                                        gete(efd, &e2);
       -                                if(e.flag & 8){
       -                                        gete(efd, &e3);
       -                                        gete(efd, &e4);
       -                                }
       -                                if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
       -                                        /* send it straight back */
       -                                        fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
       -                                        break;
       -                                }
       -                                if(e.q0==e.q1 && (e.flag&2)){
       -                                        e2.flag = e.flag;
       -                                        e = e2;
       -                                }
       -                                if(e.flag & 8){
       -                                        if(e.q1 != e.q0){
       -                                                sende(&e, fd0, cfd, afd, dfd, 0);
       -                                                sende(&blank, fd0, cfd, afd, dfd, 0);
       -                                        }
       -                                        sende(&e3, fd0, cfd, afd, dfd, 1);
       -                                }else         if(e.q1 != e.q0)
       -                                        sende(&e, fd0, cfd, afd, dfd, 1);
       -                                break;
       -
       -                        case 'l':
       -                        case 'L':
       -                                /* just send it back */
       -                                if(e.flag & 2)
       -                                        gete(efd, &e2);
       -                                fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
       -                                break;
       -
       -                        case 'd':
       -                        case 'i':
       -                                break;
       -
       -                        default:
       -                                goto Unknown;
       -                        }
       -                }
       -                qunlock(&q.lk);
       -        }
       -}
       -
       -void
       -stdoutproc(void *v)
       -{
       -        int fd1 = p[0];
       -        Fid *afd = addrfd;
       -        Fid *dfd = datafd;
       -        int n, m, w, npart;
       -        char *buf, *s, *t;
       -        Rune r;
       -        char x[16], hold[UTFmax];
       -
       -        USED(v);
       -        threadnotify(nopipes, 1);
       -        buf = malloc(8192+UTFmax+1);
       -        npart = 0;
       -        for(;;){
       -                n = threadread(fd1, buf+npart, 8192);
       -                if(n < 0)
       -                        error(nil);
       -                if(n == 0)
       -                        continue;
       -
       -                /* squash NULs */
       -                s = memchr(buf+npart, 0, n);
       -                if(s){
       -                        for(t=s; s<buf+npart+n; s++)
       -                                if(*t = *s)        /* assign = */
       -                                        t++;
       -                        n = t-(buf+npart);
       -                }
       -
       -                n += npart;
       -
       -                /* hold on to final partial rune */
       -                npart = 0;
       -                while(n>0 && (buf[n-1]&0xC0)){
       -                        --n;
       -                        npart++;
       -                        if((buf[n]&0xC0)!=0x80){
       -                                if(fullrune(buf+n, npart)){
       -                                        w = chartorune(&r, buf+n);
       -                                        n += w;
       -                                        npart -= w;
       -                                }
       -                                break;
       -                        }
       -                }
       -                if(n > 0){
       -                        memmove(hold, buf+n, npart);
       -                        buf[n] = 0;
       -                        n = label(buf, n);
       -                        buf[n] = 0;
       -                        qlock(&q.lk);
       -                        m = sprint(x, "#%d", q.p);
       -                        if(fswrite(afd, x, m) != m)
       -                                error("stdout writing address");
       -                        if(fswrite(dfd, buf, n) != n)
       -                                error("stdout writing body");
       -                        q.p += nrunes(buf, n);
       -                        qunlock(&q.lk);
       -                        memmove(buf, hold, npart);
       -                }
       -        }
       -}
       -
       -char wdir[256];
       -int
       -label(char *sr, int n)
       -{
       -        char *sl, *el, *er, *r;
       -
       -        er = sr+n;
       -        for(r=er-1; r>=sr; r--)
       -                if(*r == '\007')
       -                        break;
       -        if(r < sr)
       -                return n;
       -
       -        el = r+1;
       -        if(el-sr > sizeof wdir)
       -                sr = el - sizeof wdir;
       -        for(sl=el-3; sl>=sr; sl--)
       -                if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
       -                        break;
       -        if(sl < sr)
       -                return n;
       -
       -        *r = 0;
       -        snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
       -        fswrite(ctlfd, wdir, strlen(wdir));
       -
       -        memmove(sl, el, er-el);
       -        n -= (el-sl);
       -        return n;
       -}
       -
       -int
       -delete(Event *e)
       -{
       -        uint q0, q1;
       -        int deltap;
       -
       -        q0 = e->q0;
       -        q1 = e->q1;
       -        if(q1 <= q.p)
       -                return e->q1-e->q0;
       -        if(q0 >= q.p+ntyper)
       -                return 0;
       -        deltap = 0;
       -        if(q0 < q.p){
       -                deltap = q.p-q0;
       -                q0 = 0;
       -        }else
       -                q0 -= q.p;
       -        if(q1 > q.p+ntyper)
       -                q1 = ntyper;
       -        else
       -                q1 -= q.p;
       -        deltype(q0, q1);
       -        return deltap;
       -}
       -
       -void
       -addtype(int c, uint p0, char *b, int nb, int nr)
       -{
       -        int i, w;
       -        Rune r;
       -        uint p;
       -        char *b0;
       -
       -        for(i=0; i<nb; i+=w){
       -                w = chartorune(&r, b+i);
       -                if((r==0x7F||r==3) && c=='K'){
       -                        postnote(PNGROUP, pid, "interrupt");
       -                        /* toss all typing */
       -                        q.p += ntyper+nr;
       -                        ntypebreak = 0;
       -                        ntypeb = 0;
       -                        ntyper = 0;
       -                        /* buglet:  more than one delete ignored */
       -                        return;
       -                }
       -                if(r=='\n' || r==0x04)
       -                        ntypebreak++;
       -        }
       -        typing = realloc(typing, ntypeb+nb);
       -        if(typing == nil)
       -                error("realloc");
       -        if(p0 == ntyper)
       -                memmove(typing+ntypeb, b, nb);
       -        else{
       -                b0 = typing;
       -                for(p=0; p<p0 && b0<typing+ntypeb; p++){
       -                        w = chartorune(&r, b0+i);
       -                        b0 += w;
       -                }
       -                if(p != p0)
       -                        error("typing: findrune");
       -                memmove(b0+nb, b0, (typing+ntypeb)-b0);
       -                memmove(b0, b, nb);
       -        }
       -        ntypeb += nb;
       -        ntyper += nr;
       -}
       -
       -void
       -sendtype(int fd0)
       -{
       -        int i, n, nr;
       -
       -        while(ntypebreak){
       -                for(i=0; i<ntypeb; i++)
       -                        if(typing[i]=='\n' || typing[i]==0x04){
       -                                n = i + (typing[i] == '\n');
       -                                i++;
       -                                if(write(fd0, typing, n) != n)
       -                                        error("sending to program");
       -                                nr = nrunes(typing, i);
       -                                q.p += nr;
       -                                ntyper -= nr;
       -                                ntypeb -= i;
       -                                memmove(typing, typing+i, ntypeb);
       -                                ntypebreak--;
       -                                goto cont2;
       -                        }
       -                print("no breakchar\n");
       -                ntypebreak = 0;
       -cont2:;
       -        }
       -}
       -
       -void
       -deltype(uint p0, uint p1)
       -{
       -        int w;
       -        uint p, b0, b1;
       -        Rune r;
       -
       -        /* advance to p0 */
       -        b0 = 0;
       -        for(p=0; p<p0 && b0<ntypeb; p++){
       -                w = chartorune(&r, typing+b0);
       -                b0 += w;
       -        }
       -        if(p != p0)
       -                error("deltype 1");
       -        /* advance to p1 */
       -        b1 = b0;
       -        for(; p<p1 && b1<ntypeb; p++){
       -                w = chartorune(&r, typing+b1);
       -                b1 += w;
       -                if(r=='\n' || r==0x04)
       -                        ntypebreak--;
       -        }
       -        if(p != p1)
       -                error("deltype 2");
       -        memmove(typing+b0, typing+b1, ntypeb-b1);
       -        ntypeb -= b1-b0;
       -        ntyper -= p1-p0;
       -}
       -
       -void
       -type(Event *e, int fd0, Fid *afd, Fid *dfd)
       -{
       -        int m, n, nr;
       -        char buf[128];
       -
       -        if(e->nr > 0)
       -                addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
       -        else{
       -                m = e->q0;
       -                while(m < e->q1){
       -                        n = sprint(buf, "#%d", m);
       -                        fswrite(afd, buf, n);
       -                        n = fsread(dfd, buf, sizeof buf);
       -                        nr = nrunes(buf, n);
       -                        while(m+nr > e->q1){
       -                                do; while(n>0 && (buf[--n]&0xC0)==0x80);
       -                                --nr;
       -                        }
       -                        if(n == 0)
       -                                break;
       -                        addtype(e->c1, m-q.p, buf, n, nr);
       -                        m += nr;
       -                }
       -        }
       -        sendtype(fd0);
       -}
       -
       -void
       -sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
       -{
       -        int l, m, n, nr, lastc, end;
       -        char abuf[16], buf[128];
       -
       -        end = q.p+ntyper;
       -        l = sprint(abuf, "#%d", end);
       -        fswrite(afd, abuf, l);
       -        if(e->nr > 0){
       -                fswrite(dfd, e->b, e->nb);
       -                addtype(e->c1, ntyper, e->b, e->nb, e->nr);
       -                lastc = e->r[e->nr-1];
       -        }else{
       -                m = e->q0;
       -                lastc = 0;
       -                while(m < e->q1){
       -                        n = sprint(buf, "#%d", m);
       -                        fswrite(afd, buf, n);
       -                        n = fsread(dfd, buf, sizeof buf);
       -                        nr = nrunes(buf, n);
       -                        while(m+nr > e->q1){
       -                                do; while(n>0 && (buf[--n]&0xC0)==0x80);
       -                                --nr;
       -                        }
       -                        if(n == 0)
       -                                break;
       -                        l = sprint(abuf, "#%d", end);
       -                        fswrite(afd, abuf, l);
       -                        fswrite(dfd, buf, n);
       -                        addtype(e->c1, ntyper, buf, n, nr);
       -                        lastc = buf[n-1];
       -                        m += nr;
       -                        end += nr;
       -                }
       -        }
       -        if(donl && lastc!='\n'){
       -                fswrite(dfd, "\n", 1);
       -                addtype(e->c1, ntyper, "\n", 1, 1);
       -        }
       -        fswrite(cfd, "dot=addr", 8);
       -        sendtype(fd0);
       -}
 (DIR) diff --git a/src/cmd/yacc.c b/src/cmd/yacc.c
       t@@ -399,7 +399,7 @@ others(void)
        {
                int c, i, j;
        
       -        finput = Bopen(parser, OREAD);
       +        finput = Bopen(unsharp(parser), OREAD);
                if(finput == 0)
                        error("cannot open parser %s: %r", parser);
                warray("yyr1", levprd, nprod);
 (DIR) diff --git a/src/lib9/_p9translate.c b/src/lib9/_p9translate.c
       t@@ -14,7 +14,7 @@ static struct {
        };
        
        char*
       -_p9translate(char *old)
       +plan9translate(char *old)
        {
                char *new;
                int i, olen, nlen, len;
       t@@ -36,7 +36,7 @@ _p9translate(char *old)
                        len = strlen(old)+nlen-olen;
                        new = malloc(len+1);
                        if(new == nil)
       -                        return nil;
       +                        return "<out of memory>";
                        strcpy(new, replace[i].new);
                        strcpy(new+nlen, old+olen);
                        assert(strlen(new) == len);
 (DIR) diff --git a/src/lib9/access.c b/src/lib9/access.c
       t@@ -1,19 +0,0 @@
       -#include <u.h>
       -#define NOPLAN9DEFINES
       -#include <libc.h>
       -
       -char *_p9translate(char*);
       -
       -int
       -p9access(char *xname, int what)
       -{
       -        int ret;
       -        char *name;
       -
       -        if((name = _p9translate(xname)) == nil)
       -                return -1;
       -        ret = access(name, what);
       -        if(name != xname)
       -                free(name);
       -        return ret;
       -}
 (DIR) diff --git a/src/lib9/announce.c b/src/lib9/announce.c
       t@@ -40,7 +40,8 @@ p9announce(char *addr, char *dir)
                char *net;
                u32int host;
                int port, s;
       -        int n, sn;
       +        int n;
       +        socklen_t sn;
                struct sockaddr_in sa;
                struct sockaddr_un sun;
        
       t@@ -72,7 +73,7 @@ p9announce(char *addr, char *dir)
                if((s = socket(AF_INET, proto, 0)) < 0)
                        return -1;
                sn = sizeof n;
       -        if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&n, &sn) >= 0
       +        if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
                && n == SOCK_STREAM){
                        n = 1;
                        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
 (DIR) diff --git a/src/lib9/create.c b/src/lib9/create.c
       t@@ -3,16 +3,10 @@
        #include <libc.h>
        #include <sys/stat.h>
        
       -extern char *_p9translate(char*);
       -
        int
       -p9create(char *xpath, int mode, ulong perm)
       +p9create(char *path, int mode, ulong perm)
        {
                int fd, cexec, umode, rclose;
       -        char *path;
       -
       -        if((path = _p9translate(xpath)) == nil)
       -                return -1;
        
                cexec = mode&OCEXEC;
                rclose = mode&ORCLOSE;
       t@@ -48,7 +42,5 @@ out:
                        if(rclose)
                                remove(path);
                }
       -        if(path != xpath)
       -                free(path);
                return fd;
        }
 (DIR) diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
       t@@ -15,6 +15,7 @@ ct_numb(char *cp, int n)
        char*
        asctime(Tm *t)
        {
       +        int i;
                char *ncp;
                static char cbuf[30];
        
       t@@ -32,6 +33,12 @@ 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;
 (DIR) diff --git a/src/lib9/date.c b/src/lib9/date.c
       t@@ -1,6 +1,5 @@
       -#include <stdlib.h> /* setenv etc. */
       -
        #include <u.h>
       +#include <stdlib.h> /* setenv etc. */
        #define NOPLAN9DEFINES
        #include <libc.h>
        #include <time.h>
       t@@ -25,6 +24,8 @@ static Tm bigtm;
        static void
        tm2Tm(struct tm *tm, Tm *bigtm)
        {
       +        char *s;
       +
                memset(bigtm, 0, sizeof *bigtm);
                bigtm->sec = tm->tm_sec;
                bigtm->min = tm->tm_min;
       t@@ -39,6 +40,13 @@ tm2Tm(struct tm *tm, Tm *bigtm)
        #ifdef _HAVETZOFF
                bigtm->tzoff = tm->tm_gmtoff;
        #endif
       +        if(bigtm->zone[0] == 0){
       +                s = getenv("TIMEZONE");
       +                if(s){
       +                        strecpy(bigtm->zone, bigtm->zone+4, tm->tm_zone);
       +                        free(s);
       +                }
       +        }
        }
        
        static void
 (DIR) diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
       t@@ -18,7 +18,7 @@ mygetdents(int fd, struct dirent *buf, int n)
                nn = getdirentries(fd, (void*)buf, n, &off);
                return nn;
        }
       -#elif defined(__APPLE__) || defined(__FreeBSD__)
       +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
        static int
        mygetdents(int fd, struct dirent *buf, int n)
        {
       t@@ -171,7 +171,7 @@ dirreadall(int fd, Dir **d)
                        ts += n;
                }
                if(ts >= 0)
       -                ts = dirpackage(fd, buf, ts, d);
       +                ts = dirpackage(fd, (char*)buf, ts, d);
                free(buf);
                if(ts == 0 && n < 0)
                        return -1;
 (DIR) diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
       t@@ -5,9 +5,10 @@
         * okay.
         */
        
       +#include <u.h>
        #include <errno.h>
        #include <string.h>
       -#include <lib9.h>
       +#include <libc.h>
        
        enum
        {
 (DIR) diff --git a/src/lib9/ffork-OpenBSD.c b/src/lib9/ffork-OpenBSD.c
       t@@ -0,0 +1 @@
       +#include "ffork-pthread.c"
 (DIR) diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
       t@@ -1,6 +1,5 @@
       -#include <pwd.h>
       -
        #include <u.h>
       +#include <pwd.h>
        #include <libc.h>
        
        char*
 (DIR) diff --git a/src/lib9/lock.c b/src/lib9/lock.c
       t@@ -1,6 +1,7 @@
       +#include <u.h>
        #include <unistd.h>
        #include <sched.h>
       -#include <lib9.h>
       +#include <libc.h>
        
        int _ntas;
        static int
 (DIR) diff --git a/src/lib9/mallocz.c b/src/lib9/mallocz.c
       t@@ -1,6 +1,7 @@
       +#include <u.h>
        #include <unistd.h>
        #include <string.h>
       -#include <lib9.h>
       +#include <libc.h>
        
        void*
        mallocz(unsigned long n, int clr)
 (DIR) diff --git a/src/lib9/mkfile b/src/lib9/mkfile
       t@@ -69,8 +69,6 @@ LIB9OFILES=\
                _p9dialparse.$O\
                _p9dir.$O\
                _p9proc.$O\
       -        _p9translate.$O\
       -        access.$O\
                announce.$O\
                argv0.$O\
                atexit.$O\
       t@@ -100,6 +98,7 @@ LIB9OFILES=\
                exec.$O\
                fcallfmt.$O\
                ffork-$SYSNAME.$O\
       +        get9root.$O\
                getcallerpc-$OBJTYPE.$O\
                getenv.$O\
                getfields.$O\
       t@@ -142,6 +141,7 @@ LIB9OFILES=\
                u16.$O\
                u32.$O\
                u64.$O\
       +        unsharp.$O\
                wait.$O\
                waitpid.$O\
        
 (DIR) diff --git a/src/lib9/notify.c b/src/lib9/notify.c
       t@@ -1,6 +1,5 @@
       -#include <signal.h>
       -
        #include <u.h>
       +#include <signal.h>
        #define NOPLAN9DEFINES
        #include <libc.h>
        #include "9proc.h"
 (DIR) diff --git a/src/lib9/open.c b/src/lib9/open.c
       t@@ -2,12 +2,9 @@
        #define NOPLAN9DEFINES
        #include <libc.h>
        
       -extern char* _p9translate(char*);
       -
        int
       -p9open(char *xname, int mode)
       +p9open(char *name, int mode)
        {
       -        char *name;
                int cexec, rclose;
                int fd, umode;
        
       t@@ -23,8 +20,6 @@ p9open(char *xname, int mode)
                        werrstr("mode not supported");
                        return -1;
                }
       -        if((name = _p9translate(xname)) == nil)
       -                return -1;
                fd = open(name, umode);
                if(fd >= 0){
                        if(cexec)
       t@@ -32,7 +27,5 @@ p9open(char *xname, int mode)
                        if(rclose)
                                remove(name);
                }
       -        if(name != xname)
       -                free(name);
                return fd;
        }
 (DIR) diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c
       t@@ -1 +1,3 @@
       +/* Could use futex(2) here instead of signals? */
       +
        #include "rendez-signal.c"
 (DIR) diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-OpenBSD.c
 (DIR) diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
       t@@ -32,9 +32,10 @@
         * shared memory and mutexes.
         */
        
       +#include <u.h>
        #include <pthread.h>
        #include <signal.h>
       -#include <lib9.h>
       +#include <libc.h>
        
        enum
        {
 (DIR) diff --git a/src/lib9/time.c b/src/lib9/time.c
       t@@ -1,7 +1,7 @@
       +#include <u.h>
        #include <sys/time.h>
       +#include <time.h>
        #include <sys/resource.h>
       -
       -#include <u.h>
        #define NOPLAN9DEFINES
        #include <libc.h>
        
 (DIR) diff --git a/src/libdraw/openfont.c b/src/libdraw/openfont.c
       t@@ -18,8 +18,10 @@ openfont(Display *d, char *name)
                        nambuf = smprint("#9/font/%s", name+14);
                        if(nambuf == nil)
                                return 0;
       +                nambuf = unsharp(nambuf);
       +                if(nambuf == nil)
       +                        return 0;
                        if((fd = open(nambuf, OREAD)) < 0){
       -fprint(2, "failed at %s\n", nambuf);
                                free(nambuf);
                                return 0;
                        }
 (DIR) diff --git a/src/libdraw/x11-init.c b/src/libdraw/x11-init.c
       t@@ -185,26 +185,22 @@ xattach(char *label)
                /* 
                 * Figure out underlying screen format.
                 */
       -        _x.depth = DefaultDepth(_x.display, xrootid);
                if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
                || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
                        _x.vis = xvi.visual;
                        _x.depth = 16;
       -                _x.usetable = 1;
                }
                else
                if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
                || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
                        _x.vis = xvi.visual;
                        _x.depth = 15;
       -                _x.usetable = 1;
                }
                else
                if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
                || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
                        _x.vis = xvi.visual;
                        _x.depth = 24;
       -                _x.usetable = 1;
                }
                else
                if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
       t@@ -218,6 +214,7 @@ xattach(char *label)
                        _x.depth = 8;
                }
                else{
       +                _x.depth = DefaultDepth(_x.display, xrootid);
                        if(_x.depth != 8){
                                werrstr("can't understand depth %d screen", _x.depth);
                                goto err0;
       t@@ -225,6 +222,9 @@ xattach(char *label)
                        _x.vis = DefaultVisual(_x.display, xrootid);
                }
        
       +        if(DefaultDepth(_x.display, xrootid) == _x.depth)
       +                _x.usetable = 1;
       +
                /*
                 * _x.depth is only the number of significant pixel bits,
                 * not the total number of pixel bits.  We need to walk the
       t@@ -298,7 +298,7 @@ xattach(char *label)
                        Dx(r),                /* width */
                         Dy(r),                /* height */
                        0,                /* border width */
       -                DefaultDepthOfScreen(xscreen),        /* depth */
       +                _x.depth,        /* depth */
                        InputOutput,        /* class */
                        _x.vis,                /* visual */
                                        /* valuemask */
       t@@ -563,6 +563,18 @@ setupcmap(XWindow w)
        
                if(_x.depth >= 24) {
                        /*
       +                 * This is needed for SunOS.  Ask Axel Belinfante.
       +                 */
       +                if(_x.usetable == 0){
       +                        _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll); 
       +                        XStoreColors(_x.display, _x.cmap, _x.map, 256);
       +                        for(i = 0; i < 256; i++){
       +                                _x.tox11[i] = i;
       +                                _x.toplan9[i] = i;
       +                        }
       +                }
       +
       +                /*
                         * The pixel value returned from XGetPixel needs to
                         * be converted to RGB so we can call rgb2cmap()
                         * to translate between 24 bit X and our color. Unfortunately,
       t@@ -573,7 +585,6 @@ setupcmap(XWindow w)
                         * some displays say MSB even though they run on LSB.
                         * Besides, this is more anal.
                         */
       -
                        c = _x.map[19];        /* known to have different R, G, B values */
                        if(!XAllocColor(_x.display, _x.cmap, &c)){
                                werrstr("XAllocColor: %r");
 (DIR) diff --git a/src/libdraw/x11-itrans.c b/src/libdraw/x11-itrans.c
       t@@ -11,6 +11,9 @@
        #include <keyboard.h>
        #include "x11-memdraw.h"
        
       +#undef time
       +
       +
        static int
        __xtoplan9kbd(XEvent *e)
        {
 (DIR) diff --git a/src/libplumb/mesg.c b/src/libplumb/mesg.c
       t@@ -68,7 +68,6 @@ plumbsendtofid(Fid *fid, Plumbmsg *m)
                if(buf == nil)
                        return -1;
                n = fswrite(fid, buf, n);
       -fprint(2, "fswrite %d\n", n);
                free(buf);
                return n;
        }
 (DIR) diff --git a/src/libthread/asm-OpenBSD-386.s b/src/libthread/asm-OpenBSD-386.s
       t@@ -0,0 +1,49 @@
       +.globl        _setlabel
       +.type        _setlabel,@function
       +
       +_setlabel:
       +        movl        4(%esp), %eax
       +        movl        0(%esp), %edx
       +        movl        %edx, 0(%eax)
       +        movl        %ebx, 4(%eax)
       +        movl        %esp, 8(%eax)
       +        movl        %ebp, 12(%eax)
       +        movl        %esi, 16(%eax)
       +        movl        %edi, 20(%eax)
       +        xorl        %eax, %eax
       +        ret
       +
       +.globl        _gotolabel
       +.type        _gotolabel,@function
       +
       +_gotolabel:
       +        movl        4(%esp), %edx
       +        movl        0(%edx), %ecx
       +        movl        4(%edx), %ebx
       +        movl        8(%edx), %esp
       +        movl        12(%edx), %ebp
       +        movl        16(%edx), %esi
       +        movl        20(%edx), %edi
       +        xorl        %eax, %eax
       +        incl        %eax
       +        movl        %ecx, 0(%esp)
       +        ret
       +
       +
       +# .globl        _xinc
       +# _xinc:
       +#         movl 4(%esp), %eax
       +#         lock incl 0(%eax)
       +#         ret
       +# 
       +# .globl        _xdec
       +# _xdec:
       +#         movl 4(%esp), %eax
       +#         lock decl 0(%eax)
       +#         jz iszero
       +#         movl $1, %eax
       +#         ret
       +# iszero:
       +#         movl $0, %eax
       +#         ret
       +# 
 (DIR) diff --git a/src/libthread/exec-unix.c b/src/libthread/exec-unix.c
       t@@ -3,8 +3,8 @@
        #include "threadimpl.h"
        
        static void efork(int[3], int[2], char*, char**);
       -void
       -threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
       +static void
       +_threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
        {
                int pfd[2];
                int n, pid;
       t@@ -40,6 +40,8 @@ threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
                        efork(fd, pfd, prog, args);
                        _exit(0);
                default:
       +                if(freeargs)
       +                        free(args);
                        break;
                }
        
       t@@ -69,9 +71,42 @@ Bad:
        }
        
        void
       +threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
       +{
       +        _threadexec(pidc, fd, prog, args, 0);
       +}
       +
       +/*
       + * The &f+1 trick doesn't work on SunOS, so we might 
       + * as well bite the bullet and do this correctly.
       + */
       +void
        threadexecl(Channel *pidc, int fd[3], char *f, ...)
        {
       -        threadexec(pidc, fd, f, &f+1);
       +        char **args, *s;
       +        int n;
       +        va_list arg;
       +
       +        va_start(arg, f);
       +        for(n=0; va_arg(arg, char*) != 0; n++)
       +                ;
       +        n++;
       +        va_end(arg);
       +
       +        args = malloc(n*sizeof(args[0]));
       +        if(args == nil){
       +                if(pidc)
       +                        sendul(pidc, ~0);
       +                return;
       +        }
       +
       +        va_start(arg, f);
       +        for(n=0; (s=va_arg(arg, char*)) != 0; n++)
       +                args[n] = s;
       +        args[n] = 0;
       +        va_end(arg);
       +
       +        _threadexec(pidc, fd, f, args, 1);
        }
        
        static void
 (DIR) diff --git a/src/libthread/label.h b/src/libthread/label.h
       t@@ -7,7 +7,7 @@
        typedef struct Label Label;
        #define LABELDPC 0
        
       -#if defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__))
       +#if defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
        struct Label
        {
                ulong pc;
 (DIR) diff --git a/src/mkfile b/src/mkfile
       t@@ -1,6 +1,6 @@
        <mkhdr
        
       -BUGGERED='9p|html|httpd|ip|venti'
       +BUGGERED='9p|fmt|html|httpd|ip|utf|venti'
        LIBDIRS=`ls -ld lib* | sed -n 's/^d.* //p' |egrep -v "^lib($BUGGERED)$"`
        
        DIRS=\