tadd new guys - 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 17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b
 (DIR) parent 3e63e5c271f7a7013dc4b3fedfb83c2d547b8c26
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed, 21 Apr 2004 23:22:06 +0000
       
       add new guys
       
       Diffstat:
         A src/cmd/bc.y                        |     983 +++++++++++++++++++++++++++++++
         M src/cmd/jpg/mkfile                  |       4 ++--
         M src/cmd/mkfile                      |      24 ++++++++++++++++++++----
         A src/cmd/mtime.c                     |      33 +++++++++++++++++++++++++++++++
         A src/cmd/news.c                      |     231 +++++++++++++++++++++++++++++++
         A src/cmd/primes.c                    |     131 +++++++++++++++++++++++++++++++
         A src/cmd/units.y                     |     795 +++++++++++++++++++++++++++++++
       
       7 files changed, 2195 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/bc.y b/src/cmd/bc.y
       t@@ -0,0 +1,983 @@
       +%{
       +        #include        <u.h>
       +        #include        <libc.h>
       +        #include        <bio.h>
       +
       +        #define        bsp_max        5000
       +
       +        Biobuf        *in;
       +        Biobuf        stdin;
       +        Biobuf        stdout;
       +        char        cary[1000];
       +        char*        cp = { cary };
       +        char        string[1000];
       +        char*        str = { string };
       +        int        crs = 128;
       +        int        rcrs = 128;        /* reset crs */
       +        int        bindx = 0;
       +        int        lev = 0;
       +        int        ln;
       +        int*        ttp;
       +        char*        ss = "";
       +        int        bstack[10] = { 0 };
       +        char*        numb[15] =
       +        {
       +                " 0", " 1", " 2", " 3", " 4", " 5",
       +                " 6", " 7", " 8", " 9", " 10", " 11",
       +                " 12", " 13", " 14"
       +        };
       +        int*        pre;
       +        int*        post;
       +
       +        long        peekc = -1;
       +        int        sargc;
       +        int        ifile;
       +        char**        sargv;
       +
       +        char        *funtab[] =
       +        {
       +                "<1>","<2>","<3>","<4>","<5>",
       +                "<6>","<7>","<8>","<9>","<10>",
       +                "<11>","<12>","<13>","<14>","<15>",
       +                "<16>","<17>","<18>","<19>","<20>",
       +                "<21>","<22>","<23>","<24>","<25>",
       +                "<26>"
       +        };
       +        char        *atab[] =
       +        {
       +                "<221>","<222>","<223>","<224>","<225>",
       +                "<226>","<227>","<228>","<229>","<230>",
       +                "<231>","<232>","<233>","<234>","<235>",
       +                "<236>","<237>","<238>","<239>","<240>",
       +                "<241>","<242>","<243>","<244>","<245>",
       +                "<246>"
       +        };
       +        char*        letr[26] =
       +        {
       +                "a","b","c","d","e","f","g","h","i","j",
       +                "k","l","m","n","o","p","q","r","s","t",
       +                "u","v","w","x","y","z"
       +        };
       +        char*        dot = { "." };
       +        int        bspace[bsp_max];
       +        int*        bsp_nxt = { bspace };
       +        int        bdebug = 0;
       +        int        lflag;
       +        int        cflag;
       +        int        sflag;
       +
       +        int*        bundle(int, ...);
       +        void        conout(int*, char*);
       +        int        cpeek(int, int, int);
       +        int        getch(void);
       +        int*        geta(char*);
       +        int*        getf(char*);
       +        void        getout(void);
       +        void        output(int*);
       +        void        pp(char*);
       +        void        routput(int*);
       +        void        tp(char*);
       +        void        yyerror(char*, ...);
       +        int        yyparse(void);
       +
       +        typedef        void*        pointer;
       +/*        #pragma        varargck        type        "lx"        pointer */
       +
       +%}
       +%union
       +{
       +        int*        iptr;
       +        char*        cptr;
       +        int        cc;
       +}
       +
       +%type        <iptr>        pstat stat stat1 def slist dlets e ase nase
       +%type        <iptr>        slist re fprefix cargs eora cons constant lora
       +%type        <cptr>        crs
       +
       +%token        <cptr>        LETTER EQOP _AUTO DOT
       +%token        <cc>        DIGIT SQRT LENGTH _IF FFF EQ
       +%token        <cc>        _PRINT _WHILE _FOR NE LE GE INCR DECR
       +%token        <cc>        _RETURN _BREAK _DEFINE BASE OBASE SCALE
       +%token        <cc>        QSTR ERROR
       +
       +%right        '=' EQOP
       +%left        '+' '-'
       +%left        '*' '/' '%'
       +%right        '^'
       +%left        UMINUS
       +
       +%%
       +start:
       +        start stuff
       +|        stuff
       +
       +stuff:
       +        pstat tail
       +        {
       +                output($1);
       +        }
       +|        def dargs ')' '{' dlist slist '}'
       +        {
       +                ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
       +                conout(ttp, (char*)$1);
       +                rcrs = crs;
       +                output((int*)"");        /* this is horse puk!! */
       +                lev = bindx = 0;
       +        }
       +
       +dlist:
       +        tail
       +|        dlist _AUTO dlets tail
       +
       +stat:
       +        stat1
       +|        nase
       +        {
       +                if(sflag)
       +                        bundle(2, $1, "s.");
       +        }
       +
       +pstat:
       +        stat1
       +        {
       +                if(sflag)
       +                        bundle(2, $1, "0");
       +        }
       +|        nase
       +        {
       +                if(!sflag)
       +                        bundle(2, $1, "ps.");
       +        }
       +
       +stat1:
       +        {
       +                bundle(1, "");
       +        }
       +|        ase
       +        {
       +                bundle(2, $1, "s.");
       +        }
       +|        SCALE '=' e
       +        {
       +                bundle(2, $3, "k");
       +        }
       +|        SCALE EQOP e
       +        {
       +                bundle(4, "K", $3, $2, "k");
       +        }
       +|        BASE '=' e
       +        {
       +                bundle(2, $3, "i");
       +        }
       +|        BASE EQOP e
       +        {
       +                bundle(4, "I", $3, $2, "i");
       +        }
       +|        OBASE '=' e
       +        {
       +                bundle(2, $3, "o");
       +        }
       +|        OBASE EQOP e
       +        {
       +                bundle(4, "O", $3, $2, "o");
       +        }
       +|        QSTR
       +        {
       +                bundle(3, "[", $1, "]P");
       +        }
       +|        _BREAK
       +        {
       +                bundle(2, numb[lev-bstack[bindx-1]], "Q");
       +        }
       +|        _PRINT e
       +        {
       +                bundle(2, $2, "ps.");
       +        }
       +|        _RETURN e
       +        {
       +                bundle(4, $2, post, numb[lev], "Q");
       +        }
       +|        _RETURN
       +        {
       +                bundle(4, "0", post, numb[lev], "Q");
       +        }
       +|        '{' slist '}'
       +        {
       +                $$ = $2;
       +        }
       +|        FFF
       +        {
       +                bundle(1, "fY");
       +        }
       +|        _IF crs BLEV '(' re ')' stat
       +        {
       +                conout($7, $2);
       +                bundle(3, $5, $2, " ");
       +        }
       +|        _WHILE crs '(' re ')' stat BLEV
       +        {
       +                bundle(3, $6, $4, $2);
       +                conout($$, $2);
       +                bundle(3, $4, $2, " ");
       +        }
       +|        fprefix crs re ';' e ')' stat BLEV
       +        {
       +                bundle(5, $7, $5, "s.", $3, $2);
       +                conout($$, $2);
       +                bundle(5, $1, "s.", $3, $2, " ");
       +        }
       +|        '~' LETTER '=' e
       +        {
       +                bundle(3, $4, "S", $2);
       +        }
       +
       +fprefix:
       +        _FOR '(' e ';'
       +        {
       +                $$ = $3;
       +        }
       +
       +BLEV:
       +        =
       +        {
       +                --bindx;
       +        }
       +
       +slist:
       +        stat
       +|        slist tail stat
       +        {
       +                bundle(2, $1, $3);
       +        }
       +
       +tail:
       +        '\n'
       +        {
       +                ln++;
       +        }
       +|        ';'
       +
       +re:
       +        e EQ e
       +        {
       +                $$ = bundle(3, $1, $3, "=");
       +        }
       +|        e '<' e
       +        {
       +                bundle(3, $1, $3, ">");
       +        }
       +|        e '>' e
       +        {
       +                bundle(3, $1, $3, "<");
       +        }
       +|        e NE e
       +        {
       +                bundle(3, $1, $3, "!=");
       +        }
       +|        e GE e
       +        {
       +                bundle(3, $1, $3, "!>");
       +        }
       +|        e LE e
       +        {
       +                bundle(3, $1, $3, "!<");
       +        }
       +|        e
       +        {
       +                bundle(2, $1, " 0!=");
       +        }
       +
       +nase:
       +        '(' e ')'
       +        {
       +                $$ = $2;
       +        }
       +|        cons
       +        {
       +                bundle(3, " ", $1, " ");
       +        }
       +|        DOT cons
       +        {
       +                bundle(3, " .", $2, " ");
       +        }
       +|        cons DOT cons
       +        {
       +                bundle(5, " ", $1, ".", $3, " ");
       +        }
       +|        cons DOT
       +        {
       +                bundle(4, " ", $1, ".", " ");
       +        }
       +|        DOT
       +        {
       +                $<cptr>$ = "l.";
       +        }
       +|        LETTER '[' e ']'
       +        {
       +                bundle(3, $3, ";", geta($1));
       +        }
       +|        LETTER INCR
       +        {
       +                bundle(4, "l", $1, "d1+s", $1);
       +        }
       +|        INCR LETTER
       +        {
       +                bundle(4, "l", $2, "1+ds", $2);
       +        }
       +|        DECR LETTER
       +        {
       +                bundle(4, "l", $2, "1-ds", $2);
       +        }
       +|        LETTER DECR
       +        {
       +                bundle(4, "l", $1, "d1-s", $1);
       +        }
       +|        LETTER '[' e ']' INCR
       +        {
       +                bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1));
       +        }
       +|        INCR LETTER '[' e ']'
       +        {
       +                bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
       +        }
       +|        LETTER '[' e ']' DECR
       +        {
       +                bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
       +        }
       +|        DECR LETTER '[' e ']'
       +        {
       +                bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2));
       +        }
       +|        SCALE INCR
       +        {
       +                bundle(1, "Kd1+k");
       +        }
       +|        INCR SCALE
       +        {
       +                bundle(1, "K1+dk");
       +        }
       +|        SCALE DECR
       +        {
       +                bundle(1, "Kd1-k");
       +        }
       +|        DECR SCALE
       +        {
       +                bundle(1, "K1-dk");
       +        }
       +|        BASE INCR
       +        {
       +                bundle(1, "Id1+i");
       +        }
       +|        INCR BASE
       +        {
       +                bundle(1, "I1+di");
       +        }
       +|        BASE DECR
       +        {
       +                bundle(1, "Id1-i");
       +        }
       +|        DECR BASE
       +        {
       +                bundle(1, "I1-di");
       +        }
       +|        OBASE INCR
       +        {
       +                bundle(1, "Od1+o");
       +        }
       +|        INCR OBASE
       +        {
       +                bundle(1, "O1+do");
       +        }
       +|        OBASE DECR
       +        {
       +                bundle(1, "Od1-o");
       +        }
       +|        DECR OBASE
       +        {
       +                bundle(1, "O1-do");
       +        }
       +|        LETTER '(' cargs ')'
       +        {
       +                bundle(4, $3, "l", getf($1), "x");
       +        }
       +|        LETTER '(' ')'
       +        {
       +                bundle(3, "l", getf($1), "x");
       +        }
       +|        LETTER = {
       +                bundle(2, "l", $1);
       +        }
       +|        LENGTH '(' e ')'
       +        {
       +                bundle(2, $3, "Z");
       +        }
       +|        SCALE '(' e ')'
       +        {
       +                bundle(2, $3, "X");
       +        }
       +|        '?'
       +        {
       +                bundle(1, "?");
       +        }
       +|        SQRT '(' e ')'
       +        {
       +                bundle(2, $3, "v");
       +        }
       +|        '~' LETTER
       +        {
       +                bundle(2, "L", $2);
       +        }
       +|        SCALE
       +        {
       +                bundle(1, "K");
       +        }
       +|        BASE
       +        {
       +                bundle(1, "I");
       +        }
       +|        OBASE
       +        {
       +                bundle(1, "O");
       +        }
       +|        '-' e
       +        {
       +                bundle(3, " 0", $2, "-");
       +        }
       +|        e '+' e
       +        {
       +                bundle(3, $1, $3, "+");
       +        }
       +|        e '-' e
       +        {
       +                bundle(3, $1, $3, "-");
       +        }
       +|        e '*' e
       +        {
       +                bundle(3, $1, $3, "*");
       +        }
       +|        e '/' e
       +        {
       +                bundle(3, $1, $3, "/");
       +        }
       +|        e '%' e
       +        {
       +                bundle(3, $1, $3, "%%");
       +        }
       +|        e '^' e
       +        {
       +                bundle(3, $1, $3, "^");
       +        }
       +
       +ase:
       +        LETTER '=' e
       +        {
       +                bundle(3, $3, "ds", $1);
       +        }
       +|        LETTER '[' e ']' '=' e
       +        {
       +                bundle(5, $6, "d", $3, ":", geta($1));
       +        }
       +|        LETTER EQOP e
       +        {
       +                bundle(6, "l", $1, $3, $2, "ds", $1);
       +        }
       +|        LETTER '[' e ']' EQOP e
       +        {
       +                bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1));
       +        }
       +
       +e:
       +        ase
       +|        nase
       +
       +cargs:
       +        eora
       +|        cargs ',' eora
       +        {
       +                bundle(2, $1, $3);
       +        }
       +
       +eora:
       +        e
       +|        LETTER '[' ']'
       +        {
       +                bundle(2, "l", geta($1));
       +        }
       +
       +cons:
       +        constant
       +        {
       +                *cp++ = 0;
       +        }
       +
       +constant:
       +        '_'
       +        {
       +                $<cptr>$ = cp;
       +                *cp++ = '_';
       +        }
       +|        DIGIT
       +        {
       +                $<cptr>$ = cp;
       +                *cp++ = $1;
       +        }
       +|        constant DIGIT
       +        {
       +                *cp++ = $2;
       +        }
       +
       +crs:
       +        =
       +        {
       +                $$ = cp;
       +                *cp++ = '<';
       +                *cp++ = crs/100+'0';
       +                *cp++ = (crs%100)/10+'0';
       +                *cp++ = crs%10+'0';
       +                *cp++ = '>';
       +                *cp++ = '\0';
       +                if(crs++ >= 220) {
       +                        yyerror("program too big");
       +                        getout();
       +                }
       +                bstack[bindx++] = lev++;
       +        }
       +
       +def:
       +        _DEFINE LETTER '('
       +        {
       +                $$ = getf($2);
       +                pre = (int*)"";
       +                post = (int*)"";
       +                lev = 1;
       +                bindx = 0;
       +                bstack[bindx] = 0;
       +        }
       +
       +dargs:
       +|        lora
       +        {
       +                pp((char*)$1);
       +        }
       +|        dargs ',' lora
       +        {
       +                pp((char*)$3);
       +        }
       +
       +dlets:
       +        lora
       +        {
       +                tp((char*)$1);
       +        }
       +|        dlets ',' lora
       +        {
       +                tp((char*)$3);
       +        }
       +
       +lora:
       +        LETTER
       +        {
       +                $<cptr>$=$1;
       +        }
       +|        LETTER '[' ']'
       +        {
       +                $$ = geta($1);
       +        }
       +
       +%%
       +
       +int
       +yylex(void)
       +{
       +        int c, ch;
       +
       +restart:
       +        c = getch();
       +        peekc = -1;
       +        while(c == ' ' || c == '\t')
       +                c = getch();
       +        if(c == '\\') {
       +                getch();
       +                goto restart;
       +        }
       +        if(c >= 'a' && c <= 'z') {
       +                /* look ahead to look for reserved words */
       +                peekc = getch();
       +                if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */
       +                        if(c=='p' && peekc=='r') {
       +                                c = _PRINT;
       +                                goto skip;
       +                        }
       +                        if(c=='i' && peekc=='f') {
       +                                c = _IF;
       +                                goto skip;
       +                        }
       +                        if(c=='w' && peekc=='h') {
       +                                c = _WHILE;
       +                                goto skip;
       +                        }
       +                        if(c=='f' && peekc=='o') {
       +                                c = _FOR;
       +                                goto skip;
       +                        }
       +                        if(c=='s' && peekc=='q') {
       +                                c = SQRT;
       +                                goto skip;
       +                        }
       +                        if(c=='r' && peekc=='e') {
       +                                c = _RETURN;
       +                                goto skip;
       +                        }
       +                        if(c=='b' && peekc=='r') {
       +                                c = _BREAK;
       +                                goto skip;
       +                        }
       +                        if(c=='d' && peekc=='e') {
       +                                c = _DEFINE;
       +                                goto skip;
       +                        }
       +                        if(c=='s' && peekc=='c') {
       +                                c = SCALE;
       +                                goto skip;
       +                        }
       +                        if(c=='b' && peekc=='a') {
       +                                c = BASE;
       +                                goto skip;
       +                        }
       +                        if(c=='i' && peekc=='b') {
       +                                c = BASE;
       +                                goto skip;
       +                        }
       +                        if(c=='o' && peekc=='b') {
       +                                c = OBASE;
       +                                goto skip;
       +                        }
       +                        if(c=='d' && peekc=='i') {
       +                                c = FFF;
       +                                goto skip;
       +                        }
       +                        if(c=='a' && peekc=='u') {
       +                                c = _AUTO;
       +                                goto skip;
       +                        }
       +                        if(c=='l' && peekc=='e') {
       +                                c = LENGTH;
       +                                goto skip;
       +                        }
       +                        if(c=='q' && peekc=='u')
       +                                getout();
       +                        /* could not be found */
       +                        return ERROR;
       +
       +                skip:        /* skip over rest of word */
       +                        peekc = -1;
       +                        for(;;) {
       +                                ch = getch();
       +                                if(ch < 'a' || ch > 'z')
       +                                        break;
       +                        }
       +                        peekc = ch;
       +                        return c;
       +                }
       +
       +                /* usual case; just one single letter */
       +                yylval.cptr = letr[c-'a'];
       +                return LETTER;
       +        }
       +        if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
       +                yylval.cc = c;
       +                return DIGIT;
       +        }
       +        switch(c) {
       +        case '.':
       +                return DOT;
       +        case '*':
       +                yylval.cptr = "*";
       +                return cpeek('=', EQOP, c);
       +        case '%':
       +                yylval.cptr = "%%";
       +                return cpeek('=', EQOP, c);
       +        case '^':
       +                yylval.cptr = "^";
       +                return cpeek('=', EQOP, c);
       +        case '+':
       +                ch = cpeek('=', EQOP, c);
       +                if(ch == EQOP) {
       +                        yylval.cptr = "+";
       +                        return ch;
       +                }
       +                return cpeek('+', INCR, c);
       +        case '-':
       +                ch = cpeek('=', EQOP, c);
       +                if(ch == EQOP) {
       +                        yylval.cptr = "-";
       +                        return ch;
       +                }
       +                return cpeek('-', DECR, c);
       +        case '=':
       +                return cpeek('=', EQ, '=');
       +        case '<':
       +                return cpeek('=', LE, '<');
       +        case '>':
       +                return cpeek('=', GE, '>');
       +        case '!':
       +                return cpeek('=', NE, '!');
       +        case '/':
       +                ch = cpeek('=', EQOP, c);
       +                if(ch == EQOP) {
       +                        yylval.cptr = "/";
       +                        return ch;
       +                }
       +                if(peekc == '*') {
       +                        peekc = -1;
       +                        for(;;) {
       +                                ch = getch();
       +                                if(ch == '*') {
       +                                        peekc = getch();
       +                                        if(peekc == '/') {
       +                                                peekc = -1;
       +                                                goto restart;
       +                                        }
       +                                }
       +                        }
       +                }
       +                return c;
       +        case '"':
       +                yylval.cptr = str;
       +                while((c=getch()) != '"'){
       +                        *str++ = c;
       +                        if(str >= &string[999]){
       +                                yyerror("string space exceeded");
       +                                getout();
       +                        }
       +                }
       +                *str++ = 0;
       +                return QSTR;
       +        default:
       +                return c;
       +        }
       +}
       +
       +int
       +cpeek(int c, int yes, int no)
       +{
       +
       +        peekc = getch();
       +        if(peekc == c) {
       +                peekc = -1;
       +                return yes;
       +        }
       +        return no;
       +}
       +
       +int
       +getch(void)
       +{
       +        long ch;
       +
       +loop:
       +        ch = peekc;
       +        if(ch < 0){
       +                if(in == 0)
       +                        ch = -1;
       +                else
       +                        ch = Bgetc(in);
       +        }
       +        peekc = -1;
       +        if(ch >= 0)
       +                return ch;
       +        ifile++;
       +        if(ifile > sargc) {
       +                if(ifile >= sargc+2)
       +                        getout();
       +                in = &stdin;
       +                Binit(in, 0, OREAD);
       +                ln = 0;
       +                goto loop;
       +        }
       +        Bterm(in);
       +        if((in = Bopen(sargv[ifile], OREAD)) != 0){
       +                ln = 0;
       +                ss = sargv[ifile];
       +                goto loop;
       +        }
       +        yyerror("cannot open input file");
       +        return 0;                /* shut up ken */
       +}
       +
       +int*
       +bundle(int a, ...)
       +{
       +        int i, *p, *q;
       +
       +        p = &a;
       +        i = *p++;
       +        q = bsp_nxt;
       +        if(bdebug)
       +                fprint(2, "bundle %d elements at %lx\n", i, q);
       +        while(i-- > 0) {
       +                if(bsp_nxt >= &bspace[bsp_max])
       +                        yyerror("bundling space exceeded");
       +                *bsp_nxt++ = *p++;
       +        }
       +        *bsp_nxt++ = 0;
       +        yyval.iptr = q;
       +        return q;
       +}
       +
       +void
       +routput(int *p)
       +{
       +        if(bdebug)
       +                fprint(2, "routput(%lx)\n", p);
       +        if(p >= &bspace[0] && p < &bspace[bsp_max]) {
       +                /* part of a bundle */
       +                while(*p != 0)
       +                        routput((int*)(*p++));
       +        } else
       +                Bprint(&stdout, (char*)p);        /* character string */
       +}
       +
       +void
       +output(int *p)
       +{
       +        routput(p);
       +        bsp_nxt = &bspace[0];
       +        Bprint(&stdout, "\n");
       +        Bflush(&stdout);
       +        cp = cary;
       +        crs = rcrs;
       +}
       +
       +void
       +conout(int *p, char *s)
       +{
       +        Bprint(&stdout, "[");
       +        routput(p);
       +        Bprint(&stdout, "]s%s\n", s);
       +        Bflush(&stdout);
       +        lev--;
       +}
       +
       +void
       +yyerror(char *s, ...)
       +{
       +        if(ifile > sargc)
       +                ss = "teletype";
       +        Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
       +        Bflush(&stdout);
       +        cp = cary;
       +        crs = rcrs;
       +        bindx = 0;
       +        lev = 0;
       +        bsp_nxt = &bspace[0];
       +}
       +
       +void
       +pp(char *s)
       +{
       +        /* puts the relevant stuff on pre and post for the letter s */
       +        bundle(3, "S", s, pre);
       +        pre = yyval.iptr;
       +        bundle(4, post, "L", s, "s.");
       +        post = yyval.iptr;
       +}
       +
       +void
       +tp(char *s)
       +{
       +        /* same as pp, but for temps */
       +        bundle(3, "0S", s, pre);
       +        pre = yyval.iptr;
       +        bundle(4, post, "L", s, "s.");
       +        post = yyval.iptr;
       +}
       +
       +void
       +yyinit(int argc, char **argv)
       +{
       +        Binit(&stdout, 1, OWRITE);
       +        sargv = argv;
       +        sargc = argc - 1;
       +        if(sargc == 0) {
       +                in = &stdin;
       +                Binit(in, 0, OREAD);
       +        } else if((in = Bopen(sargv[1], OREAD)) == 0)
       +                yyerror("cannot open input file");
       +        ifile = 1;
       +        ln = 0;
       +        ss = sargv[1];
       +}
       +
       +void
       +getout(void)
       +{
       +        Bprint(&stdout, "q");
       +        Bflush(&stdout);
       +        exits(0);
       +}
       +
       +int*
       +getf(char *p)
       +{
       +        return (int*)funtab[*p - 'a'];
       +}
       +
       +int*
       +geta(char *p)
       +{
       +        return (int*)atab[*p - 'a'];
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int p[2];
       +
       +        while(argc > 1 && *argv[1] == '-') {
       +                switch(argv[1][1]) {
       +                case 'd':
       +                        bdebug++;
       +                        break;
       +                case 'c':
       +                        cflag++;
       +                        break;
       +                case 'l':
       +                        lflag++;
       +                        break;
       +                case 's':
       +                        sflag++;
       +                        break;
       +                default:
       +                        fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
       +                        exits("usage");
       +                }
       +                argc--;
       +                argv++;
       +        }
       +        if(lflag) {
       +                argv--;
       +                argc++;
       +                argv[1] = "/sys/lib/bclib";
       +        }
       +        if(cflag) {
       +                yyinit(argc, argv);
       +                for(;;)
       +                        yyparse();
       +                exits(0);
       +        }
       +        pipe(p);
       +        if(fork() == 0) {
       +                dup(p[1], 1);
       +                close(p[0]);
       +                close(p[1]);
       +                yyinit(argc, argv);
       +                for(;;)
       +                        yyparse();
       +        }
       +        dup(p[0], 0);
       +        close(p[0]);
       +        close(p[1]);
       +        execl("/bin/dc", "dc", 0);
       +}
 (DIR) diff --git a/src/cmd/jpg/mkfile b/src/cmd/jpg/mkfile
       t@@ -38,12 +38,12 @@ torgbv.$O:        ycbcr.h rgbv.h
        
        ycbcr.h:        rgbycc.c
                9c rgbycc.c
       -        9l -o o.rgbycc rgbycc.c
       +        9l -o o.rgbycc rgbycc.o -ldraw -l9
                ./o.rgbycc >ycbcr.h
        
        rgbv.h:        rgbrgbv.c
                9c rgbrgbv.c
       -        9l -o o.rgbrgbv rgbrgbv.c
       +        9l -o o.rgbrgbv rgbrgbv.o -ldraw -l9
                ./o.rgbrgbv >rgbv.h
        
        nuke:V:        nuke-headers
 (DIR) diff --git a/src/cmd/mkfile b/src/cmd/mkfile
       t@@ -1,8 +1,7 @@
        <$PLAN9/src/mkhdr
        
       -TARG=`ls *.c | sed 's/\.c//'`
       -LDFLAGS=$LDFLAGS -L$X11/lib -lX11
       -SHORTLIB=sec fs mux regexp9 draw thread bio 9
       +TARG=`ls *.[cy] | sed 's/\.c//'`
       +SHORTLIB=sec fs mux regexp9 thread bio 9
        
        <$PLAN9/src/mkmany
        
       t@@ -11,4 +10,21 @@ DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
        
        <$PLAN9/src/mkdirs
        
       -dir-install: $PLAN9/bin/yacc
       +dir-all dir-install: $PLAN9/bin/9yacc
       +
       +XLIB=draw bio 9
       +$O.clock: clock.$O ${XLIB:%=$PLAN9/lib/lib%.a}
       +        $LD -o $target $prereq -L$X11/lib -lX11
       +
       +$O.tweak: tweak.$O ${XLIB:%=$PLAN9/lib/lib%.a}
       +        $LD -o $target $prereq -L$X11/lib -lX11
       +
       +%.tab.h %.tab.c: %.y
       +        $YACC $YFLAGS -s $stem $prereq
       +
       +%.o: %.tab.c
       +        9c -o $target $stem.tab.c
       +
       +CLEANFILES=$CLEANFILES bc.tab.[ch] units.tab.[ch]
       +
       +
 (DIR) diff --git a/src/cmd/mtime.c b/src/cmd/mtime.c
       t@@ -0,0 +1,33 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: mtime file...\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int errors, i;
       +        Dir *d;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        errors = 0;
       +        for(i=0; i<argc; i++){
       +                if((d = dirstat(argv[i])) == nil){
       +                        fprint(2, "stat %s: %r\n", argv[i]);
       +                        errors = 1;
       +                }else{
       +                        print("%11lud %s\n", d->mtime, argv[i]);
       +                        free(d);
       +                }
       +        }
       +        exits(errors ? "errors" : nil);
       +}
 (DIR) diff --git a/src/cmd/news.c b/src/cmd/news.c
       t@@ -0,0 +1,231 @@
       +/*
       + *        news foo        prints /lib/news/foo
       + *        news -a                prints all news items, latest first
       + *        news -n                lists names of new items
       + *        news                prints items changed since last news
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +
       +#define        NINC        50        /* Multiples of directory allocation */
       +char        *NEWS = "#9/news";
       +char        TFILE[] = "%s/lib/newstime";
       +
       +/*
       + *        The following items should not be printed.
       + */
       +char*        ignore[] =
       +{
       +        "core",
       +        "dead.letter",
       +        0
       +};
       +
       +typedef
       +struct
       +{
       +        long        time;
       +        char        *name;
       +        vlong        length;
       +} File;
       +File*        n_list;
       +int        n_count;
       +int        n_items;
       +Biobuf        bout;
       +
       +int        fcmp(const void *a, const void *b);
       +void        read_dir(int update);
       +void        print_item(char *f);
       +void        eachitem(void (*emit)(char*), int all, int update);
       +void        note(char *s);
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        int i;
       +
       +        NEWS = unsharp(NEWS);
       +
       +        Binit(&bout, 1, OWRITE);
       +        if(argc == 1) {
       +                eachitem(print_item, 0, 1);
       +                exits(0);
       +        }
       +        ARGBEGIN{
       +        case 'a':        /* print all */
       +                eachitem(print_item, 1, 0);
       +                break;
       +
       +        case 'n':        /* names only */
       +                eachitem(note, 0, 0);
       +                if(n_items)
       +                        Bputc(&bout, '\n');
       +                break;
       +
       +        default:
       +                fprint(2, "news: bad option %c\n", ARGC());
       +                exits("usage");
       +        }ARGEND
       +        for(i=0; i<argc; i++)
       +                print_item(argv[i]);
       +        exits(0);
       +}
       +
       +int
       +fcmp(const void *a, const void *b)
       +{
       +        long x;
       +
       +        x = ((File*)b)->time - ((File*)a)->time;
       +        if(x < 0)
       +                return -1;
       +        if(x > 0)
       +                return 1;
       +        return 0;
       +}
       +
       +/*
       + *        read_dir: get the file names and modification dates for the
       + *        files in /usr/news into n_list; sort them in reverse by
       + *        modification date.
       + */
       +void
       +read_dir(int update)
       +{
       +        Dir *d;
       +        char newstime[100], *home;
       +        int i, j, n, na, fd;
       +
       +        n_count = 0;
       +        n_list = malloc(NINC*sizeof(File));
       +        na = NINC;
       +        home = getenv("home");
       +        if(home) {
       +                sprint(newstime, TFILE, home);
       +                d = dirstat(newstime);
       +                if(d != nil) {
       +                        n_list[n_count].name = strdup("");
       +                        n_list[n_count].time =d->mtime-1;
       +                        n_list[n_count].length = 0;
       +                        n_count++;
       +                        free(d);
       +                }
       +                if(update) {
       +                        fd = create(newstime, OWRITE, 0644);
       +                        if(fd >= 0)
       +                                close(fd);
       +                }
       +        }
       +        fd = open(NEWS, OREAD);
       +        if(fd < 0) {
       +                fprint(2, "news: ");
       +                perror(NEWS);
       +                exits(NEWS);
       +        }
       +
       +        n = dirreadall(fd, &d);
       +        for(i=0; i<n; i++) {
       +                for(j=0; ignore[j]; j++)
       +                        if(strcmp(ignore[j], d[i].name) == 0)
       +                                goto ign;
       +                if(na <= n_count) {
       +                        na += NINC;
       +                        n_list = realloc(n_list, na*sizeof(File));
       +                }
       +                n_list[n_count].name = strdup(d[i].name);
       +                n_list[n_count].time = d[i].mtime;
       +                n_list[n_count].length = d[i].length;
       +                n_count++;
       +        ign:;
       +        }
       +        free(d);
       +
       +        close(fd);
       +        qsort(n_list, n_count, sizeof(File), fcmp);
       +}
       +
       +void
       +print_item(char *file)
       +{
       +        char name[4096], *p, *ep;
       +        Dir *dbuf;
       +        int f, c;
       +        int bol, bop;
       +
       +        sprint(name, "%s/%s", NEWS, file);
       +        f = open(name, OREAD);
       +        if(f < 0) {
       +                fprint(2, "news: ");
       +                perror(name);
       +                return;
       +        }
       +        strcpy(name, "...");
       +        dbuf = dirfstat(f);
       +        if(dbuf == nil)
       +                return;
       +        Bprint(&bout, "\n%s (%s) %s\n", file,
       +                dbuf->muid[0]? dbuf->muid : dbuf->uid,
       +                asctime(localtime(dbuf->mtime)));
       +        free(dbuf);
       +
       +        bol = 1;        /* beginning of line ...\n */
       +        bop = 1;        /* beginning of page ...\n\n */
       +        for(;;) {
       +                c = read(f, name, sizeof(name));
       +                if(c <= 0)
       +                        break;
       +                p = name;
       +                ep = p+c;
       +                while(p < ep) {
       +                        c = *p++;
       +                        if(c == '\n') {
       +                                if(!bop) {
       +                                        Bputc(&bout, c);
       +                                        if(bol)
       +                                                bop = 1;
       +                                        bol = 1;
       +                                }
       +                                continue;
       +                        }
       +                        if(bol) {
       +                                Bputc(&bout, '\t');
       +                                bol = 0;
       +                                bop = 0;
       +                        }
       +                        Bputc(&bout, c);
       +                }
       +        }
       +        if(!bol)
       +                Bputc(&bout, '\n');
       +        close(f);
       +}
       +
       +void
       +eachitem(void (*emit)(char*), int all, int update)
       +{
       +        int i;
       +
       +        read_dir(update);
       +        for(i=0; i<n_count; i++) {
       +                if(n_list[i].name[0] == 0) {        /* newstime */
       +                        if(all)
       +                                continue;
       +                        break;
       +                }
       +                if(n_list[i].length == 0)                /* in progress */
       +                        continue;
       +                (*emit)(n_list[i].name);
       +        }
       +}
       +
       +void
       +note(char *file)
       +{
       +
       +        if(!n_items)
       +                Bprint(&bout, "news:");
       +        Bprint(&bout, " %s", file);
       +        n_items++;
       +}
 (DIR) diff --git a/src/cmd/primes.c b/src/cmd/primes.c
       t@@ -0,0 +1,131 @@
       +#include        <u.h>
       +#include        <libc.h>
       +
       +#define        ptsiz        (sizeof(pt)/sizeof(pt[0]))
       +#define        whsiz        (sizeof(wheel)/sizeof(wheel[0]))
       +#define        tabsiz        (sizeof(table)/sizeof(table[0]))
       +#define        tsiz8        (tabsiz*8)
       +
       +double        big = 9.007199254740992e15;
       +
       +int        pt[] =
       +{
       +          2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
       +         31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
       +         73, 79, 83, 89, 97,101,103,107,109,113,
       +        127,131,137,139,149,151,157,163,167,173,
       +        179,181,191,193,197,199,211,223,227,229,
       +};
       +double        wheel[] =
       +{
       +        10, 2, 4, 2, 4, 6, 2, 6, 4, 2,
       +         4, 6, 6, 2, 6, 4, 2, 6, 4, 6,
       +         8, 4, 2, 4, 2, 4, 8, 6, 4, 6,
       +         2, 4, 6, 2, 6, 6, 4, 2, 4, 6,
       +         2, 6, 4, 2, 4, 2,10, 2,
       +};
       +uchar        table[1000];
       +uchar        bittab[] =
       +{
       +        1, 2, 4, 8, 16, 32, 64, 128,
       +};
       +
       +void        mark(double nn, long k);
       +void        ouch(void);
       +
       +void
       +main(int argc, char *argp[])
       +{
       +        int i;
       +        double k, temp, v, limit, nn;
       +
       +        if(argc <= 1) {
       +                fprint(2, "usage: primes starting [ending]\n");
       +                exits("usage");
       +        }
       +        nn = atof(argp[1]);
       +        limit = big;
       +        if(argc > 2) {
       +                limit = atof(argp[2]);
       +                if(limit < nn)
       +                        exits(0);
       +                if(limit > big)
       +                        ouch();
       +        }
       +        if(nn < 0 || nn > big)
       +                ouch();
       +        if(nn == 0)
       +                nn = 1;
       +
       +        if(nn < 230) {
       +                for(i=0; i<ptsiz; i++) {
       +                        if(pt[i] < nn)
       +                                continue;
       +                        if(pt[i] > limit)
       +                                exits(0);
       +                        print("%d\n", pt[i]);
       +                        if(limit >= big)
       +                                exits(0);
       +                }
       +                nn = 230;
       +        }
       +
       +        modf(nn/2, &temp);
       +        nn = 2.*temp + 1;
       +/*
       + *        clear the sieve table.
       + */
       +        for(;;) {
       +                for(i=0; i<tabsiz; i++)
       +                        table[i] = 0;
       +/*
       + *        run the sieve.
       + */
       +                v = sqrt(nn+tsiz8);
       +                mark(nn, 3);
       +                mark(nn, 5);
       +                mark(nn, 7);
       +                for(i=0,k=11; k<=v; k+=wheel[i]) {
       +                        mark(nn, k);
       +                        i++;
       +                        if(i >= whsiz)
       +                                i = 0;
       +                }
       +/*
       + *        now get the primes from the table
       + *        and print them.
       + */
       +                for(i=0; i<tsiz8; i+=2) {
       +                        if(table[i>>3] & bittab[i&07])
       +                                continue;
       +                        temp = nn + i;
       +                        if(temp > limit)
       +                                exits(0);
       +                        print("%.0f\n", temp);
       +                        if(limit >= big)
       +                                exits(0);
       +                }
       +                nn += tsiz8;
       +        }
       +}
       +
       +void
       +mark(double nn, long k)
       +{
       +        double t1;
       +        long j;
       +
       +        modf(nn/k, &t1);
       +        j = k*t1 - nn;
       +        if(j < 0)
       +                j += k;
       +        for(; j<tsiz8; j+=k)
       +                table[j>>3] |= bittab[j&07];
       +}
       +
       +void
       +ouch(void)
       +{
       +        fprint(2, "limits exceeded\n");
       +        exits("limits");
       +}
 (DIR) diff --git a/src/cmd/units.y b/src/cmd/units.y
       t@@ -0,0 +1,795 @@
       +%{
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +
       +enum
       +{
       +        Ndim        = 15,                /* number of dimensions */
       +        Nsym        = 40,                /* size of a name */
       +        Nvar        = 203,                /* hash table size */
       +        Maxe        = 695,                /* log of largest number */
       +};
       +
       +typedef        struct        Var        Var;
       +typedef        struct        Node        Node;
       +typedef        struct        Prefix        Prefix;
       +
       +struct        Node
       +{
       +        double        val;
       +        schar        dim[Ndim];
       +};
       +struct        Var
       +{
       +        Rune        name[Nsym];
       +        Node        node;
       +        Var*        link;
       +};
       +struct        Prefix
       +{
       +        double        val;
       +        char*        name;
       +        Rune*        pname;
       +};
       +
       +char        buf[100];
       +int        digval;
       +Biobuf*        fi;
       +Biobuf        linebuf;
       +Var*        fund[Ndim];
       +Rune        line[1000];
       +ulong        lineno;
       +int        linep;
       +int        nerrors;
       +Node        one;
       +int        peekrune;
       +Node        retnode1;
       +Node        retnode2;
       +Node        retnode;
       +Rune        sym[Nsym];
       +Var*        vars[Nvar];
       +int        vflag;
       +
       +#define div unitsdiv
       +
       +extern        void        add(Node*, Node*, Node*);
       +extern        void        div(Node*, Node*, Node*);
       +extern        int        specialcase(Node*, Node*, Node*);
       +extern        double        fadd(double, double);
       +extern        double        fdiv(double, double);
       +extern        double        fmul(double, double);
       +extern        int        gdigit(void*);
       +extern        Var*        lookup(int);
       +extern        void        main(int, char*[]);
       +extern        void        mul(Node*, Node*, Node*);
       +extern        void        ofile(void);
       +extern        double        pname(void);
       +extern        void        printdim(char*, int, int);
       +extern        int        ralpha(int);
       +extern        int        readline(void);
       +extern        void        sub(Node*, Node*, Node*);
       +extern        int        Ufmt(Fmt*);
       +extern        void        xpn(Node*, Node*, int);
       +extern        void        yyerror(char*, ...);
       +extern        int        yylex(void);
       +extern        int        yyparse(void);
       +
       +typedef        Node*        indnode;
       +/* #pragma        varargck        type        "U"        indnode */
       +
       +%}
       +%union
       +{
       +        Node        node;
       +        Var*        var;
       +        int        numb;
       +        double        val;
       +}
       +
       +%type        <node>        prog expr expr0 expr1 expr2 expr3 expr4
       +
       +%token        <val>        VAL
       +%token        <var>        VAR
       +%token        <numb>        SUP
       +%%
       +prog:
       +        ':' VAR expr
       +        {
       +                int f;
       +
       +                f = $2->node.dim[0];
       +                $2->node = $3;
       +                $2->node.dim[0] = 1;
       +                if(f)
       +                        yyerror("redefinition of %S", $2->name);
       +                else
       +                if(vflag)
       +                        print("%S\t%U\n", $2->name, &$2->node);
       +        }
       +|        ':' VAR '#'
       +        {
       +                int f, i;
       +
       +                for(i=1; i<Ndim; i++)
       +                        if(fund[i] == 0)
       +                                break;
       +                if(i >= Ndim) {
       +                        yyerror("too many dimensions");
       +                        i = Ndim-1;
       +                }
       +                fund[i] = $2;
       +
       +                f = $2->node.dim[0];
       +                $2->node = one;
       +                $2->node.dim[0] = 1;
       +                $2->node.dim[i] = 1;
       +                if(f)
       +                        yyerror("redefinition of %S", $2->name);
       +                else
       +                if(vflag)
       +                        print("%S\t#\n", $2->name);
       +        }
       +|        '?' expr
       +        {
       +                retnode1 = $2;
       +        }
       +|        '?'
       +        {
       +                retnode1 = one;
       +        }
       +
       +expr:
       +        expr4
       +|        expr '+' expr4
       +        {
       +                add(&$$, &$1, &$3);
       +        }
       +|        expr '-' expr4
       +        {
       +                sub(&$$, &$1, &$3);
       +        }
       +
       +expr4:
       +        expr3
       +|        expr4 '*' expr3
       +        {
       +                mul(&$$, &$1, &$3);
       +        }
       +|        expr4 '/' expr3
       +        {
       +                div(&$$, &$1, &$3);
       +        }
       +
       +expr3:
       +        expr2
       +|        expr3 expr2
       +        {
       +                mul(&$$, &$1, &$2);
       +        }
       +
       +expr2:
       +        expr1
       +|        expr2 SUP
       +        {
       +                xpn(&$$, &$1, $2);
       +        }
       +|        expr2 '^' expr1
       +        {
       +                int i;
       +
       +                for(i=1; i<Ndim; i++)
       +                        if($3.dim[i]) {
       +                                yyerror("exponent has units");
       +                                $$ = $1;
       +                                break;
       +                        }
       +                if(i >= Ndim) {
       +                        i = $3.val;
       +                        if(i != $3.val)
       +                                yyerror("exponent not integral");
       +                        xpn(&$$, &$1, i);
       +                }
       +        }
       +
       +expr1:
       +        expr0
       +|        expr1 '|' expr0
       +        {
       +                div(&$$, &$1, &$3);
       +        }
       +
       +expr0:
       +        VAR
       +        {
       +                if($1->node.dim[0] == 0) {
       +                        yyerror("undefined %S", $1->name);
       +                        $$ = one;
       +                } else
       +                        $$ = $1->node;
       +        }
       +|        VAL
       +        {
       +                $$ = one;
       +                $$.val = $1;
       +        }
       +|        '(' expr ')'
       +        {
       +                $$ = $2;
       +        }
       +%%
       +
       +int
       +yylex(void)
       +{
       +        int c, i;
       +
       +        c = peekrune;
       +        peekrune = ' ';
       +
       +loop:
       +        if((c >= '0' && c <= '9') || c == '.')
       +                goto numb;
       +        if(ralpha(c))
       +                goto alpha;
       +        switch(c) {
       +        case ' ':
       +        case '\t':
       +                c = line[linep++];
       +                goto loop;
       +        case 0xd7:
       +                return 0x2a;
       +        case 0xf7:
       +                return 0x2f;
       +        case 0xb9:
       +        case 0x2071:
       +                yylval.numb = 1;
       +                return SUP;
       +        case 0xb2:
       +        case 0x2072:
       +                yylval.numb = 2;
       +                return SUP;
       +        case 0xb3:
       +        case 0x2073:
       +                yylval.numb = 3;
       +                return SUP;
       +        }
       +        return c;
       +
       +alpha:
       +        memset(sym, 0, sizeof(sym));
       +        for(i=0;; i++) {
       +                if(i < nelem(sym))
       +                        sym[i] = c;
       +                c = line[linep++];
       +                if(!ralpha(c))
       +                        break;
       +        }
       +        sym[nelem(sym)-1] = 0;
       +        peekrune = c;
       +        yylval.var = lookup(0);
       +        return VAR;
       +
       +numb:
       +        digval = c;
       +        yylval.val = fmtcharstod(gdigit, 0);
       +        return VAL;
       +}
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        char *file;
       +
       +        ARGBEGIN {
       +        default:
       +                print("usage: units [-v] [file]\n");
       +                exits("usage");
       +        case 'v':
       +                vflag = 1;
       +                break;
       +        } ARGEND
       +
       +        file = unsharp("#9/lib/units");
       +        if(argc > 0)
       +                file = argv[0];
       +        fi = Bopen(file, OREAD);
       +        if(fi == 0) {
       +                print("cant open: %s\n", file);
       +                exits("open");
       +        }
       +        fmtinstall('U', Ufmt);
       +        one.val = 1;
       +
       +        /*
       +         * read the 'units' file to
       +         * develope a database
       +         */
       +        lineno = 0;
       +        for(;;) {
       +                lineno++;
       +                if(readline())
       +                        break;
       +                if(line[0] == 0 || line[0] == '/')
       +                        continue;
       +                peekrune = ':';
       +                yyparse();
       +        }
       +
       +        /*
       +         * read the console to
       +         * print ratio of pairs
       +         */
       +        Bterm(fi);
       +        fi = &linebuf;
       +        Binit(fi, 0, OREAD);
       +        lineno = 0;
       +        for(;;) {
       +                if(lineno & 1)
       +                        print("you want: ");
       +                else
       +                        print("you have: ");
       +                if(readline())
       +                        break;
       +                peekrune = '?';
       +                nerrors = 0;
       +                yyparse();
       +                if(nerrors)
       +                        continue;
       +                if(lineno & 1) {
       +                        if(specialcase(&retnode, &retnode2, &retnode1))
       +                                print("\tis %U\n", &retnode);
       +                        else {
       +                                div(&retnode, &retnode2, &retnode1);
       +                                print("\t* %U\n", &retnode);
       +                                div(&retnode, &retnode1, &retnode2);
       +                                print("\t/ %U\n", &retnode);
       +                        }
       +                } else
       +                        retnode2 = retnode1;
       +                lineno++;
       +        }
       +        print("\n");
       +        exits(0);
       +}
       +
       +/*
       + * all characters that have some
       + * meaning. rest are usable as names
       + */
       +int
       +ralpha(int c)
       +{
       +        switch(c) {
       +        case 0:
       +        case '+':
       +        case '-':
       +        case '*':
       +        case '/':
       +        case '[':
       +        case ']':
       +        case '(':
       +        case ')':
       +        case '^':
       +        case ':':
       +        case '?':
       +        case ' ':
       +        case '\t':
       +        case '.':
       +        case '|':
       +        case '#':
       +        case 0xb9:
       +        case 0x2071:
       +        case 0xb2:
       +        case 0x2072:
       +        case 0xb3:
       +        case 0x2073:
       +        case 0xd7:
       +        case 0xf7:
       +                return 0;
       +        }
       +        return 1;
       +}
       +
       +int
       +gdigit(void *v)
       +{
       +        int c;
       +
       +        USED(v);
       +        c = digval;
       +        if(c) {
       +                digval = 0;
       +                return c;
       +        }
       +        c = line[linep++];
       +        peekrune = c;
       +        return c;
       +}
       +
       +void
       +yyerror(char *fmt, ...)
       +{
       +        va_list arg;
       +
       +        /*
       +         * hack to intercept message from yaccpar
       +         */
       +        if(strcmp(fmt, "syntax error") == 0) {
       +                yyerror("syntax error, last name: %S", sym);
       +                return;
       +        }
       +        va_start(arg, fmt);
       +        vseprint(buf, buf+sizeof(buf), fmt, arg);
       +        va_end(arg);
       +        print("%ld: %S\n\t%s\n", lineno, line, buf);
       +        nerrors++;
       +        if(nerrors > 5) {
       +                print("too many errors\n");
       +                exits("errors");
       +        }
       +}
       +
       +void
       +add(Node *c, Node *a, Node *b)
       +{
       +        int i, d;
       +
       +        for(i=0; i<Ndim; i++) {
       +                d = a->dim[i];
       +                c->dim[i] = d;
       +                if(d != b->dim[i])
       +                        yyerror("add must be like units");
       +        }
       +        c->val = fadd(a->val, b->val);
       +}
       +
       +void
       +sub(Node *c, Node *a, Node *b)
       +{
       +        int i, d;
       +
       +        for(i=0; i<Ndim; i++) {
       +                d = a->dim[i];
       +                c->dim[i] = d;
       +                if(d != b->dim[i])
       +                        yyerror("sub must be like units");
       +        }
       +        c->val = fadd(a->val, -b->val);
       +}
       +
       +void
       +mul(Node *c, Node *a, Node *b)
       +{
       +        int i;
       +
       +        for(i=0; i<Ndim; i++)
       +                c->dim[i] = a->dim[i] + b->dim[i];
       +        c->val = fmul(a->val, b->val);
       +}
       +
       +void
       +div(Node *c, Node *a, Node *b)
       +{
       +        int i;
       +
       +        for(i=0; i<Ndim; i++)
       +                c->dim[i] = a->dim[i] - b->dim[i];
       +        c->val = fdiv(a->val, b->val);
       +}
       +
       +void
       +xpn(Node *c, Node *a, int b)
       +{
       +        int i;
       +
       +        *c = one;
       +        if(b < 0) {
       +                b = -b;
       +                for(i=0; i<b; i++)
       +                        div(c, c, a);
       +        } else
       +        for(i=0; i<b; i++)
       +                mul(c, c, a);
       +}
       +
       +int
       +specialcase(Node *c, Node *a, Node *b)
       +{
       +        int i, d, d1, d2;
       +
       +        d1 = 0;
       +        d2 = 0;
       +        for(i=1; i<Ndim; i++) {
       +                d = a->dim[i];
       +                if(d) {
       +                        if(d != 1 || d1)
       +                                return 0;
       +                        d1 = i;
       +                }
       +                d = b->dim[i];
       +                if(d) {
       +                        if(d != 1 || d2)
       +                                return 0;
       +                        d2 = i;
       +                }
       +        }
       +        if(d1 == 0 || d2 == 0)
       +                return 0;
       +
       +        if(memcmp(fund[d1]->name, L"°C", 3*sizeof(Rune)) == 0 &&
       +           memcmp(fund[d2]->name, L"°F", 3*sizeof(Rune)) == 0 &&
       +           b->val == 1) {
       +                memcpy(c->dim, b->dim, sizeof(c->dim));
       +                c->val = a->val * 9. / 5. + 32.;
       +                return 1;
       +        }
       +
       +        if(memcmp(fund[d1]->name, L"°F", 3*sizeof(Rune)) == 0 &&
       +           memcmp(fund[d2]->name, L"°C", 3*sizeof(Rune)) == 0 &&
       +           b->val == 1) {
       +                memcpy(c->dim, b->dim, sizeof(c->dim));
       +                c->val = (a->val - 32.) * 5. / 9.;
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +void
       +printdim(char *str, int d, int n)
       +{
       +        Var *v;
       +
       +        if(n) {
       +                v = fund[d];
       +                if(v)
       +                        sprint(strchr(str, 0), " %S", v->name);
       +                else
       +                        sprint(strchr(str, 0), " [%d]", d);
       +                switch(n) {
       +                case 1:
       +                        break;
       +                case 2:
       +                        strcat(str, "²");
       +                        break;
       +                case 3:
       +                        strcat(str, "³");
       +                        break;
       +                default:
       +                        sprint(strchr(str, 0), "^%d", n);
       +                }
       +        }
       +}
       +
       +int
       +Ufmt(Fmt *fp)
       +{
       +        char str[200];
       +        Node *n;
       +        int f, i, d;
       +
       +        n = va_arg(fp->args, Node*);
       +        sprint(str, "%g", n->val);
       +
       +        f = 0;
       +        for(i=1; i<Ndim; i++) {
       +                d = n->dim[i];
       +                if(d > 0)
       +                        printdim(str, i, d);
       +                else
       +                if(d < 0)
       +                        f = 1;
       +        }
       +
       +        if(f) {
       +                strcat(str, " /");
       +                for(i=1; i<Ndim; i++) {
       +                        d = n->dim[i];
       +                        if(d < 0)
       +                                printdim(str, i, -d);
       +                }
       +        }
       +
       +        return fmtstrcpy(fp, str);
       +}
       +
       +int
       +readline(void)
       +{
       +        int i, c;
       +
       +        linep = 0;
       +        for(i=0;; i++) {
       +                c = Bgetrune(fi);
       +                if(c < 0)
       +                        return 1;
       +                if(c == '\n')
       +                        break;
       +                if(i < nelem(line))
       +                        line[i] = c;
       +        }
       +        if(i >= nelem(line))
       +                i = nelem(line)-1;
       +        line[i] = 0;
       +        return 0;
       +}
       +
       +Var*
       +lookup(int f)
       +{
       +        int i;
       +        Var *v, *w;
       +        double p;
       +        ulong h;
       +
       +        h = 0;
       +        for(i=0; sym[i]; i++)
       +                h = h*13 + sym[i];
       +        h %= nelem(vars);
       +
       +        for(v=vars[h]; v; v=v->link)
       +                if(memcmp(sym, v->name, sizeof(sym)) == 0)
       +                        return v;
       +        if(f)
       +                return 0;
       +        v = malloc(sizeof(*v));
       +        if(v == nil) {
       +                fprint(2, "out of memory\n");
       +                exits("mem");
       +        }
       +        memset(v, 0, sizeof(*v));
       +        memcpy(v->name, sym, sizeof(sym));
       +        v->link = vars[h];
       +        vars[h] = v;
       +
       +        p = 1;
       +        for(;;) {
       +                p = fmul(p, pname());
       +                if(p == 0)
       +                        break;
       +                w = lookup(1);
       +                if(w) {
       +                        v->node = w->node;
       +                        v->node.val = fmul(v->node.val, p);
       +                        break;
       +                }
       +        }
       +        return v;
       +}
       +
       +Prefix        prefix[] =
       +{
       +        1e-24,        "yocto", 0,
       +        1e-21,        "zepto", 0,
       +        1e-18,        "atto", 0,
       +        1e-15,        "femto", 0,
       +        1e-12,        "pico", 0,
       +        1e-9,        "nano", 0,
       +        1e-6,        "micro", 0,
       +        1e-6,        "μ", 0,
       +        1e-3,        "milli", 0,
       +        1e-2,        "centi", 0,
       +        1e-1,        "deci", 0,
       +        1e1,        "deka", 0,
       +        1e2,        "hecta", 0,
       +        1e2,        "hecto", 0,
       +        1e3,        "kilo", 0,
       +        1e6,        "mega", 0,
       +        1e6,        "meg", 0,
       +        1e9,        "giga", 0,
       +        1e12,        "tera", 0,
       +        1e15,        "peta", 0,
       +        1e18,        "exa", 0,
       +        1e21,        "zetta", 0,
       +        1e24,        "yotta", 0,
       +        0,        0, 0,
       +};
       +
       +double
       +pname(void)
       +{
       +        Rune *p;
       +        int i, j, c;
       +
       +        /*
       +         * rip off normal prefixs
       +         */
       +        if(prefix[0].pname == nil){
       +                for(i=0; prefix[i].name; i++)
       +                        prefix[i].pname = runesmprint("%s", prefix[i].name);
       +        }
       +
       +        for(i=0; p=prefix[i].pname; i++) {
       +                for(j=0; c=p[j]; j++)
       +                        if(c != sym[j])
       +                                goto no;
       +                memmove(sym, sym+j, (Nsym-j)*sizeof(*sym));
       +                memset(sym+(Nsym-j), 0, j*sizeof(*sym));
       +                return prefix[i].val;
       +        no:;
       +        }
       +
       +        /*
       +         * rip off 's' suffixes
       +         */
       +        for(j=0; sym[j]; j++)
       +                ;
       +        j--;
       +        /* j>1 is special hack to disallow ms finding m */
       +        if(j > 1 && sym[j] == 's') {
       +                sym[j] = 0;
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +/*
       + * careful floating point
       + */
       +double
       +fmul(double a, double b)
       +{
       +        double l;
       +
       +        if(a <= 0) {
       +                if(a == 0)
       +                        return 0;
       +                l = log(-a);
       +        } else
       +                l = log(a);
       +
       +        if(b <= 0) {
       +                if(b == 0)
       +                        return 0;
       +                l += log(-b);
       +        } else
       +                l += log(b);
       +
       +        if(l > Maxe) {
       +                yyerror("overflow in multiply");
       +                return 1;
       +        }
       +        if(l < -Maxe) {
       +                yyerror("underflow in multiply");
       +                return 0;
       +        }
       +        return a*b;
       +}
       +
       +double
       +fdiv(double a, double b)
       +{
       +        double l;
       +
       +        if(a <= 0) {
       +                if(a == 0)
       +                        return 0;
       +                l = log(-a);
       +        } else
       +                l = log(a);
       +
       +        if(b <= 0) {
       +                if(b == 0) {
       +                        yyerror("division by zero");
       +                        return 1;
       +                }
       +                l -= log(-b);
       +        } else
       +                l -= log(b);
       +
       +        if(l > Maxe) {
       +                yyerror("overflow in divide");
       +                return 1;
       +        }
       +        if(l < -Maxe) {
       +                yyerror("underflow in divide");
       +                return 0;
       +        }
       +        return a/b;
       +}
       +
       +double
       +fadd(double a, double b)
       +{
       +        return a + b;
       +}