/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <locale.h>
#include <signal.h>
#define NDIM 10
#define NTAB 1009
char *dfile = "/usr/share/lib/unittab";
char *unames[NDIM];
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-21, "zepto",
1e-24, "yocto",
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",
1e1, "deca",
1e2, "hecta",
1e2, "hecto",
1e3, "kilo",
1e6, "mega",
1e6, "meg",
1e9, "giga",
1e12, "tera",
1e15, "peta",
1e18, "exa",
1e21, "zetta",
1e24, "yotta",
1<<10, "kibi",
1L<<20, "mebi",
1L<<30, "gibi",
1LL<<40,"tebi",
0.0, 0
};
FILE *inp;
int fperrc;
int peekc;
int dumpflg;
void fperr(int sig);
double getflt(void);
struct table *hash(char *name);
int get(void);
void init(void);
int equal(char *s1, char *s2);
int lookup(char *name, struct unit *up, int den, int c);
int convr(struct unit *up);
int pu(int u, int i, int f);
void units(struct unit *up);
int
main(int argc, char *argv[])
{
int i;
char *file;
struct unit u1, u2;
double f;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if(argc>1 && *argv[1]=='-') {
argc--;
argv++;
dumpflg++;
}
file = dfile;
if(argc > 1)
file = argv[1];
if ((inp = fopen(file, "r")) == NULL) {
printf(gettext("no table\n"));
exit(1);
}
signal(8, fperr);
init();
loop:
fperrc = 0;
printf(gettext("you have: "));
if(convr(&u1))
goto loop;
if(fperrc)
goto fp;
loop1:
printf(gettext("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 || f == 0.0)
goto fp;
printf("\t* %e\n", f);
printf("\t/ %e\n", 1./f);
goto loop;
conform:
if(fperrc)
goto fp;
printf(gettext("conformability\n"));
units(&u1);
units(&u2);
goto loop;
fp:
printf(gettext("underflow or overflow\n"));
goto loop;
}
void
units(struct unit *up)
{
struct unit *p;
int 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');
}
int
pu(int u, int i, int f)
{
if(u > 0) {
if(f&2)
putchar('-');
if(unames[i])
printf("%s", unames[i]); else
printf(gettext("*%c*"), i+'a');
if(u > 1)
putchar(u+'0');
return(2);
}
if(u < 0)
return(1);
return(0);
}
int
convr(struct unit *up)
{
struct unit *p;
int c;
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;
}
int
lookup(char *name, struct unit *up, int den, int c)
{
struct unit *p;
struct table *q;
int 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(gettext("cannot recognize %s\n"), name);
return(1);
}
int
equal(char *s1, char *s2)
{
char *c1, *c2;
c1 = s1;
c2 = s2;
while(*c1++ == *c2)
if(*c2++ == 0)
return(1);
return(0);
}
void
init(void)
{
char *cp;
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) {
if(dumpflg) {
printf(gettext("%d units; %d bytes\n\n"), i, cp-names);
for(tp = &table[0]; tp < &table[NTAB]; tp++) {
if(tp->name == 0)
continue;
printf("%s", tp->name);
units((struct unit *)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((struct unit *)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(gettext("redefinition %s\n"), np);
goto l0;
}
double
getflt(void)
{
int 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);
}
int
get(void)
{
int 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(char *name)
{
struct table *tp;
char *np;
unsigned int 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;
}
void
fperr(int sig)
{
signal(8, fperr);
fperrc++;
}