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