|
|
1.1 ! root 1: /* ! 2: * $Header: /newbits/bin/units.c,v 1.2 89/02/22 05:09:42 bin Exp $ ! 3: * $Log: /newbits/bin/units.c,v $ ! 4: * Revision 1.2 89/02/22 05:09:42 bin ! 5: * Changed memory allocation to work better on the atari. ! 6: * Changed where it looks for units and binary units, using path. ! 7: * ! 8: */ ! 9: static char *revision = "$Revision 1.1 $"; ! 10: static char *header = ! 11: "$Header: /newbits/bin/units.c,v 1.2 89/02/22 05:09:42 bin Exp $"; ! 12: ! 13: /* ! 14: * units -- do multiplicative unit conversions ! 15: * td 80.09.04 ! 16: * Modified to keep the intermediate format in a file and ! 17: * update it automatically when it has changed. ! 18: * (NOTE: program is setuid to bin) ! 19: * rec 84.08.13 ! 20: * Changed Waiting for Godot ... to Rebuilding %s from %s. ! 21: * (Nota Bene: ! 22: * cc -o units -f units.c ! 23: * chown bin /bin/units ! 24: * chmod 4755 /bin/units ! 25: * ) ! 26: */ ! 27: ! 28: #include <stdio.h> ! 29: #include <sys/stat.h> ! 30: #include <path.h> ! 31: #ifdef GEM ! 32: #include <osbind.h> ! 33: #endif ! 34: ! 35: #define PATHSIZE 64 ! 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[] = "units"; ! 63: char binufile[] = "binunits"; ! 64: char *uname; ! 65: char *buname; ! 66: char buf[NBUF]; ! 67: char inbuf[BUFSIZ]; ! 68: ! 69: extern char *getenv(), *path(), *index(), *strcpy(); ! 70: ! 71: int nunits; ! 72: int uflag; /* Update information only */ ! 73: FILE *fd; ! 74: int peekc = EOF; ! 75: int lastc = EOF; ! 76: int lineno = 1; ! 77: ! 78: char *getname(); ! 79: char *prefix(); ! 80: char *alloc(); ! 81: ! 82: main(argc, argv) ! 83: int argc; ! 84: char *argv[]; ! 85: { ! 86: UNIT have, want; ! 87: register int i; ! 88: ! 89: setbuf(stdout, NULL); ! 90: setbuf(stderr, NULL); ! 91: if (argc>1 && *argv[1]=='-') { ! 92: if (argv[1][1]=='u' && argv[1][2]=='\0') ! 93: uflag++; ! 94: else { ! 95: fprintf(stderr, "Usage: units [-u]\n"); ! 96: exit(1); ! 97: } ! 98: } ! 99: init(); ! 100: setbuf(fd = stdin, inbuf); ! 101: Again: ! 102: if (!getunit(&have, "You have: ") ! 103: || !getunit(&want, "You want: ")) ! 104: exit(0); ! 105: for (i=0; i!=NDIM; i++) ! 106: if (have.u_dim[i] != want.u_dim[i]) { ! 107: printf("Conformability\n"); ! 108: punit(&have); ! 109: punit(&want); ! 110: goto Again; ! 111: } ! 112: printf("* %g\n/ %g\n", have.u_val/want.u_val, want.u_val/have.u_val); ! 113: goto Again; ! 114: } ! 115: ! 116: /* ! 117: * Initialise by reading in units information ! 118: * either in binary or ascii form and updating ! 119: * the binary information. ! 120: */ ! 121: init() ! 122: { ! 123: if (!binary()) ! 124: update(); ! 125: printf("%d units\n", nunits); ! 126: peekc = EOF; ! 127: if (uflag) ! 128: exit(0); ! 129: } ! 130: ! 131: /* ! 132: * allocate a new copy. ! 133: */ ! 134: char * ! 135: newcpy(s) ! 136: register char *s; ! 137: { ! 138: return(strcpy(malloc(strlen(s) + 1), s)); ! 139: } ! 140: ! 141: /* ! 142: * find a file on a path in the environment, or a default path ! 143: * with an access priveledge. ! 144: * ! 145: * example: pathn("helpfile", "LIBPATH", ",,\lib", "r"); ! 146: * ! 147: * Returns full path name. ! 148: */ ! 149: char * ! 150: pathn(name, envpath, deflpath, acs) ! 151: char *name, *envpath, *deflpath, *acs; ! 152: { ! 153: static char fullname[PATHSIZE]; ! 154: register char *pathptr; ! 155: ! 156: if((NULL == envpath) || (NULL == (pathptr = getenv(envpath)))) ! 157: pathptr = deflpath; ! 158: ! 159: if(NULL == index(acs, 'w')) { ! 160: if ((pathptr = path(pathptr, name, AREAD)) == NULL) ! 161: fullname[0] = '\0'; /* bad name */ ! 162: else ! 163: strcpy(fullname, pathptr); ! 164: } ! 165: else { ! 166: register char *p, c; ! 167: ! 168: if((p = path(pathptr, name, AWRITE)) == NULL) { ! 169: for(p = fullname; (c = *pathptr++) && c != LISTSEP;) ! 170: *p++ = c; ! 171: *p++ = PATHSEP; ! 172: strcpy(p, name); ! 173: } else ! 174: strcpy(fullname, p); ! 175: } ! 176: return(fullname); ! 177: } ! 178: ! 179: /* ! 180: * Attempt to read in the already-stored ! 181: * binary information. Return non-zero if ! 182: * successful. ! 183: * ! 184: * if(binary and ascii) ! 185: * if(binary out of date) ! 186: * rebuild ! 187: * else ! 188: * use binary ! 189: * if(binary and no ascii) ! 190: * use binary ! 191: * if(ascii and no binary) ! 192: * rebuild ! 193: * crash ! 194: */ ! 195: binary() ! 196: { ! 197: register char *sstart; ! 198: register int n; ! 199: register int bfd; ! 200: time_t timeasc; ! 201: ! 202: uname = newcpy(pathn(ufile, "LIBPATH", DEFLIBPATH, "r")); ! 203: buname = newcpy(pathn(binufile, "LIBPATH", DEFLIBPATH, "r")); ! 204: if(!buname[0]) { /* no binary */ ! 205: if(!uname[0]) /* also no ansii */ ! 206: cerr("can't find unit file `%s' or `%s'", ! 207: ufile, binufile); ! 208: buname = malloc(strlen(uname) + strlen(binufile)); ! 209: strcpy(buname, uname); ! 210: strcpy(index(buname, '\0') - strlen(ufile), binufile); ! 211: return(0); ! 212: } ! 213: else if(!stat(uname, &sb)) { /* binary and ascii found */ ! 214: timeasc = sb.st_mtime; ! 215: if(stat(buname, &sb) || (timeasc > sb.st_mtime)) ! 216: return(0); /* bin file out of date */ ! 217: } ! 218: if(uflag) /* update only */ ! 219: return(0); ! 220: if((bfd = open(buname, 0)) < 0) ! 221: return (0); ! 222: if(read(bfd, &hdr, sizeof(hdr)) != sizeof(hdr)) ! 223: goto bad; ! 224: if(hdr.h_magic != UMAGIC) ! 225: goto bad; ! 226: nunits = hdr.h_nunits; ! 227: sstart = alloc(hdr.h_ssize); ! 228: if (read(bfd, sstart, hdr.h_ssize) != hdr.h_ssize) ! 229: goto bad; ! 230: units = (UNIT *)alloc(n = nunits*sizeof(UNIT)); ! 231: if (read(bfd, units, n) != n) ! 232: goto bad; ! 233: for (n=0; n!=nunits; n++) ! 234: units[n].u_name += (long)sstart; ! 235: close(bfd); ! 236: return (1); ! 237: bad: ! 238: close(bfd); ! 239: return (0); ! 240: } ! 241: ! 242: /* ! 243: * Update units information by reading the ! 244: * units file. ! 245: */ ! 246: update() ! 247: { ! 248: register char *name; ! 249: register int i; ! 250: register char *sstart, *send; ! 251: register int bfd; ! 252: ! 253: fprintf(stderr, "Rebuilding %s from %s ...\n", buname, uname); ! 254: if ((fd = fopen(uname, "r")) == NULL) ! 255: cerr("can't open unit file `%s'", ufile); ! 256: setbuf(fd, inbuf); ! 257: units = (UNIT *)alloc(NUNITS*sizeof(UNIT)); ! 258: sstart = alloc(0); ! 259: for (nunits=0; nunits!=NUNITS; nunits++) { ! 260: name = getname(); ! 261: for (i=0; i!=nunits; i++) ! 262: if (strcmp(units[i].u_name, name) == 0) ! 263: fprintf(stderr, "`%s' redefined, line %d\n", ! 264: name, lineno); ! 265: units[nunits].u_name = name; ! 266: if (!getunit(&units[nunits], NULL)) ! 267: break; ! 268: } ! 269: send = alloc(0); ! 270: if (!feof(fd)) ! 271: cerr("too many units"); ! 272: fclose(fd); ! 273: /* ! 274: * Write out, if possible, binary ! 275: * information for faster response next time. ! 276: */ ! 277: if ((bfd = creat(buname, 0644)) >= 0) { ! 278: hdr.h_magic = UMAGIC; ! 279: hdr.h_nunits = nunits; ! 280: hdr.h_ssize = send-sstart; ! 281: if (write(bfd, &hdr, sizeof(hdr)) != sizeof(hdr)) ! 282: goto bad; ! 283: if (write(bfd, sstart, hdr.h_ssize) != hdr.h_ssize) ! 284: goto bad; ! 285: for (i=0; i!=nunits; i++) ! 286: units[i].u_name -= (long)sstart;/* Rel. address */ ! 287: write(bfd, units, nunits*sizeof(UNIT)); ! 288: for (i=0; i!=nunits; i++) ! 289: units[i].u_name += (long)sstart; ! 290: bad: ! 291: close(bfd); ! 292: } ! 293: } ! 294: ! 295: nextc() ! 296: { ! 297: register int c; ! 298: ! 299: if (peekc != EOF) { ! 300: c = peekc; ! 301: peekc = EOF; ! 302: return (c); ! 303: } ! 304: if (lastc == '\n') ! 305: lineno++; ! 306: lastc = getc(fd); ! 307: if (lastc == '#') { /* Eat a comment */ ! 308: do { ! 309: lastc = getc(fd); ! 310: } while(lastc!='\n' && lastc!=EOF); ! 311: } ! 312: return (lastc); ! 313: } ! 314: ! 315: char * ! 316: getname() ! 317: { ! 318: register char *s, *t; ! 319: register int c; ! 320: register char *v; ! 321: ! 322: do { ! 323: c = nextc(); ! 324: } while(c==' ' || c=='\n' || c=='\t'); ! 325: s = buf; ! 326: while(c!=' ' && c!='\t' && c!='\n' && c!=EOF) { ! 327: *s++ = c; ! 328: c = nextc(); ! 329: } ! 330: *s = '\0'; ! 331: peekc = c; ! 332: v = t = alloc(strlen(buf)+1); ! 333: s = buf; ! 334: while (*t++ = *s++) ! 335: ; ! 336: return (v); ! 337: } ! 338: ! 339: punit(u) ! 340: register UNIT *u; ! 341: { ! 342: register int i; ! 343: ! 344: printf("%g", u->u_val); ! 345: for (i=0; i!=NDIM; i++) ! 346: if (u->u_dim[i] == 1) ! 347: printf(" %s", units[i].u_name); ! 348: else if (u->u_dim[i] > 0) ! 349: printf(" %s+%d", units[i].u_name, u->u_dim[i]); ! 350: else if (u->u_dim[i] < 0) ! 351: printf(" %s-%d", units[i].u_name, -u->u_dim[i]); ! 352: printf("\n"); ! 353: } ! 354: ! 355: double ! 356: ipow(d, n) ! 357: double d; ! 358: { ! 359: double v; ! 360: ! 361: v = 1.; ! 362: if (n < 0) { ! 363: d = 1./d; ! 364: n = -n; ! 365: } ! 366: while (n) { ! 367: v *= d; ! 368: --n; ! 369: } ! 370: return (v); ! 371: } ! 372: ! 373: struct{ ! 374: char *prefix; ! 375: double factor; ! 376: }pre[]={ ! 377: "femto", 1e-15, ! 378: "pico", 1e-12, ! 379: "nano", 1e-9, ! 380: "micro", 1e-6, ! 381: "milli", 1e-3, ! 382: "centi", 1e-2, ! 383: "deci", 1e-1, ! 384: "hemi", .5, ! 385: "demi", .5, ! 386: "semi", .5, ! 387: "sesqui", 1.5, ! 388: "deka", 1e1, ! 389: "hecto", 1e2, ! 390: "hekto", 1e2, /* common (?) misspelling */ ! 391: "kilo", 1e3, ! 392: "myria", 1e5, ! 393: "mega", 1e6, ! 394: "giga", 1e9, ! 395: "tera", 1e12, ! 396: NULL, 1. ! 397: }; ! 398: /* ! 399: * Return the string stripped of its ! 400: * prefix (if any). Set factor ! 401: * to the multiplicative factor indicated by ! 402: * the prefix found. ! 403: */ ! 404: char * ! 405: prefix(str, factor) ! 406: char *str; ! 407: double *factor; ! 408: { ! 409: register char *s, *t; ! 410: register int i; ! 411: ! 412: for (i=0; pre[i].prefix!=NULL; i++) { ! 413: s = pre[i].prefix; ! 414: t = str; ! 415: while (*s != '\0') ! 416: if (*s++ != *t++) ! 417: break; ! 418: if (*s == '\0') { ! 419: *factor = *factor * pre[i].factor; ! 420: return (t); ! 421: } ! 422: } ! 423: return(NULL); ! 424: } ! 425: ! 426: getunit(u, prompt) ! 427: UNIT *u; ! 428: char *prompt; ! 429: { ! 430: register int c; ! 431: register char *s; ! 432: register int i; ! 433: int j, expon, digit, div, pow; ! 434: double factor; ! 435: double atof(); ! 436: ! 437: Again: ! 438: if (prompt != NULL) ! 439: printf("%s", prompt); ! 440: u->u_val = 1.; ! 441: for (i=0; i != NDIM; i++) ! 442: u->u_dim[i] = 0; ! 443: div = 0; ! 444: pow = 1; ! 445: for(;;)switch(c=nextc()){ ! 446: case ' ': ! 447: case '\t': ! 448: break; ! 449: case '\n': ! 450: return (1); ! 451: case EOF: ! 452: return (0); ! 453: case '0':case '1':case '2':case '3':case '4': ! 454: case '5':case '6':case '7':case '8':case '9': ! 455: case '.':case '-':case '+': ! 456: /* ! 457: * a palpable number ! 458: */ ! 459: s = buf; ! 460: if (c == '+') ! 461: c = nextc(); ! 462: digit = 0; ! 463: while (c>='0' && c<='9') { ! 464: *s++ = c; ! 465: c = nextc(); ! 466: digit++; ! 467: } ! 468: if (c == '.') { ! 469: *s++ = c; ! 470: while ((c=nextc())>='0' && c<='9') { ! 471: *s++ = c; ! 472: digit++; ! 473: } ! 474: } ! 475: if (!digit) { ! 476: Badnumber: ! 477: *s = '\0'; ! 478: fprintf(stderr, "Bad number `%s'\n", buf); ! 479: goto Bad; ! 480: } ! 481: if (c=='e' || c=='E') { ! 482: *s++ = 'e'; ! 483: c = nextc(); ! 484: if (c == '+') ! 485: c = nextc(); ! 486: else if (c == '-') { ! 487: *s++ = c; ! 488: c = nextc(); ! 489: } ! 490: if (c<'0' || '9'<c) ! 491: goto Badnumber; ! 492: do { ! 493: *s++ = c; ! 494: c = nextc(); ! 495: } while('0'<=c && c<='9'); ! 496: } ! 497: *s = '\0'; ! 498: peekc = c; ! 499: factor = atof(buf); ! 500: if (div) { ! 501: if (factor == 0.) { ! 502: fprintf(stderr, "Divide check\n"); ! 503: goto Bad; ! 504: } ! 505: u->u_val /= factor; ! 506: div = 0; ! 507: } else ! 508: u->u_val *= factor; ! 509: break; ! 510: ! 511: case '/': /* divide by next unit */ ! 512: if (div) { ! 513: Baddiv: ! 514: fprintf(stderr, "Two division signs in a row\n"); ! 515: goto Bad; ! 516: } ! 517: div++; ! 518: break; ! 519: ! 520: case '!': /* primitive unit */ ! 521: i = 0; ! 522: if ((c = nextc())<'0' || c>'9') { ! 523: fprintf(stderr, "`!' must precede a number\n"); ! 524: goto Bad; ! 525: } ! 526: do { ! 527: i = i*10+c-'0'; ! 528: c = nextc(); ! 529: } while('0'<=c && c<='9'); ! 530: peekc = c; ! 531: if (i<0 || NDIM<=i) { ! 532: printf("Primitive unit out of range [0,%d]\n", NDIM-1); ! 533: goto Bad; ! 534: } ! 535: u->u_dim[i]++; ! 536: break; ! 537: ! 538: default: ! 539: s = buf; ! 540: do { ! 541: *s++ = c; ! 542: c = nextc(); ! 543: } while(c!=EOF && !anyc(c, "/0123456789+-. \t\n")); ! 544: *s = '\0'; ! 545: s = buf; ! 546: if (strcmp(s, "per") == 0) { ! 547: if (div) ! 548: goto Baddiv; ! 549: div++; ! 550: break; ! 551: } ! 552: if (strcmp(s, "square")==0 || strcmp(s, "sq")==0) { ! 553: pow *= 2; ! 554: break; ! 555: } ! 556: if (strcmp(s, "cubic")==0 || strcmp(s, "cu")==0) { ! 557: pow *= 3; ! 558: break; ! 559: } ! 560: factor = 1.; ! 561: do { ! 562: for (i=0; i!=nunits; i++) ! 563: if (eqplural(s, units[i].u_name)) ! 564: break; ! 565: } while(i==nunits && (s=prefix(s, &factor))!=NULL); ! 566: if (i == nunits) { ! 567: fprintf(stderr, "Unrecognised unit %s\n", buf); ! 568: goto Bad; ! 569: } ! 570: if (c=='+' || c=='-') { ! 571: if (c == '-') ! 572: div = !div; ! 573: expon = 0; ! 574: if ((c = nextc())<'0' || c>'9') { ! 575: printf("+ or - must be followed by digits\n"); ! 576: goto Bad; ! 577: } ! 578: do { ! 579: expon = expon*10+c-'0'; ! 580: c = nextc(); ! 581: } while('0'<=c && c<='9'); ! 582: } else ! 583: expon = 1; ! 584: expon *= pow; ! 585: pow = 1; ! 586: peekc = c; ! 587: if (div) { ! 588: expon = -expon; ! 589: div = 0; ! 590: } ! 591: u->u_val *= ipow(factor*units[i].u_val, expon); ! 592: for (j=0; j!=NDIM; j++) ! 593: u->u_dim[j] += units[i].u_dim[j]*expon; ! 594: } ! 595: Bad: ! 596: while (c!='\n' && c!=EOF) ! 597: c = nextc(); ! 598: if (prompt!=NULL) ! 599: goto Again; ! 600: printf("line %d\n", lineno); ! 601: return (1); ! 602: } ! 603: ! 604: /* ! 605: * Check for any occurrences of ! 606: * the character `c' in string `s'. ! 607: */ ! 608: anyc(c, s) ! 609: register char c; ! 610: register char *s; ! 611: { ! 612: while (*s != '\0') ! 613: if (c == *s++) ! 614: return (1); ! 615: return (0); ! 616: } ! 617: ! 618: /* ! 619: * Return non-zero if string `s' is the ! 620: * same or plural as string `t'. ! 621: */ ! 622: eqplural(s, t) ! 623: register char *s, *t; ! 624: { ! 625: while (*t != '\0') ! 626: if (*s++ != *t++) ! 627: return (0); ! 628: return (*s=='\0' || (*s++=='s' && *s=='\0')); ! 629: } ! 630: ! 631: /* ! 632: * Diagnostics ! 633: */ ! 634: /* VARARGS */ ! 635: cerr(x) ! 636: char *x; ! 637: { ! 638: fprintf(stderr, "units: %r\n", &x); ! 639: exit(1); ! 640: } ! 641: ! 642: /* ! 643: * get contiguous memory. ! 644: */ ! 645: char * ! 646: alloc(nb) ! 647: unsigned nb; ! 648: { ! 649: register char *rp; ! 650: #ifndef GEM ! 651: if((rp = sbrk(nb)) == ((char *)-1)) ! 652: cerr("out of memory"); ! 653: #else ! 654: static char *mp = NULL; ! 655: static long l; ! 656: ! 657: if((NULL == mp) && ! 658: (!(l = Malloc(-1L)) || ! 659: !(mp = (char *)Malloc(l)))) ! 660: cerr("no memory"); ! 661: ! 662: if(0 > (l -= nb)) ! 663: cerr("out of memory"); ! 664: rp = mp; ! 665: mp += nb; ! 666: #endif ! 667: return (rp); ! 668: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.