Annotation of coherent/d/bin/units.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.