1/*
2 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7/*	  All Rights Reserved  	*/
8
9/*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved.  The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15#pragma ident	"%Z%%M%	%I%	%E% SMI"
16
17#include <stdio.h>
18#include <locale.h>
19#include <signal.h>
20
21#define	NDIM	10
22#define	NTAB	1009
23char	*dfile	= "/usr/share/lib/unittab";
24char	*unames[NDIM];
25struct unit
26{
27	double	factor;
28	char	dim[NDIM];
29};
30
31struct table
32{
33	double	factor;
34	char	dim[NDIM];
35	char	*name;
36} table[NTAB];
37char	names[NTAB*10];
38struct prefix
39{
40	double	factor;
41	char	*pname;
42} prefix[] =
43{
44	1e-21,	"zepto",
45	1e-24,	"yocto",
46	1e-18,	"atto",
47	1e-15,	"femto",
48	1e-12,	"pico",
49	1e-9,	"nano",
50	1e-6,	"micro",
51	1e-3,	"milli",
52	1e-2,	"centi",
53	1e-1,	"deci",
54	1e1,	"deka",
55	1e1,	"deca",
56	1e2,	"hecta",
57	1e2,	"hecto",
58	1e3,	"kilo",
59	1e6,	"mega",
60	1e6,	"meg",
61	1e9,	"giga",
62	1e12,	"tera",
63	1e15,	"peta",
64	1e18,	"exa",
65	1e21,	"zetta",
66	1e24,	"yotta",
67	1<<10,	"kibi",
68	1L<<20,	"mebi",
69	1L<<30,	"gibi",
70	1LL<<40,"tebi",
71	0.0,	0
72};
73FILE	*inp;
74int	fperrc;
75int	peekc;
76int	dumpflg;
77
78void fperr(int sig);
79double getflt(void);
80struct table *hash(char *name);
81int get(void);
82void init(void);
83int equal(char *s1, char *s2);
84int lookup(char *name, struct unit *up, int den, int c);
85int convr(struct unit *up);
86int pu(int u, int i, int f);
87void units(struct unit *up);
88
89int
90main(int argc, char *argv[])
91{
92	int i;
93	char *file;
94	struct unit u1, u2;
95	double f;
96
97	(void) setlocale(LC_ALL, "");
98#if !defined(TEXT_DOMAIN)
99#define TEXT_DOMAIN "SYS_TEST"
100#endif
101        (void) textdomain(TEXT_DOMAIN);
102
103	if(argc>1 && *argv[1]=='-') {
104		argc--;
105		argv++;
106		dumpflg++;
107	}
108	file = dfile;
109	if(argc > 1)
110		file = argv[1];
111	if ((inp = fopen(file, "r")) == NULL) {
112		printf(gettext("no table\n"));
113		exit(1);
114	}
115	signal(8, fperr);
116	init();
117
118loop:
119	fperrc = 0;
120	printf(gettext("you have: "));
121	if(convr(&u1))
122		goto loop;
123	if(fperrc)
124		goto fp;
125loop1:
126	printf(gettext("you want: "));
127	if(convr(&u2))
128		goto loop1;
129	for(i=0; i<NDIM; i++)
130		if(u1.dim[i] != u2.dim[i])
131			goto conform;
132	f = u1.factor/u2.factor;
133	if(fperrc || f == 0.0)
134		goto fp;
135	printf("\t* %e\n", f);
136	printf("\t/ %e\n", 1./f);
137	goto loop;
138
139conform:
140	if(fperrc)
141		goto fp;
142	printf(gettext("conformability\n"));
143	units(&u1);
144	units(&u2);
145	goto loop;
146
147fp:
148	printf(gettext("underflow or overflow\n"));
149	goto loop;
150}
151
152void
153units(struct unit *up)
154{
155	struct unit *p;
156	int f, i;
157
158	p = up;
159	printf("\t%e ", p->factor);
160	f = 0;
161	for(i=0; i<NDIM; i++)
162		f |= pu(p->dim[i], i, f);
163	if(f&1) {
164		putchar('/');
165		f = 0;
166		for(i=0; i<NDIM; i++)
167			f |= pu(-p->dim[i], i, f);
168	}
169	putchar('\n');
170}
171
172int
173pu(int u, int i, int f)
174{
175
176	if(u > 0) {
177		if(f&2)
178			putchar('-');
179		if(unames[i])
180			printf("%s", unames[i]); else
181			printf(gettext("*%c*"), i+'a');
182		if(u > 1)
183			putchar(u+'0');
184			return(2);
185	}
186	if(u < 0)
187		return(1);
188	return(0);
189}
190
191int
192convr(struct unit *up)
193{
194	struct unit *p;
195	int c;
196	char *cp;
197	char name[20];
198	int den, err;
199
200	p = up;
201	for(c=0; c<NDIM; c++)
202		p->dim[c] = 0;
203	p->factor = getflt();
204	if(p->factor == 0.)
205		p->factor = 1.0;
206	err = 0;
207	den = 0;
208	cp = name;
209
210loop:
211	switch(c=get()) {
212
213	case '1':
214	case '2':
215	case '3':
216	case '4':
217	case '5':
218	case '6':
219	case '7':
220	case '8':
221	case '9':
222	case '-':
223	case '/':
224	case ' ':
225	case '\t':
226	case '\n':
227		if(cp != name) {
228			*cp++ = 0;
229			cp = name;
230			err |= lookup(cp, p, den, c);
231		}
232		if(c == '/')
233			den++;
234		if(c == '\n')
235			return(err);
236		goto loop;
237	}
238	*cp++ = c;
239	goto loop;
240}
241
242int
243lookup(char *name, struct unit *up, int den, int c)
244{
245	struct unit *p;
246	struct table *q;
247	int i;
248	char *cp1, *cp2;
249	double e;
250
251	p = up;
252	e = 1.0;
253
254loop:
255	q = hash(name);
256	if(q->name) {
257		l1:
258		if(den) {
259			p->factor /= q->factor*e;
260			for(i=0; i<NDIM; i++)
261				p->dim[i] -= q->dim[i];
262		} else {
263			p->factor *= q->factor*e;
264			for(i=0; i<NDIM; i++)
265				p->dim[i] += q->dim[i];
266		}
267		if(c >= '2' && c <= '9') {
268			c--;
269			goto l1;
270		}
271		return(0);
272	}
273	for(i=0; cp1 = prefix[i].pname; i++) {
274		cp2 = name;
275		while(*cp1 == *cp2++)
276			if(*cp1++ == 0) {
277				cp1--;
278				break;
279			}
280		if(*cp1 == 0) {
281			e *= prefix[i].factor;
282			name = cp2-1;
283			goto loop;
284		}
285	}
286	for(cp1 = name; *cp1; cp1++);
287	if(cp1 > name+1 && *--cp1 == 's') {
288		*cp1 = 0;
289		goto loop;
290	}
291	printf(gettext("cannot recognize %s\n"), name);
292	return(1);
293}
294
295int
296equal(char *s1, char *s2)
297{
298	char *c1, *c2;
299
300	c1 = s1;
301	c2 = s2;
302	while(*c1++ == *c2)
303		if(*c2++ == 0)
304			return(1);
305	return(0);
306}
307
308void
309init(void)
310{
311	char *cp;
312	struct table *tp, *lp;
313	int c, i, f, t;
314	char *np;
315
316	cp = names;
317	for(i=0; i<NDIM; i++) {
318		np = cp;
319		*cp++ = '*';
320		*cp++ = i+'a';
321		*cp++ = '*';
322		*cp++ = 0;
323		lp = hash(np);
324		lp->name = np;
325		lp->factor = 1.0;
326		lp->dim[i] = 1;
327	}
328	lp = hash("");
329	lp->name = cp-1;
330	lp->factor = 1.0;
331
332l0:
333	c = get();
334	if(c == 0) {
335		if(dumpflg) {
336		printf(gettext("%d units; %d bytes\n\n"), i, cp-names);
337		for(tp = &table[0]; tp < &table[NTAB]; tp++) {
338			if(tp->name == 0)
339				continue;
340			printf("%s", tp->name);
341			units((struct unit *)tp);
342		} }
343		fclose(inp);
344		inp = stdin;
345		return;
346	}
347	if(c == '/') {
348		while(c != '\n' && c != 0)
349			c = get();
350		goto l0;
351	}
352	if(c == '\n')
353		goto l0;
354	np = cp;
355	while(c != ' ' && c != '\t') {
356		*cp++ = c;
357		c = get();
358		if (c==0)
359			goto l0;
360		if(c == '\n') {
361			*cp++ = 0;
362			tp = hash(np);
363			if(tp->name)
364				goto redef;
365			tp->name = np;
366			tp->factor = lp->factor;
367			for(c=0; c<NDIM; c++)
368				tp->dim[c] = lp->dim[c];
369			i++;
370			goto l0;
371		}
372	}
373	*cp++ = 0;
374	lp = hash(np);
375	if(lp->name)
376		goto redef;
377	convr((struct unit *)lp);
378	lp->name = np;
379	f = 0;
380	i++;
381	if(lp->factor != 1.0)
382		goto l0;
383	for(c=0; c<NDIM; c++) {
384		t = lp->dim[c];
385		if(t>1 || (f>0 && t!=0))
386			goto l0;
387		if(f==0 && t==1) {
388			if(unames[c])
389				goto l0;
390			f = c+1;
391		}
392	}
393	if(f>0)
394		unames[f-1] = np;
395	goto l0;
396
397redef:
398	printf(gettext("redefinition %s\n"), np);
399	goto l0;
400}
401
402double
403getflt(void)
404{
405	int c, i, dp;
406	double d, e;
407	int f;
408
409	d = 0.;
410	dp = 0;
411	do
412		c = get();
413	while(c == ' ' || c == '\t');
414
415l1:
416	if(c >= '0' && c <= '9') {
417		d = d*10. + c-'0';
418		if(dp)
419			dp++;
420		c = get();
421		goto l1;
422	}
423	if(c == '.') {
424		dp++;
425		c = get();
426		goto l1;
427	}
428	if(dp)
429		dp--;
430	if(c == '+' || c == '-') {
431		f = 0;
432		if(c == '-')
433			f++;
434		i = 0;
435		c = get();
436		while(c >= '0' && c <= '9') {
437			i = i*10 + c-'0';
438			c = get();
439		}
440		if(f)
441			i = -i;
442		dp -= i;
443	}
444	e = 1.;
445	i = dp;
446	if(i < 0)
447		i = -i;
448	while(i--)
449		e *= 10.;
450	if(dp < 0)
451		d *= e; else
452		d /= e;
453	if(c == '|')
454		return(d/getflt());
455	peekc = c;
456	return(d);
457}
458
459int
460get(void)
461{
462	int c;
463
464	if(c=peekc) {
465		peekc = 0;
466		return(c);
467	}
468	c = getc(inp);
469	if (c == EOF) {
470		if (inp == stdin) {
471			printf("\n");
472			exit(0);
473		}
474		return(0);
475	}
476	return(c);
477}
478
479struct table *
480hash(char *name)
481{
482	struct table *tp;
483	char *np;
484	unsigned int h;
485
486	h = 0;
487	np = name;
488	while(*np)
489		h = h*57 + *np++ - '0';
490	if( ((int)h)<0) h= -(int)h;
491	h %= NTAB;
492	tp = &table[h];
493l0:
494	if(tp->name == 0)
495		return(tp);
496	if(equal(name, tp->name))
497		return(tp);
498	tp++;
499	if(tp >= &table[NTAB])
500		tp = table;
501	goto l0;
502}
503
504void
505fperr(int sig)
506{
507
508	signal(8, fperr);
509	fperrc++;
510}
511