|
|
1.1 ! root 1: static char Copyright[] = "$Copyright: (c) 1985, INETCO Systems, Ltd.$"; ! 2: static char Release[] = "$Release: INETCO COHERENT V8.0$"; ! 3: static char Date[] = "$Date: 91/04/19 12:41:06 $"; ! 4: ! 5: /* (-lgl ! 6: * The information contained herein is a trade secret of Mark Williams ! 7: * Company, and is confidential information. It is provided under a ! 8: * license agreement, and may be copied or disclosed only under the ! 9: * terms of that agreement. Any reproduction or disclosure of this ! 10: * material without the express written authorization of Mark Williams ! 11: * Company or persuant to the license agreement is unlawful. ! 12: * ! 13: * Coherent Version 2.3.38 ! 14: * Copyright (c) 1982, 1983, 1984. ! 15: * An unpublished work by Mark Williams Company, Chicago. ! 16: * All rights reserved. ! 17: -lgl) */ ! 18: /* ! 19: * units -- do multiplicative unit conversions ! 20: * td 80.09.04 ! 21: * Modified to keep the intermediate format in a file and ! 22: * update it automatically when it has changed. ! 23: * (NOTE: program is setuid to bin) ! 24: * rec 84.08.13 ! 25: * Changed Waiting for Godot ... to Rebuilding %s from %s. ! 26: * (Nota Bene: ! 27: * cc -o units -f units.c ! 28: * chown bin /bin/units ! 29: * chmod 4755 /bin/units ! 30: * ) ! 31: */ ! 32: ! 33: #include <stdio.h> ! 34: #include <sys/stat.h> ! 35: ! 36: #define NDIM 12 ! 37: #define NUNITS 900 ! 38: #define NBUF 256 /* Length of longest line */ ! 39: #define UMAGIC 0123456 /* Magic number written in binary header */ ! 40: ! 41: /* ! 42: * Header for the units file. ! 43: * This tells that it is the real ! 44: * thing and how much to read in. ! 45: */ ! 46: typedef struct HDR { ! 47: unsigned h_magic; ! 48: unsigned h_nunits; ! 49: unsigned h_ssize; /* String space size */ ! 50: } HDR; ! 51: ! 52: HDR hdr; ! 53: ! 54: typedef struct UNIT { ! 55: char *u_name; ! 56: double u_val; ! 57: char u_dim[NDIM]; ! 58: } UNIT; ! 59: ! 60: UNIT *units; ! 61: struct stat sb; ! 62: char ufile[] = "/usr/lib/units"; ! 63: char binufile[] = "/usr/lib/binunits"; ! 64: char buf[NBUF]; ! 65: char inbuf[BUFSIZ]; ! 66: ! 67: int nunits; ! 68: int uflag; /* Update information only */ ! 69: FILE *fd; ! 70: int peekc = EOF; ! 71: int lastc = EOF; ! 72: int lineno = 1; ! 73: ! 74: char *getname(); ! 75: char *prefix(); ! 76: char *alloc(); ! 77: ! 78: main(argc, argv) ! 79: int argc; ! 80: char *argv[]; ! 81: { ! 82: UNIT have, want; ! 83: register int i; ! 84: ! 85: setbuf(stdout, NULL); ! 86: setbuf(stderr, NULL); ! 87: if (argc>1 && *argv[1]=='-') { ! 88: if (argv[1][1]=='u' && argv[1][2]=='\0') ! 89: uflag++; ! 90: else { ! 91: fprintf(stderr, "Usage: units [-u]\n"); ! 92: exit(1); ! 93: } ! 94: } ! 95: init(); ! 96: setbuf(fd = stdin, inbuf); ! 97: Again: ! 98: if (!getunit(&have, "You have: ") ! 99: || !getunit(&want, "You want: ")) ! 100: exit(0); ! 101: for (i=0; i!=NDIM; i++) ! 102: if (have.u_dim[i] != want.u_dim[i]) { ! 103: printf("Conformability\n"); ! 104: punit(&have); ! 105: punit(&want); ! 106: goto Again; ! 107: } ! 108: printf("* %g\n/ %g\n", have.u_val/want.u_val, want.u_val/have.u_val); ! 109: goto Again; ! 110: } ! 111: ! 112: /* ! 113: * Initialise by reading in units information ! 114: * either in binary or ascii form and updating ! 115: * the binary information. ! 116: */ ! 117: init() ! 118: { ! 119: if (!binary()) ! 120: update(); ! 121: printf("%d units\n", nunits); ! 122: peekc = EOF; ! 123: if (uflag) ! 124: exit(0); ! 125: /* ! 126: * Throw away super-user information ! 127: */ ! 128: setuid(getuid()); ! 129: } ! 130: ! 131: /* ! 132: * Attempt to read in the already-stored ! 133: * binary information. Return non-zero if ! 134: * successful. ! 135: */ ! 136: binary() ! 137: { ! 138: register char *sstart; ! 139: register int n; ! 140: register int bfd; ! 141: time_t timeasc; ! 142: ! 143: if (stat(ufile, &sb) < 0) ! 144: return (0); ! 145: timeasc = sb.st_mtime; ! 146: if ((bfd = open(binufile, 0))<0 || fstat(bfd, &sb)<0) ! 147: return (0); ! 148: if (timeasc > sb.st_mtime) /* Out of date? */ ! 149: goto bad1; ! 150: if (read(bfd, &hdr, sizeof(hdr)) != sizeof(hdr)) ! 151: goto bad1; ! 152: if (hdr.h_magic != UMAGIC) ! 153: goto bad1; ! 154: nunits = hdr.h_nunits; ! 155: sstart = alloc(hdr.h_ssize); ! 156: if (read(bfd, sstart, hdr.h_ssize) != hdr.h_ssize) ! 157: goto bad; ! 158: units = (UNIT *)alloc(n = nunits*sizeof(UNIT)); ! 159: if (read(bfd, units, n) != n) ! 160: goto bad; ! 161: for (n=0; n!=nunits; n++) ! 162: units[n].u_name += (long)sstart; ! 163: close(bfd); ! 164: return (1); ! 165: bad: ! 166: brk(sstart); ! 167: bad1: ! 168: close(bfd); ! 169: return (0); ! 170: } ! 171: ! 172: /* ! 173: * Update units information by reading the ! 174: * units file. ! 175: */ ! 176: update() ! 177: { ! 178: register char *name; ! 179: register int i; ! 180: register char *sstart, *send; ! 181: register int bfd; ! 182: ! 183: fprintf(stderr, "Rebuilding %s from %s ...\n", binufile, ufile); ! 184: if ((fd = fopen(ufile, "r")) == NULL) ! 185: cerr("can't open unit file `%s'", ufile); ! 186: setbuf(fd, inbuf); ! 187: units = (UNIT *)alloc(NUNITS*sizeof(UNIT)); ! 188: sstart = sbrk(0); ! 189: for (nunits=0; nunits!=NUNITS; nunits++) { ! 190: name = getname(); ! 191: for (i=0; i!=nunits; i++) ! 192: if (strcmp(units[i].u_name, name) == 0) ! 193: fprintf(stderr, "`%s' redefined, line %d\n", ! 194: name, lineno); ! 195: units[nunits].u_name = name; ! 196: if (!getunit(&units[nunits], NULL)) ! 197: break; ! 198: } ! 199: send = sbrk(0); ! 200: if (!feof(fd)) ! 201: cerr("too many units"); ! 202: fclose(fd); ! 203: /* ! 204: * Write out, if possible, binary ! 205: * information for faster response next time. ! 206: */ ! 207: if ((bfd = creat(binufile, 0644)) >= 0) { ! 208: hdr.h_magic = UMAGIC; ! 209: hdr.h_nunits = nunits; ! 210: hdr.h_ssize = send-sstart; ! 211: if (write(bfd, &hdr, sizeof(hdr)) != sizeof(hdr)) ! 212: goto bad; ! 213: if (write(bfd, sstart, hdr.h_ssize) != hdr.h_ssize) ! 214: goto bad; ! 215: for (i=0; i!=nunits; i++) ! 216: units[i].u_name -= (long)sstart;/* Rel. address */ ! 217: write(bfd, units, nunits*sizeof(UNIT)); ! 218: for (i=0; i!=nunits; i++) ! 219: units[i].u_name += (long)sstart; ! 220: bad: ! 221: close(bfd); ! 222: } ! 223: } ! 224: ! 225: nextc() ! 226: { ! 227: register int c; ! 228: ! 229: if (peekc != EOF) { ! 230: c = peekc; ! 231: peekc = EOF; ! 232: return (c); ! 233: } ! 234: if (lastc == '\n') ! 235: lineno++; ! 236: lastc = getc(fd); ! 237: if (lastc == '#') { /* Eat a comment */ ! 238: do { ! 239: lastc = getc(fd); ! 240: } while(lastc!='\n' && lastc!=EOF); ! 241: } ! 242: return (lastc); ! 243: } ! 244: ! 245: char * ! 246: getname() ! 247: { ! 248: register char *s, *t; ! 249: register int c; ! 250: register char *v; ! 251: ! 252: do { ! 253: c = nextc(); ! 254: } while(c==' ' || c=='\n' || c=='\t'); ! 255: s = buf; ! 256: while(c!=' ' && c!='\t' && c!='\n' && c!=EOF) { ! 257: *s++ = c; ! 258: c = nextc(); ! 259: } ! 260: *s = '\0'; ! 261: peekc = c; ! 262: v = t = alloc(strlen(buf)+1); ! 263: s = buf; ! 264: while (*t++ = *s++) ! 265: ; ! 266: return (v); ! 267: } ! 268: ! 269: punit(u) ! 270: register UNIT *u; ! 271: { ! 272: register int i; ! 273: ! 274: printf("%g", u->u_val); ! 275: for (i=0; i!=NDIM; i++) ! 276: if (u->u_dim[i] == 1) ! 277: printf(" %s", units[i].u_name); ! 278: else if (u->u_dim[i] > 0) ! 279: printf(" %s+%d", units[i].u_name, u->u_dim[i]); ! 280: else if (u->u_dim[i] < 0) ! 281: printf(" %s-%d", units[i].u_name, -u->u_dim[i]); ! 282: printf("\n"); ! 283: } ! 284: ! 285: double ! 286: ipow(d, n) ! 287: double d; ! 288: { ! 289: double v; ! 290: ! 291: v = 1.; ! 292: if (n < 0) { ! 293: d = 1./d; ! 294: n = -n; ! 295: } ! 296: while (n) { ! 297: v *= d; ! 298: --n; ! 299: } ! 300: return (v); ! 301: } ! 302: ! 303: struct{ ! 304: char *prefix; ! 305: double factor; ! 306: }pre[]={ ! 307: "femto", 1e-15, ! 308: "pico", 1e-12, ! 309: "nano", 1e-9, ! 310: "micro", 1e-6, ! 311: "milli", 1e-3, ! 312: "centi", 1e-2, ! 313: "deci", 1e-1, ! 314: "hemi", .5, ! 315: "demi", .5, ! 316: "semi", .5, ! 317: "sesqui", 1.5, ! 318: "deka", 1e1, ! 319: "hecto", 1e2, ! 320: "hekto", 1e2, /* common (?) misspelling */ ! 321: "kilo", 1e3, ! 322: "myria", 1e5, ! 323: "mega", 1e6, ! 324: "giga", 1e9, ! 325: "tera", 1e12, ! 326: NULL, 1. ! 327: }; ! 328: /* ! 329: * Return the string stripped of its ! 330: * prefix (if any). Set factor ! 331: * to the multiplicative factor indicated by ! 332: * the prefix found. ! 333: */ ! 334: char * ! 335: prefix(str, factor) ! 336: char *str; ! 337: double *factor; ! 338: { ! 339: register char *s, *t; ! 340: register int i; ! 341: ! 342: for (i=0; pre[i].prefix!=NULL; i++) { ! 343: s = pre[i].prefix; ! 344: t = str; ! 345: while (*s != '\0') ! 346: if (*s++ != *t++) ! 347: break; ! 348: if (*s == '\0') { ! 349: *factor = *factor * pre[i].factor; ! 350: return (t); ! 351: } ! 352: } ! 353: return(NULL); ! 354: } ! 355: ! 356: getunit(u, prompt) ! 357: UNIT *u; ! 358: char *prompt; ! 359: { ! 360: register int c; ! 361: register char *s; ! 362: register int i; ! 363: int j, expon, digit, div, pow; ! 364: double factor; ! 365: double atof(); ! 366: ! 367: Again: ! 368: if (prompt != NULL) ! 369: printf("%s", prompt); ! 370: u->u_val = 1.; ! 371: for (i=0; i != NDIM; i++) ! 372: u->u_dim[i] = 0; ! 373: div = 0; ! 374: pow = 1; ! 375: for(;;)switch(c=nextc()){ ! 376: case ' ': ! 377: case '\t': ! 378: break; ! 379: case '\n': ! 380: return (1); ! 381: case EOF: ! 382: return (0); ! 383: case '0':case '1':case '2':case '3':case '4': ! 384: case '5':case '6':case '7':case '8':case '9': ! 385: case '.':case '-':case '+': ! 386: /* ! 387: * a palpable number ! 388: */ ! 389: s = buf; ! 390: if (c == '+') ! 391: c = nextc(); ! 392: digit = 0; ! 393: while (c>='0' && c<='9') { ! 394: *s++ = c; ! 395: c = nextc(); ! 396: digit++; ! 397: } ! 398: if (c == '.') { ! 399: *s++ = c; ! 400: while ((c=nextc())>='0' && c<='9') { ! 401: *s++ = c; ! 402: digit++; ! 403: } ! 404: } ! 405: if (!digit) { ! 406: Badnumber: ! 407: *s = '\0'; ! 408: fprintf(stderr, "Bad number `%s'\n", buf); ! 409: goto Bad; ! 410: } ! 411: if (c=='e' || c=='E') { ! 412: *s++ = 'e'; ! 413: c = nextc(); ! 414: if (c == '+') ! 415: c = nextc(); ! 416: else if (c == '-') { ! 417: *s++ = c; ! 418: c = nextc(); ! 419: } ! 420: if (c<'0' || '9'<c) ! 421: goto Badnumber; ! 422: do { ! 423: *s++ = c; ! 424: c = nextc(); ! 425: } while('0'<=c && c<='9'); ! 426: } ! 427: *s = '\0'; ! 428: peekc = c; ! 429: factor = atof(buf); ! 430: if (div) { ! 431: if (factor == 0.) { ! 432: fprintf(stderr, "Divide check\n"); ! 433: goto Bad; ! 434: } ! 435: u->u_val /= factor; ! 436: div = 0; ! 437: } else ! 438: u->u_val *= factor; ! 439: break; ! 440: ! 441: case '/': /* divide by next unit */ ! 442: if (div) { ! 443: Baddiv: ! 444: fprintf(stderr, "Two division signs in a row\n"); ! 445: goto Bad; ! 446: } ! 447: div++; ! 448: break; ! 449: ! 450: case '!': /* primitive unit */ ! 451: i = 0; ! 452: if ((c = nextc())<'0' || c>'9') { ! 453: fprintf(stderr, "`!' must precede a number\n"); ! 454: goto Bad; ! 455: } ! 456: do { ! 457: i = i*10+c-'0'; ! 458: c = nextc(); ! 459: } while('0'<=c && c<='9'); ! 460: peekc = c; ! 461: if (i<0 || NDIM<=i) { ! 462: printf("Primitive unit out of range [0,%d]\n", NDIM-1); ! 463: goto Bad; ! 464: } ! 465: u->u_dim[i]++; ! 466: break; ! 467: ! 468: default: ! 469: s = buf; ! 470: do { ! 471: *s++ = c; ! 472: c = nextc(); ! 473: } while(c!=EOF && !anyc(c, "/0123456789+-. \t\n")); ! 474: *s = '\0'; ! 475: s = buf; ! 476: if (strcmp(s, "per") == 0) { ! 477: if (div) ! 478: goto Baddiv; ! 479: div++; ! 480: break; ! 481: } ! 482: if (strcmp(s, "square")==0 || strcmp(s, "sq")==0) { ! 483: pow *= 2; ! 484: break; ! 485: } ! 486: if (strcmp(s, "cubic")==0 || strcmp(s, "cu")==0) { ! 487: pow *= 3; ! 488: break; ! 489: } ! 490: factor = 1.; ! 491: do { ! 492: for (i=0; i!=nunits; i++) ! 493: if (eqplural(s, units[i].u_name)) ! 494: break; ! 495: } while(i==nunits && (s=prefix(s, &factor))!=NULL); ! 496: if (i == nunits) { ! 497: fprintf(stderr, "Unrecognised unit %s\n", buf); ! 498: goto Bad; ! 499: } ! 500: if (c=='+' || c=='-') { ! 501: if (c == '-') ! 502: div = !div; ! 503: expon = 0; ! 504: if ((c = nextc())<'0' || c>'9') { ! 505: printf("+ or - must be followed by digits\n"); ! 506: goto Bad; ! 507: } ! 508: do { ! 509: expon = expon*10+c-'0'; ! 510: c = nextc(); ! 511: } while('0'<=c && c<='9'); ! 512: } else ! 513: expon = 1; ! 514: expon *= pow; ! 515: pow = 1; ! 516: peekc = c; ! 517: if (div) { ! 518: expon = -expon; ! 519: div = 0; ! 520: } ! 521: u->u_val *= ipow(factor*units[i].u_val, expon); ! 522: for (j=0; j!=NDIM; j++) ! 523: u->u_dim[j] += units[i].u_dim[j]*expon; ! 524: } ! 525: Bad: ! 526: while (c!='\n' && c!=EOF) ! 527: c = nextc(); ! 528: if (prompt!=NULL) ! 529: goto Again; ! 530: printf("line %d\n", lineno); ! 531: return (1); ! 532: } ! 533: ! 534: /* ! 535: * Check for any occurrences of ! 536: * the character `c' in string `s'. ! 537: */ ! 538: anyc(c, s) ! 539: register char c; ! 540: register char *s; ! 541: { ! 542: while (*s != '\0') ! 543: if (c == *s++) ! 544: return (1); ! 545: return (0); ! 546: } ! 547: ! 548: /* ! 549: * Return non-zero if string `s' is the ! 550: * same or plural as string `t'. ! 551: */ ! 552: eqplural(s, t) ! 553: register char *s, *t; ! 554: { ! 555: while (*t != '\0') ! 556: if (*s++ != *t++) ! 557: return (0); ! 558: return (*s=='\0' || (*s++=='s' && *s=='\0')); ! 559: } ! 560: ! 561: /* ! 562: * Diagnostics ! 563: */ ! 564: /* VARARGS */ ! 565: cerr(x) ! 566: { ! 567: fprintf(stderr, "units: %r\n", &x); ! 568: exit(1); ! 569: } ! 570: ! 571: /* ! 572: * Use sbrk for alloc to get ! 573: * contiguous memory. ! 574: */ ! 575: char * ! 576: alloc(nb) ! 577: unsigned nb; ! 578: { ! 579: register char *rp; ! 580: ! 581: if ((rp = sbrk(nb)) == NULL) ! 582: cerr("out of memory"); ! 583: return (rp); ! 584: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.