BSD 4_1c_2 release
[unix-history] / usr / src / usr.bin / units.c
CommitLineData
31cef89c 1static char *sccsid = "@(#)units.c 4.1 (Berkeley) 10/1/80";
b3bb7316
BJ
2#include <stdio.h>
3
4#define NDIM 10
5#define NTAB 601
6char *dfile = "/usr/lib/units";
7char *unames[NDIM];
8double getflt();
9int fperr();
10struct table *hash();
11struct unit
12{
13 double factor;
14 char dim[NDIM];
15};
16
17struct table
18{
19 double factor;
20 char dim[NDIM];
21 char *name;
22} table[NTAB];
23char names[NTAB*10];
24struct 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};
48FILE *inp;
49int fperrc;
50int peekc;
51int dumpflg;
52
53main(argc, argv)
54char *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
76loop:
77 fperrc = 0;
78 printf("you have: ");
79 if(convr(&u1))
80 goto loop;
81 if(fperrc)
82 goto fp;
83loop1:
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
97conform:
98 if(fperrc)
99 goto fp;
100 printf("conformability\n");
101 units(&u1);
102 units(&u2);
103 goto loop;
104
105fp:
106 printf("underflow or overflow\n");
107 goto loop;
108}
109
110units(up)
111struct 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
130pu(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
148convr(up)
149struct 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
167loop:
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
199lookup(name, up, den, c)
200char *name;
201struct 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
212loop:
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
253equal(s1, s2)
254char *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
266init()
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
289l0:
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
354redef:
355 printf("redefinition %s\n", np);
356 goto l0;
357}
358
359double
360getflt()
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
372l1:
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
416get()
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
435struct table *
436hash(name)
437char *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];
450l0:
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
461fperr()
462{
463
464 signal(8, fperr);
465 fperrc++;
466}