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