xref: /csrg-svn/usr.bin/units/units.c (revision 48325)
1*48325Sbostic /*-
2*48325Sbostic  * %sccs.include.proprietary.c%
3*48325Sbostic  */
4*48325Sbostic 
5*48325Sbostic #ifndef lint
6*48325Sbostic static char sccsid[] = "@(#)units.c	4.3 (Berkeley) 04/18/91";
7*48325Sbostic #endif /* not lint */
8*48325Sbostic 
91147Sbill #include <stdio.h>
1037910Sbostic #include "pathnames.h"
111147Sbill 
121147Sbill #define	NDIM	10
131147Sbill #define	NTAB	601
1437910Sbostic char	*dfile	= _PATH_UNITS;
151147Sbill char	*unames[NDIM];
161147Sbill double	getflt();
171147Sbill int	fperr();
181147Sbill struct	table	*hash();
191147Sbill struct unit
201147Sbill {
211147Sbill 	double	factor;
221147Sbill 	char	dim[NDIM];
231147Sbill };
241147Sbill 
251147Sbill struct table
261147Sbill {
271147Sbill 	double	factor;
281147Sbill 	char	dim[NDIM];
291147Sbill 	char	*name;
301147Sbill } table[NTAB];
311147Sbill char	names[NTAB*10];
321147Sbill struct prefix
331147Sbill {
341147Sbill 	double	factor;
351147Sbill 	char	*pname;
361147Sbill } prefix[] =
371147Sbill {
381147Sbill 	1e-18,	"atto",
391147Sbill 	1e-15,	"femto",
401147Sbill 	1e-12,	"pico",
411147Sbill 	1e-9,	"nano",
421147Sbill 	1e-6,	"micro",
431147Sbill 	1e-3,	"milli",
441147Sbill 	1e-2,	"centi",
451147Sbill 	1e-1,	"deci",
461147Sbill 	1e1,	"deka",
471147Sbill 	1e2,	"hecta",
481147Sbill 	1e2,	"hecto",
491147Sbill 	1e3,	"kilo",
501147Sbill 	1e6,	"mega",
511147Sbill 	1e6,	"meg",
521147Sbill 	1e9,	"giga",
531147Sbill 	1e12,	"tera",
541147Sbill 	0.0,	0
551147Sbill };
561147Sbill FILE	*inp;
571147Sbill int	fperrc;
581147Sbill int	peekc;
591147Sbill int	dumpflg;
601147Sbill 
main(argc,argv)611147Sbill main(argc, argv)
621147Sbill char *argv[];
631147Sbill {
641147Sbill 	register i;
651147Sbill 	register char *file;
661147Sbill 	struct unit u1, u2;
671147Sbill 	double f;
681147Sbill 
691147Sbill 	if(argc>1 && *argv[1]=='-') {
701147Sbill 		argc--;
711147Sbill 		argv++;
721147Sbill 		dumpflg++;
731147Sbill 	}
741147Sbill 	file = dfile;
751147Sbill 	if(argc > 1)
761147Sbill 		file = argv[1];
771147Sbill 	if ((inp = fopen(file, "r")) == NULL) {
781147Sbill 		printf("no table\n");
791147Sbill 		exit(1);
801147Sbill 	}
811147Sbill 	signal(8, fperr);
821147Sbill 	init();
831147Sbill 
841147Sbill loop:
851147Sbill 	fperrc = 0;
861147Sbill 	printf("you have: ");
871147Sbill 	if(convr(&u1))
881147Sbill 		goto loop;
891147Sbill 	if(fperrc)
901147Sbill 		goto fp;
911147Sbill loop1:
921147Sbill 	printf("you want: ");
931147Sbill 	if(convr(&u2))
941147Sbill 		goto loop1;
951147Sbill 	for(i=0; i<NDIM; i++)
961147Sbill 		if(u1.dim[i] != u2.dim[i])
971147Sbill 			goto conform;
981147Sbill 	f = u1.factor/u2.factor;
991147Sbill 	if(fperrc)
1001147Sbill 		goto fp;
1011147Sbill 	printf("\t* %e\n", f);
1021147Sbill 	printf("\t/ %e\n", 1./f);
1031147Sbill 	goto loop;
1041147Sbill 
1051147Sbill conform:
1061147Sbill 	if(fperrc)
1071147Sbill 		goto fp;
1081147Sbill 	printf("conformability\n");
1091147Sbill 	units(&u1);
1101147Sbill 	units(&u2);
1111147Sbill 	goto loop;
1121147Sbill 
1131147Sbill fp:
1141147Sbill 	printf("underflow or overflow\n");
1151147Sbill 	goto loop;
1161147Sbill }
1171147Sbill 
1181147Sbill units(up)
1191147Sbill struct unit *up;
1201147Sbill {
1211147Sbill 	register struct unit *p;
1221147Sbill 	register f, i;
1231147Sbill 
1241147Sbill 	p = up;
1251147Sbill 	printf("\t%e ", p->factor);
1261147Sbill 	f = 0;
1271147Sbill 	for(i=0; i<NDIM; i++)
1281147Sbill 		f |= pu(p->dim[i], i, f);
1291147Sbill 	if(f&1) {
1301147Sbill 		putchar('/');
1311147Sbill 		f = 0;
1321147Sbill 		for(i=0; i<NDIM; i++)
1331147Sbill 			f |= pu(-p->dim[i], i, f);
1341147Sbill 	}
1351147Sbill 	putchar('\n');
1361147Sbill }
1371147Sbill 
pu(u,i,f)1381147Sbill pu(u, i, f)
1391147Sbill {
1401147Sbill 
1411147Sbill 	if(u > 0) {
1421147Sbill 		if(f&2)
1431147Sbill 			putchar('-');
1441147Sbill 		if(unames[i])
1451147Sbill 			printf("%s", unames[i]); else
1461147Sbill 			printf("*%c*", i+'a');
1471147Sbill 		if(u > 1)
1481147Sbill 			putchar(u+'0');
1491147Sbill 			return(2);
1501147Sbill 	}
1511147Sbill 	if(u < 0)
1521147Sbill 		return(1);
1531147Sbill 	return(0);
1541147Sbill }
1551147Sbill 
1561147Sbill convr(up)
1571147Sbill struct unit *up;
1581147Sbill {
1591147Sbill 	register struct unit *p;
1601147Sbill 	register c;
1611147Sbill 	register char *cp;
1621147Sbill 	char name[20];
1631147Sbill 	int den, err;
1641147Sbill 
1651147Sbill 	p = up;
1661147Sbill 	for(c=0; c<NDIM; c++)
1671147Sbill 		p->dim[c] = 0;
1681147Sbill 	p->factor = getflt();
1691147Sbill 	if(p->factor == 0.)
1701147Sbill 		p->factor = 1.0;
1711147Sbill 	err = 0;
1721147Sbill 	den = 0;
1731147Sbill 	cp = name;
1741147Sbill 
1751147Sbill loop:
1761147Sbill 	switch(c=get()) {
1771147Sbill 
1781147Sbill 	case '1':
1791147Sbill 	case '2':
1801147Sbill 	case '3':
1811147Sbill 	case '4':
1821147Sbill 	case '5':
1831147Sbill 	case '6':
1841147Sbill 	case '7':
1851147Sbill 	case '8':
1861147Sbill 	case '9':
1871147Sbill 	case '-':
1881147Sbill 	case '/':
1891147Sbill 	case ' ':
1901147Sbill 	case '\t':
1911147Sbill 	case '\n':
1921147Sbill 		if(cp != name) {
1931147Sbill 			*cp++ = 0;
1941147Sbill 			cp = name;
1951147Sbill 			err |= lookup(cp, p, den, c);
1961147Sbill 		}
1971147Sbill 		if(c == '/')
1981147Sbill 			den++;
1991147Sbill 		if(c == '\n')
2001147Sbill 			return(err);
2011147Sbill 		goto loop;
2021147Sbill 	}
2031147Sbill 	*cp++ = c;
2041147Sbill 	goto loop;
2051147Sbill }
2061147Sbill 
lookup(name,up,den,c)2071147Sbill lookup(name, up, den, c)
2081147Sbill char *name;
2091147Sbill struct unit *up;
2101147Sbill {
2111147Sbill 	register struct unit *p;
2121147Sbill 	register struct table *q;
2131147Sbill 	register i;
2141147Sbill 	char *cp1, *cp2;
2151147Sbill 	double e;
2161147Sbill 
2171147Sbill 	p = up;
2181147Sbill 	e = 1.0;
2191147Sbill 
2201147Sbill loop:
2211147Sbill 	q = hash(name);
2221147Sbill 	if(q->name) {
2231147Sbill 		l1:
2241147Sbill 		if(den) {
2251147Sbill 			p->factor /= q->factor*e;
2261147Sbill 			for(i=0; i<NDIM; i++)
2271147Sbill 				p->dim[i] -= q->dim[i];
2281147Sbill 		} else {
2291147Sbill 			p->factor *= q->factor*e;
2301147Sbill 			for(i=0; i<NDIM; i++)
2311147Sbill 				p->dim[i] += q->dim[i];
2321147Sbill 		}
2331147Sbill 		if(c >= '2' && c <= '9') {
2341147Sbill 			c--;
2351147Sbill 			goto l1;
2361147Sbill 		}
2371147Sbill 		return(0);
2381147Sbill 	}
2391147Sbill 	for(i=0; cp1 = prefix[i].pname; i++) {
2401147Sbill 		cp2 = name;
2411147Sbill 		while(*cp1 == *cp2++)
2421147Sbill 			if(*cp1++ == 0) {
2431147Sbill 				cp1--;
2441147Sbill 				break;
2451147Sbill 			}
2461147Sbill 		if(*cp1 == 0) {
2471147Sbill 			e *= prefix[i].factor;
2481147Sbill 			name = cp2-1;
2491147Sbill 			goto loop;
2501147Sbill 		}
2511147Sbill 	}
2521147Sbill 	for(cp1 = name; *cp1; cp1++);
2531147Sbill 	if(cp1 > name+1 && *--cp1 == 's') {
2541147Sbill 		*cp1 = 0;
2551147Sbill 		goto loop;
2561147Sbill 	}
2571147Sbill 	printf("cannot recognize %s\n", name);
2581147Sbill 	return(1);
2591147Sbill }
2601147Sbill 
equal(s1,s2)2611147Sbill equal(s1, s2)
2621147Sbill char *s1, *s2;
2631147Sbill {
2641147Sbill 	register char *c1, *c2;
2651147Sbill 
2661147Sbill 	c1 = s1;
2671147Sbill 	c2 = s2;
2681147Sbill 	while(*c1++ == *c2)
2691147Sbill 		if(*c2++ == 0)
2701147Sbill 			return(1);
2711147Sbill 	return(0);
2721147Sbill }
2731147Sbill 
init()2741147Sbill init()
2751147Sbill {
2761147Sbill 	register char *cp;
2771147Sbill 	register struct table *tp, *lp;
2781147Sbill 	int c, i, f, t;
2791147Sbill 	char *np;
2801147Sbill 
2811147Sbill 	cp = names;
2821147Sbill 	for(i=0; i<NDIM; i++) {
2831147Sbill 		np = cp;
2841147Sbill 		*cp++ = '*';
2851147Sbill 		*cp++ = i+'a';
2861147Sbill 		*cp++ = '*';
2871147Sbill 		*cp++ = 0;
2881147Sbill 		lp = hash(np);
2891147Sbill 		lp->name = np;
2901147Sbill 		lp->factor = 1.0;
2911147Sbill 		lp->dim[i] = 1;
2921147Sbill 	}
2931147Sbill 	lp = hash("");
2941147Sbill 	lp->name = cp-1;
2951147Sbill 	lp->factor = 1.0;
2961147Sbill 
2971147Sbill l0:
2981147Sbill 	c = get();
2991147Sbill 	if(c == 0) {
3001147Sbill 		printf("%d units; %d bytes\n\n", i, cp-names);
3011147Sbill 		if(dumpflg)
3021147Sbill 		for(tp = &table[0]; tp < &table[NTAB]; tp++) {
3031147Sbill 			if(tp->name == 0)
3041147Sbill 				continue;
3051147Sbill 			printf("%s", tp->name);
3061147Sbill 			units(tp);
3071147Sbill 		}
3081147Sbill 		fclose(inp);
3091147Sbill 		inp = stdin;
3101147Sbill 		return;
3111147Sbill 	}
3121147Sbill 	if(c == '/') {
3131147Sbill 		while(c != '\n' && c != 0)
3141147Sbill 			c = get();
3151147Sbill 		goto l0;
3161147Sbill 	}
3171147Sbill 	if(c == '\n')
3181147Sbill 		goto l0;
3191147Sbill 	np = cp;
3201147Sbill 	while(c != ' ' && c != '\t') {
3211147Sbill 		*cp++ = c;
3221147Sbill 		c = get();
3231147Sbill 		if (c==0)
3241147Sbill 			goto l0;
3251147Sbill 		if(c == '\n') {
3261147Sbill 			*cp++ = 0;
3271147Sbill 			tp = hash(np);
3281147Sbill 			if(tp->name)
3291147Sbill 				goto redef;
3301147Sbill 			tp->name = np;
3311147Sbill 			tp->factor = lp->factor;
3321147Sbill 			for(c=0; c<NDIM; c++)
3331147Sbill 				tp->dim[c] = lp->dim[c];
3341147Sbill 			i++;
3351147Sbill 			goto l0;
3361147Sbill 		}
3371147Sbill 	}
3381147Sbill 	*cp++ = 0;
3391147Sbill 	lp = hash(np);
3401147Sbill 	if(lp->name)
3411147Sbill 		goto redef;
3421147Sbill 	convr(lp);
3431147Sbill 	lp->name = np;
3441147Sbill 	f = 0;
3451147Sbill 	i++;
3461147Sbill 	if(lp->factor != 1.0)
3471147Sbill 		goto l0;
3481147Sbill 	for(c=0; c<NDIM; c++) {
3491147Sbill 		t = lp->dim[c];
3501147Sbill 		if(t>1 || (f>0 && t!=0))
3511147Sbill 			goto l0;
3521147Sbill 		if(f==0 && t==1) {
3531147Sbill 			if(unames[c])
3541147Sbill 				goto l0;
3551147Sbill 			f = c+1;
3561147Sbill 		}
3571147Sbill 	}
3581147Sbill 	if(f>0)
3591147Sbill 		unames[f-1] = np;
3601147Sbill 	goto l0;
3611147Sbill 
3621147Sbill redef:
3631147Sbill 	printf("redefinition %s\n", np);
3641147Sbill 	goto l0;
3651147Sbill }
3661147Sbill 
3671147Sbill double
getflt()3681147Sbill getflt()
3691147Sbill {
3701147Sbill 	register c, i, dp;
3711147Sbill 	double d, e;
3721147Sbill 	int f;
3731147Sbill 
3741147Sbill 	d = 0.;
3751147Sbill 	dp = 0;
3761147Sbill 	do
3771147Sbill 		c = get();
3781147Sbill 	while(c == ' ' || c == '\t');
3791147Sbill 
3801147Sbill l1:
3811147Sbill 	if(c >= '0' && c <= '9') {
3821147Sbill 		d = d*10. + c-'0';
3831147Sbill 		if(dp)
3841147Sbill 			dp++;
3851147Sbill 		c = get();
3861147Sbill 		goto l1;
3871147Sbill 	}
3881147Sbill 	if(c == '.') {
3891147Sbill 		dp++;
3901147Sbill 		c = get();
3911147Sbill 		goto l1;
3921147Sbill 	}
3931147Sbill 	if(dp)
3941147Sbill 		dp--;
3951147Sbill 	if(c == '+' || c == '-') {
3961147Sbill 		f = 0;
3971147Sbill 		if(c == '-')
3981147Sbill 			f++;
3991147Sbill 		i = 0;
4001147Sbill 		c = get();
4011147Sbill 		while(c >= '0' && c <= '9') {
4021147Sbill 			i = i*10 + c-'0';
4031147Sbill 			c = get();
4041147Sbill 		}
4051147Sbill 		if(f)
4061147Sbill 			i = -i;
4071147Sbill 		dp -= i;
4081147Sbill 	}
4091147Sbill 	e = 1.;
4101147Sbill 	i = dp;
4111147Sbill 	if(i < 0)
4121147Sbill 		i = -i;
4131147Sbill 	while(i--)
4141147Sbill 		e *= 10.;
4151147Sbill 	if(dp < 0)
4161147Sbill 		d *= e; else
4171147Sbill 		d /= e;
4181147Sbill 	if(c == '|')
4191147Sbill 		return(d/getflt());
4201147Sbill 	peekc = c;
4211147Sbill 	return(d);
4221147Sbill }
4231147Sbill 
get()4241147Sbill get()
4251147Sbill {
4261147Sbill 	register c;
4271147Sbill 
4281147Sbill 	if(c=peekc) {
4291147Sbill 		peekc = 0;
4301147Sbill 		return(c);
4311147Sbill 	}
4321147Sbill 	c = getc(inp);
4331147Sbill 	if (c == EOF) {
4341147Sbill 		if (inp == stdin) {
4351147Sbill 			printf("\n");
4361147Sbill 			exit(0);
4371147Sbill 		}
4381147Sbill 		return(0);
4391147Sbill 	}
4401147Sbill 	return(c);
4411147Sbill }
4421147Sbill 
4431147Sbill struct table *
hash(name)4441147Sbill hash(name)
4451147Sbill char *name;
4461147Sbill {
4471147Sbill 	register struct table *tp;
4481147Sbill 	register char *np;
4491147Sbill 	register unsigned h;
4501147Sbill 
4511147Sbill 	h = 0;
4521147Sbill 	np = name;
4531147Sbill 	while(*np)
4541147Sbill 		h = h*57 + *np++ - '0';
4551147Sbill 	if( ((int)h)<0) h= -(int)h;
4561147Sbill 	h %= NTAB;
4571147Sbill 	tp = &table[h];
4581147Sbill l0:
4591147Sbill 	if(tp->name == 0)
4601147Sbill 		return(tp);
4611147Sbill 	if(equal(name, tp->name))
4621147Sbill 		return(tp);
4631147Sbill 	tp++;
4641147Sbill 	if(tp >= &table[NTAB])
4651147Sbill 		tp = table;
4661147Sbill 	goto l0;
4671147Sbill }
4681147Sbill 
fperr()4691147Sbill fperr()
4701147Sbill {
4711147Sbill 
4721147Sbill 	signal(8, fperr);
4731147Sbill 	fperrc++;
4741147Sbill }
475