xref: /illumos-gate/usr/src/cmd/units/units.c (revision 49218d4f8e4d84d1c08aeb267bcf6e451f2056dc)
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
23 char	*dfile	= "/usr/share/lib/unittab";
24 char	*unames[NDIM];
25 struct unit
26 {
27 	double	factor;
28 	char	dim[NDIM];
29 };
30 
31 struct table
32 {
33 	double	factor;
34 	char	dim[NDIM];
35 	char	*name;
36 } table[NTAB];
37 char	names[NTAB*10];
38 struct 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 };
73 FILE	*inp;
74 int	fperrc;
75 int	peekc;
76 int	dumpflg;
77 
78 void fperr(int sig);
79 double getflt(void);
80 struct table *hash(char *name);
81 int get(void);
82 void init(void);
83 int equal(char *s1, char *s2);
84 int lookup(char *name, struct unit *up, int den, int c);
85 int convr(struct unit *up);
86 int pu(int u, int i, int f);
87 void units(struct unit *up);
88 
89 int
90 main(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 
118 loop:
119 	fperrc = 0;
120 	printf(gettext("you have: "));
121 	if(convr(&u1))
122 		goto loop;
123 	if(fperrc)
124 		goto fp;
125 loop1:
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 
139 conform:
140 	if(fperrc)
141 		goto fp;
142 	printf(gettext("conformability\n"));
143 	units(&u1);
144 	units(&u2);
145 	goto loop;
146 
147 fp:
148 	printf(gettext("underflow or overflow\n"));
149 	goto loop;
150 }
151 
152 void
153 units(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 
172 int
173 pu(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 
191 int
192 convr(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 
210 loop:
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 
242 int
243 lookup(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 
254 loop:
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 
295 int
296 equal(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 
308 void
309 init(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 
332 l0:
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 
397 redef:
398 	printf(gettext("redefinition %s\n"), np);
399 	goto l0;
400 }
401 
402 double
403 getflt(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 
415 l1:
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 
459 int
460 get(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 
479 struct table *
480 hash(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];
493 l0:
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 
504 void
505 fperr(int sig)
506 {
507 
508 	signal(8, fperr);
509 	fperrc++;
510 }
511