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