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