+#include <stdio.h>
+
+#define NDIM 10
+#define NTAB 601
+char *dfile = "/usr/lib/units";
+char *unames[NDIM];
+double getflt();
+int fperr();
+struct table *hash();
+struct unit
+{
+ double factor;
+ char dim[NDIM];
+};
+
+struct table
+{
+ double factor;
+ char dim[NDIM];
+ char *name;
+} table[NTAB];
+char names[NTAB*10];
+struct prefix
+{
+ double factor;
+ char *pname;
+} prefix[] =
+{
+ 1e-18, "atto",
+ 1e-15, "femto",
+ 1e-12, "pico",
+ 1e-9, "nano",
+ 1e-6, "micro",
+ 1e-3, "milli",
+ 1e-2, "centi",
+ 1e-1, "deci",
+ 1e1, "deka",
+ 1e2, "hecta",
+ 1e2, "hecto",
+ 1e3, "kilo",
+ 1e6, "mega",
+ 1e6, "meg",
+ 1e9, "giga",
+ 1e12, "tera",
+ 0.0, 0
+};
+FILE *inp;
+int fperrc;
+int peekc;
+int dumpflg;
+
+main(argc, argv)
+char *argv[];
+{
+ register i;
+ register char *file;
+ struct unit u1, u2;
+ double f;
+
+ if(argc>1 && *argv[1]=='-') {
+ argc--;
+ argv++;
+ dumpflg++;
+ }
+ file = dfile;
+ if(argc > 1)
+ file = argv[1];
+ if ((inp = fopen(file, "r")) == NULL) {
+ printf("no table\n");
+ exit(1);
+ }
+ signal(8, fperr);
+ init();
+
+loop:
+ fperrc = 0;
+ printf("you have: ");
+ if(convr(&u1))
+ goto loop;
+ if(fperrc)
+ goto fp;
+loop1:
+ printf("you want: ");
+ if(convr(&u2))
+ goto loop1;
+ for(i=0; i<NDIM; i++)
+ if(u1.dim[i] != u2.dim[i])
+ goto conform;
+ f = u1.factor/u2.factor;
+ if(fperrc)
+ goto fp;
+ printf("\t* %e\n", f);
+ printf("\t/ %e\n", 1./f);
+ goto loop;
+
+conform:
+ if(fperrc)
+ goto fp;
+ printf("conformability\n");
+ units(&u1);
+ units(&u2);
+ goto loop;
+
+fp:
+ printf("underflow or overflow\n");
+ goto loop;
+}
+
+units(up)
+struct unit *up;
+{
+ register struct unit *p;
+ register f, i;
+
+ p = up;
+ printf("\t%e ", p->factor);
+ f = 0;
+ for(i=0; i<NDIM; i++)
+ f |= pu(p->dim[i], i, f);
+ if(f&1) {
+ putchar('/');
+ f = 0;
+ for(i=0; i<NDIM; i++)
+ f |= pu(-p->dim[i], i, f);
+ }
+ putchar('\n');
+}
+
+pu(u, i, f)
+{
+
+ if(u > 0) {
+ if(f&2)
+ putchar('-');
+ if(unames[i])
+ printf("%s", unames[i]); else
+ printf("*%c*", i+'a');
+ if(u > 1)
+ putchar(u+'0');
+ return(2);
+ }
+ if(u < 0)
+ return(1);
+ return(0);
+}
+
+convr(up)
+struct unit *up;
+{
+ register struct unit *p;
+ register c;
+ register char *cp;
+ char name[20];
+ int den, err;
+
+ p = up;
+ for(c=0; c<NDIM; c++)
+ p->dim[c] = 0;
+ p->factor = getflt();
+ if(p->factor == 0.)
+ p->factor = 1.0;
+ err = 0;
+ den = 0;
+ cp = name;
+
+loop:
+ switch(c=get()) {
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '/':
+ case ' ':
+ case '\t':
+ case '\n':
+ if(cp != name) {
+ *cp++ = 0;
+ cp = name;
+ err |= lookup(cp, p, den, c);
+ }
+ if(c == '/')
+ den++;
+ if(c == '\n')
+ return(err);
+ goto loop;
+ }
+ *cp++ = c;
+ goto loop;
+}
+
+lookup(name, up, den, c)
+char *name;
+struct unit *up;
+{
+ register struct unit *p;
+ register struct table *q;
+ register i;
+ char *cp1, *cp2;
+ double e;
+
+ p = up;
+ e = 1.0;
+
+loop:
+ q = hash(name);
+ if(q->name) {
+ l1:
+ if(den) {
+ p->factor /= q->factor*e;
+ for(i=0; i<NDIM; i++)
+ p->dim[i] -= q->dim[i];
+ } else {
+ p->factor *= q->factor*e;
+ for(i=0; i<NDIM; i++)
+ p->dim[i] += q->dim[i];
+ }
+ if(c >= '2' && c <= '9') {
+ c--;
+ goto l1;
+ }
+ return(0);
+ }
+ for(i=0; cp1 = prefix[i].pname; i++) {
+ cp2 = name;
+ while(*cp1 == *cp2++)
+ if(*cp1++ == 0) {
+ cp1--;
+ break;
+ }
+ if(*cp1 == 0) {
+ e *= prefix[i].factor;
+ name = cp2-1;
+ goto loop;
+ }
+ }
+ for(cp1 = name; *cp1; cp1++);
+ if(cp1 > name+1 && *--cp1 == 's') {
+ *cp1 = 0;
+ goto loop;
+ }
+ printf("cannot recognize %s\n", name);
+ return(1);
+}
+
+equal(s1, s2)
+char *s1, *s2;
+{
+ register char *c1, *c2;
+
+ c1 = s1;
+ c2 = s2;
+ while(*c1++ == *c2)
+ if(*c2++ == 0)
+ return(1);
+ return(0);
+}
+
+init()
+{
+ register char *cp;
+ register struct table *tp, *lp;
+ int c, i, f, t;
+ char *np;
+
+ cp = names;
+ for(i=0; i<NDIM; i++) {
+ np = cp;
+ *cp++ = '*';
+ *cp++ = i+'a';
+ *cp++ = '*';
+ *cp++ = 0;
+ lp = hash(np);
+ lp->name = np;
+ lp->factor = 1.0;
+ lp->dim[i] = 1;
+ }
+ lp = hash("");
+ lp->name = cp-1;
+ lp->factor = 1.0;
+
+l0:
+ c = get();
+ if(c == 0) {
+ printf("%l units; %l bytes\n\n", i, cp-names);
+ if(dumpflg)
+ for(tp = &table[0]; tp < &table[NTAB]; tp++) {
+ if(tp->name == 0)
+ continue;
+ printf("%s", tp->name);
+ units(tp);
+ }
+ fclose(inp);
+ inp = stdin;
+ return;
+ }
+ if(c == '/') {
+ while(c != '\n' && c != 0)
+ c = get();
+ goto l0;
+ }
+ if(c == '\n')
+ goto l0;
+ np = cp;
+ while(c != ' ' && c != '\t') {
+ *cp++ = c;
+ c = get();
+ if (c==0)
+ goto l0;
+ if(c == '\n') {
+ *cp++ = 0;
+ tp = hash(np);
+ if(tp->name)
+ goto redef;
+ tp->name = np;
+ tp->factor = lp->factor;
+ for(c=0; c<NDIM; c++)
+ tp->dim[c] = lp->dim[c];
+ i++;
+ goto l0;
+ }
+ }
+ *cp++ = 0;
+ lp = hash(np);
+ if(lp->name)
+ goto redef;
+ convr(lp);
+ lp->name = np;
+ f = 0;
+ i++;
+ if(lp->factor != 1.0)
+ goto l0;
+ for(c=0; c<NDIM; c++) {
+ t = lp->dim[c];
+ if(t>1 || (f>0 && t!=0))
+ goto l0;
+ if(f==0 && t==1) {
+ if(unames[c])
+ goto l0;
+ f = c+1;
+ }
+ }
+ if(f>0)
+ unames[f-1] = np;
+ goto l0;
+
+redef:
+ printf("redefinition %s\n", np);
+ goto l0;
+}
+
+double
+getflt()
+{
+ register c, i, dp;
+ double d, e;
+ int f;
+
+ d = 0.;
+ dp = 0;
+ do
+ c = get();
+ while(c == ' ' || c == '\t');
+
+l1:
+ if(c >= '0' && c <= '9') {
+ d = d*10. + c-'0';
+ if(dp)
+ dp++;
+ c = get();
+ goto l1;
+ }
+ if(c == '.') {
+ dp++;
+ c = get();
+ goto l1;
+ }
+ if(dp)
+ dp--;
+ if(c == '+' || c == '-') {
+ f = 0;
+ if(c == '-')
+ f++;
+ i = 0;
+ c = get();
+ while(c >= '0' && c <= '9') {
+ i = i*10 + c-'0';
+ c = get();
+ }
+ if(f)
+ i = -i;
+ dp -= i;
+ }
+ e = 1.;
+ i = dp;
+ if(i < 0)
+ i = -i;
+ while(i--)
+ e *= 10.;
+ if(dp < 0)
+ d *= e; else
+ d /= e;
+ if(c == '|')
+ return(d/getflt());
+ peekc = c;
+ return(d);
+}
+
+get()
+{
+ register c;
+
+ if(c=peekc) {
+ peekc = 0;
+ return(c);
+ }
+ c = getc(inp);
+ if (c == EOF) {
+ if (inp == stdin) {
+ printf("\n");
+ exit(0);
+ }
+ return(0);
+ }
+ return(c);
+}
+
+struct table *
+hash(name)
+char *name;
+{
+ register struct table *tp;
+ register char *np;
+ register unsigned h;
+
+ h = 0;
+ np = name;
+ while(*np)
+ h = h*57 + *np++ - '0';
+ if( ((int)h)<0) h= -(int)h;
+ h %= NTAB;
+ tp = &table[h];
+l0:
+ if(tp->name == 0)
+ return(tp);
+ if(equal(name, tp->name))
+ return(tp);
+ tp++;
+ if(tp >= &table[NTAB])
+ tp = table;
+ goto l0;
+}
+
+fperr()
+{
+
+ signal(8, fperr);
+ fperrc++;
+}