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 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 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 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 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 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 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 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 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 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 * 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 504 fperr(int sig) 505 { 506 507 signal(8, fperr); 508 fperrc++; 509 } 510