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