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