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