aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-21 23:22:06 +0000
committerrsc <devnull@localhost>2004-04-21 23:22:06 +0000
commit17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b (patch)
tree921c649de0d83bdde4561f5868e5ff3ab9986af8 /src/cmd
parent3e63e5c271f7a7013dc4b3fedfb83c2d547b8c26 (diff)
downloadplan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.tar.gz
plan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.tar.bz2
plan9port-17e5fb8973d9e48ef53a88eb78f845f8a7b41a5b.zip
add new guys
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/bc.y983
-rw-r--r--src/cmd/jpg/mkfile4
-rw-r--r--src/cmd/mkfile24
-rw-r--r--src/cmd/mtime.c33
-rw-r--r--src/cmd/news.c231
-rw-r--r--src/cmd/primes.c131
-rw-r--r--src/cmd/units.y795
7 files changed, 2195 insertions, 6 deletions
diff --git a/src/cmd/bc.y b/src/cmd/bc.y
new file mode 100644
index 00000000..5eddf471
--- /dev/null
+++ b/src/cmd/bc.y
@@ -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);
+}
diff --git a/src/cmd/jpg/mkfile b/src/cmd/jpg/mkfile
index 198f8e2f..cdefe413 100644
--- a/src/cmd/jpg/mkfile
+++ b/src/cmd/jpg/mkfile
@@ -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
diff --git a/src/cmd/mkfile b/src/cmd/mkfile
index 1b064ebc..ab348260 100644
--- a/src/cmd/mkfile
+++ b/src/cmd/mkfile
@@ -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
@@ -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]
+
+
diff --git a/src/cmd/mtime.c b/src/cmd/mtime.c
new file mode 100644
index 00000000..db5ea490
--- /dev/null
+++ b/src/cmd/mtime.c
@@ -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);
+}
diff --git a/src/cmd/news.c b/src/cmd/news.c
new file mode 100644
index 00000000..c6a99a30
--- /dev/null
+++ b/src/cmd/news.c
@@ -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++;
+}
diff --git a/src/cmd/primes.c b/src/cmd/primes.c
new file mode 100644
index 00000000..0e926545
--- /dev/null
+++ b/src/cmd/primes.c
@@ -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");
+}
diff --git a/src/cmd/units.y b/src/cmd/units.y
new file mode 100644
index 00000000..372295fd
--- /dev/null
+++ b/src/cmd/units.y
@@ -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;
+}