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