mirror of
https://github.com/bobbimanners/GNO-Extras.git
synced 2024-12-22 17:30:13 +00:00
465 lines
6.5 KiB
Plaintext
465 lines
6.5 KiB
Plaintext
#include <stdio.h>
|
|
|
|
#define NDIM 10
|
|
#define NTAB 601
|
|
char *dfile = "/usr/local/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';
|
|
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++;
|
|
}
|