[BACK]Return to units.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / units

Annotation of src/usr.bin/units/units.c, Revision 1.12

1.12    ! ray         1: /*     $OpenBSD: units.c,v 1.11 2004/12/02 22:54:55 pat Exp $  */
1.2       deraadt     2: /*     $NetBSD: units.c,v 1.6 1996/04/06 06:01:03 thorpej Exp $        */
                      3:
1.1       deraadt     4: /*
                      5:  * units.c   Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  * Disclaimer:  This software is provided by the author "as is".  The author
                     15:  * shall not be liable for any damages caused in any way by this software.
                     16:  *
                     17:  * I would appreciate (though I do not require) receiving a copy of any
                     18:  * improvements you might make to this program.
                     19:  */
                     20:
                     21: #include <ctype.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24: #include <stdlib.h>
                     25:
                     26: #include "pathnames.h"
                     27:
                     28: #define VERSION "1.0"
                     29:
                     30: #ifndef UNITSFILE
                     31: #define UNITSFILE _PATH_UNITSLIB
                     32: #endif
                     33:
                     34: #define MAXUNITS 1000
                     35: #define MAXPREFIXES 50
                     36:
                     37: #define MAXSUBUNITS 500
                     38:
                     39: #define PRIMITIVECHAR '!'
                     40:
                     41: char *powerstring = "^";
                     42:
                     43: struct {
                     44:        char *uname;
                     45:        char *uval;
1.7       deraadt    46: } unittable[MAXUNITS];
1.1       deraadt    47:
                     48: struct unittype {
                     49:        char *numerator[MAXSUBUNITS];
                     50:        char *denominator[MAXSUBUNITS];
                     51:        double factor;
                     52: };
                     53:
                     54: struct {
                     55:        char *prefixname;
                     56:        char *prefixval;
1.7       deraadt    57: } prefixtable[MAXPREFIXES];
1.1       deraadt    58:
                     59:
                     60: char *NULLUNIT = "";
                     61:
1.4       deraadt    62: #ifdef DOS
                     63: #define SEPERATOR      ";"
                     64: #else
                     65: #define SEPERATOR      ":"
                     66: #endif
                     67:
1.1       deraadt    68: int unitcount;
                     69: int prefixcount;
                     70:
1.9       deraadt    71: char *dupstr(char *);
                     72: void readerror(int);
                     73: void readunits(char *);
                     74: void initializeunit(struct unittype *);
                     75: int addsubunit(char *[], char *);
                     76: void showunit(struct unittype *);
                     77: void zeroerror(void);
                     78: int addunit(struct unittype *, char *, int);
                     79: int compare(const void *, const void *);
                     80: void sortunit(struct unittype *);
                     81: void cancelunit(struct unittype *);
                     82: char *lookupunit(char *);
                     83: int reduceproduct(struct unittype *, int);
                     84: int reduceunit(struct unittype *);
                     85: int compareproducts(char **, char **);
                     86: int compareunits(struct unittype *, struct unittype *);
                     87: int completereduce(struct unittype *);
                     88: void showanswer(struct unittype *, struct unittype *);
                     89: void usage(void);
1.1       deraadt    90:
                     91: char *
                     92: dupstr(char *str)
                     93: {
                     94:        char *ret;
                     95:
1.7       deraadt    96:        ret = strdup(str);
1.1       deraadt    97:        if (!ret) {
                     98:                fprintf(stderr, "Memory allocation error\n");
                     99:                exit(3);
                    100:        }
                    101:        return (ret);
                    102: }
                    103:
                    104:
1.9       deraadt   105: void
1.1       deraadt   106: readerror(int linenum)
                    107: {
                    108:        fprintf(stderr, "Error in units file '%s' line %d\n", UNITSFILE,
                    109:            linenum);
                    110: }
                    111:
                    112:
1.9       deraadt   113: void
1.1       deraadt   114: readunits(char *userfile)
                    115: {
                    116:        char line[80], *lineptr;
                    117:        int len, linenum, i;
1.9       deraadt   118:        FILE *unitfile;
1.1       deraadt   119:
                    120:        unitcount = 0;
                    121:        linenum = 0;
                    122:
                    123:        if (userfile) {
                    124:                unitfile = fopen(userfile, "rt");
                    125:                if (!unitfile) {
                    126:                        fprintf(stderr, "Unable to open units file '%s'\n",
                    127:                            userfile);
                    128:                        exit(1);
                    129:                }
1.4       deraadt   130:        } else {
1.1       deraadt   131:                unitfile = fopen(UNITSFILE, "rt");
                    132:                if (!unitfile) {
1.9       deraadt   133:                        char filename[1000], separator[2] = SEPERATOR;
1.1       deraadt   134:                        char *direc, *env;
                    135:
                    136:                        env = getenv("PATH");
                    137:                        if (env) {
                    138:                                direc = strtok(env, separator);
                    139:                                while (direc) {
1.5       millert   140:                                        snprintf(filename, sizeof(filename),
                    141:                                            "%s/%s", direc, UNITSFILE);
1.1       deraadt   142:                                        unitfile = fopen(filename, "rt");
                    143:                                        if (unitfile)
                    144:                                                break;
                    145:                                        direc = strtok(NULL, separator);
                    146:                                }
                    147:                        }
                    148:                        if (!unitfile) {
                    149:                                fprintf(stderr, "Can't find units file '%s'\n",
                    150:                                    UNITSFILE);
                    151:                                exit(1);
                    152:                        }
                    153:                }
                    154:        }
                    155:        while (!feof(unitfile)) {
1.12    ! ray       156:                if (!fgets(line, sizeof(line), unitfile))
1.1       deraadt   157:                        break;
                    158:                linenum++;
                    159:                lineptr = line;
                    160:                if (*lineptr == '/')
                    161:                        continue;
                    162:                lineptr += strspn(lineptr, " \n\t");
                    163:                len = strcspn(lineptr, " \n\t");
                    164:                lineptr[len] = 0;
                    165:                if (!strlen(lineptr))
                    166:                        continue;
                    167:                if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
                    168:                        if (prefixcount == MAXPREFIXES) {
1.4       deraadt   169:                                fprintf(stderr,
                    170:                                    "Memory for prefixes exceeded in line %d\n",
1.1       deraadt   171:                                    linenum);
                    172:                                continue;
                    173:                        }
1.11      pat       174:
1.1       deraadt   175:                        lineptr[strlen(lineptr) - 1] = 0;
1.11      pat       176:                        for (i = 0; i < prefixcount; i++) {
                    177:                                if (!strcmp(prefixtable[i].prefixname, lineptr))
                    178:                                        break;
                    179:                        }
                    180:                        if (i < prefixcount) {
                    181:                                fprintf(stderr, "Redefinition of prefix '%s' "
                    182:                                    "on line %d ignored\n", lineptr, linenum);
                    183:                                continue;       /* skip duplicate prefix */
                    184:                        }
                    185:
1.1       deraadt   186:                        prefixtable[prefixcount].prefixname = dupstr(lineptr);
                    187:                        lineptr += len + 1;
                    188:                        if (!strlen(lineptr)) {
                    189:                                readerror(linenum);
1.10      pat       190:                                free(prefixtable[prefixcount].prefixname);
1.1       deraadt   191:                                continue;
                    192:                        }
                    193:                        lineptr += strspn(lineptr, " \n\t");
                    194:                        len = strcspn(lineptr, "\n\t");
                    195:                        lineptr[len] = 0;
                    196:                        prefixtable[prefixcount++].prefixval = dupstr(lineptr);
1.9       deraadt   197:                } else {                /* it's not a prefix */
1.1       deraadt   198:                        if (unitcount == MAXUNITS) {
1.4       deraadt   199:                                fprintf(stderr,
                    200:                                    "Memory for units exceeded in line %d\n",
1.1       deraadt   201:                                    linenum);
                    202:                                continue;
                    203:                        }
1.11      pat       204:
                    205:                        for (i = 0; i < unitcount; i++) {
                    206:                                if (!strcmp(unittable[i].uname, lineptr))
                    207:                                        break;
                    208:                        }
                    209:                        if (i < unitcount) {
                    210:                                fprintf(stderr, "Redefinition of unit '%s' "
                    211:                                    "on line %d ignored\n", lineptr, linenum);
                    212:                                continue;       /* skip duplicate unit */
                    213:                        }
                    214:
1.1       deraadt   215:                        unittable[unitcount].uname = dupstr(lineptr);
                    216:                        lineptr += len + 1;
                    217:                        lineptr += strspn(lineptr, " \n\t");
                    218:                        if (!strlen(lineptr)) {
                    219:                                readerror(linenum);
1.10      pat       220:                                free(unittable[unitcount].uname);
1.1       deraadt   221:                                continue;
                    222:                        }
                    223:                        len = strcspn(lineptr, "\n\t");
                    224:                        lineptr[len] = 0;
                    225:                        unittable[unitcount++].uval = dupstr(lineptr);
                    226:                }
                    227:        }
                    228:        fclose(unitfile);
                    229: }
                    230:
1.9       deraadt   231: void
                    232: initializeunit(struct unittype *theunit)
1.1       deraadt   233: {
                    234:        theunit->factor = 1.0;
                    235:        theunit->numerator[0] = theunit->denominator[0] = NULL;
                    236: }
                    237:
                    238:
1.9       deraadt   239: int
1.1       deraadt   240: addsubunit(char *product[], char *toadd)
                    241: {
                    242:        char **ptr;
                    243:
                    244:        for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
                    245:        if (ptr >= product + MAXSUBUNITS) {
                    246:                fprintf(stderr, "Memory overflow in unit reduction\n");
                    247:                return 1;
                    248:        }
                    249:        if (!*ptr)
                    250:                *(ptr + 1) = 0;
                    251:        *ptr = dupstr(toadd);
                    252:        return 0;
                    253: }
                    254:
                    255:
1.9       deraadt   256: void
                    257: showunit(struct unittype *theunit)
1.1       deraadt   258: {
                    259:        char **ptr;
                    260:        int printedslash;
                    261:        int counter = 1;
                    262:
                    263:        printf("\t%.8g", theunit->factor);
                    264:        for (ptr = theunit->numerator; *ptr; ptr++) {
                    265:                if (ptr > theunit->numerator && **ptr &&
                    266:                    !strcmp(*ptr, *(ptr - 1)))
                    267:                        counter++;
                    268:                else {
                    269:                        if (counter > 1)
                    270:                                printf("%s%d", powerstring, counter);
                    271:                        if (**ptr)
                    272:                                printf(" %s", *ptr);
                    273:                        counter = 1;
                    274:                }
                    275:        }
                    276:        if (counter > 1)
                    277:                printf("%s%d", powerstring, counter);
                    278:        counter = 1;
                    279:        printedslash = 0;
                    280:        for (ptr = theunit->denominator; *ptr; ptr++) {
                    281:                if (ptr > theunit->denominator && **ptr &&
                    282:                    !strcmp(*ptr, *(ptr - 1)))
                    283:                        counter++;
                    284:                else {
                    285:                        if (counter > 1)
                    286:                                printf("%s%d", powerstring, counter);
                    287:                        if (**ptr) {
                    288:                                if (!printedslash)
                    289:                                        printf(" /");
                    290:                                printedslash = 1;
                    291:                                printf(" %s", *ptr);
                    292:                        }
                    293:                        counter = 1;
                    294:                }
                    295:        }
                    296:        if (counter > 1)
                    297:                printf("%s%d", powerstring, counter);
                    298:        printf("\n");
                    299: }
                    300:
                    301:
1.9       deraadt   302: void
1.8       deraadt   303: zeroerror(void)
1.1       deraadt   304: {
                    305:        fprintf(stderr, "Unit reduces to zero\n");
                    306: }
                    307:
                    308: /*
                    309:    Adds the specified string to the unit.
                    310:    Flip is 0 for adding normally, 1 for adding reciprocal.
                    311:
                    312:    Returns 0 for successful addition, nonzero on error.
                    313: */
                    314:
1.9       deraadt   315: int
                    316: addunit(struct unittype *theunit, char *toadd, int flip)
1.1       deraadt   317: {
                    318:        char *scratch, *savescr;
                    319:        char *item;
                    320:        char *divider, *slash;
                    321:        int doingtop;
                    322:
                    323:        savescr = scratch = dupstr(toadd);
                    324:        for (slash = scratch + 1; *slash; slash++)
                    325:                if (*slash == '-' &&
                    326:                    (tolower(*(slash - 1)) != 'e' ||
                    327:                    !strchr(".0123456789", *(slash + 1))))
                    328:                        *slash = ' ';
                    329:        slash = strchr(scratch, '/');
                    330:        if (slash)
                    331:                *slash = 0;
                    332:        doingtop = 1;
                    333:        do {
                    334:                item = strtok(scratch, " *\t\n/");
                    335:                while (item) {
                    336:                        if (strchr("0123456789.", *item)) { /* item is a number */
                    337:                                double num;
                    338:
                    339:                                divider = strchr(item, '|');
                    340:                                if (divider) {
                    341:                                        *divider = 0;
                    342:                                        num = atof(item);
                    343:                                        if (!num) {
                    344:                                                zeroerror();
1.10      pat       345:                                                free(savescr);
1.1       deraadt   346:                                                return 1;
                    347:                                        }
                    348:                                        if (doingtop ^ flip)
                    349:                                                theunit->factor *= num;
                    350:                                        else
                    351:                                                theunit->factor /= num;
                    352:                                        num = atof(divider + 1);
                    353:                                        if (!num) {
                    354:                                                zeroerror();
1.10      pat       355:                                                free(savescr);
1.1       deraadt   356:                                                return 1;
                    357:                                        }
                    358:                                        if (doingtop ^ flip)
                    359:                                                theunit->factor /= num;
                    360:                                        else
                    361:                                                theunit->factor *= num;
1.9       deraadt   362:                                } else {
1.1       deraadt   363:                                        num = atof(item);
                    364:                                        if (!num) {
                    365:                                                zeroerror();
1.10      pat       366:                                                free(savescr);
1.1       deraadt   367:                                                return 1;
                    368:                                        }
                    369:                                        if (doingtop ^ flip)
                    370:                                                theunit->factor *= num;
                    371:                                        else
                    372:                                                theunit->factor /= num;
                    373:
                    374:                                }
1.9       deraadt   375:                        } else {        /* item is not a number */
1.1       deraadt   376:                                int repeat = 1;
                    377:
                    378:                                if (strchr("23456789",
                    379:                                    item[strlen(item) - 1])) {
                    380:                                        repeat = item[strlen(item) - 1] - '0';
                    381:                                        item[strlen(item) - 1] = 0;
                    382:                                }
                    383:                                for (; repeat; repeat--)
1.10      pat       384:                                        if (addsubunit(doingtop ^ flip
                    385:                                            ? theunit->numerator
                    386:                                            : theunit->denominator, item)) {
                    387:                                                free(savescr);
1.1       deraadt   388:                                                return 1;
1.10      pat       389:                                        }
1.1       deraadt   390:                        }
                    391:                        item = strtok(NULL, " *\t/\n");
                    392:                }
                    393:                doingtop--;
                    394:                if (slash) {
                    395:                        scratch = slash + 1;
1.9       deraadt   396:                } else
1.1       deraadt   397:                        doingtop--;
                    398:        } while (doingtop >= 0);
                    399:        free(savescr);
                    400:        return 0;
                    401: }
                    402:
                    403:
1.9       deraadt   404: int
1.1       deraadt   405: compare(const void *item1, const void *item2)
                    406: {
                    407:        return strcmp(*(char **) item1, *(char **) item2);
                    408: }
                    409:
                    410:
1.9       deraadt   411: void
                    412: sortunit(struct unittype *theunit)
1.1       deraadt   413: {
                    414:        char **ptr;
                    415:        int count;
                    416:
                    417:        for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
                    418:        qsort(theunit->numerator, count, sizeof(char *), compare);
                    419:        for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
                    420:        qsort(theunit->denominator, count, sizeof(char *), compare);
                    421: }
                    422:
                    423:
1.9       deraadt   424: void
                    425: cancelunit(struct unittype *theunit)
1.1       deraadt   426: {
                    427:        char **den, **num;
                    428:        int comp;
                    429:
                    430:        den = theunit->denominator;
                    431:        num = theunit->numerator;
                    432:
                    433:        while (*num && *den) {
                    434:                comp = strcmp(*den, *num);
                    435:                if (!comp) {
1.9       deraadt   436: #if 0
                    437:                        if (*den!=NULLUNIT)
                    438:                                free(*den);
                    439:                        if (*num!=NULLUNIT)
                    440:                                free(*num);
                    441: #endif
1.1       deraadt   442:                        *den++ = NULLUNIT;
                    443:                        *num++ = NULLUNIT;
1.9       deraadt   444:                } else if (comp < 0)
1.1       deraadt   445:                        den++;
                    446:                else
                    447:                        num++;
                    448:        }
                    449: }
                    450:
                    451:
                    452:
                    453:
                    454: /*
                    455:    Looks up the definition for the specified unit.
                    456:    Returns a pointer to the definition or a null pointer
                    457:    if the specified unit does not appear in the units table.
                    458: */
                    459:
                    460: static char buffer[100];       /* buffer for lookupunit answers with
                    461:                                   prefixes */
                    462:
                    463: char *
                    464: lookupunit(char *unit)
                    465: {
                    466:        int i;
                    467:        char *copy;
                    468:
                    469:        for (i = 0; i < unitcount; i++) {
                    470:                if (!strcmp(unittable[i].uname, unit))
                    471:                        return unittable[i].uval;
                    472:        }
                    473:
                    474:        if (unit[strlen(unit) - 1] == '^') {
                    475:                copy = dupstr(unit);
1.5       millert   476:                copy[strlen(copy) - 1] = '\0';
1.1       deraadt   477:                for (i = 0; i < unitcount; i++) {
                    478:                        if (!strcmp(unittable[i].uname, copy)) {
1.7       deraadt   479:                                strlcpy(buffer, copy, sizeof(buffer));
1.1       deraadt   480:                                free(copy);
                    481:                                return buffer;
                    482:                        }
                    483:                }
                    484:                free(copy);
                    485:        }
                    486:        if (unit[strlen(unit) - 1] == 's') {
                    487:                copy = dupstr(unit);
                    488:                copy[strlen(copy) - 1] = 0;
                    489:                for (i = 0; i < unitcount; i++) {
                    490:                        if (!strcmp(unittable[i].uname, copy)) {
1.7       deraadt   491:                                strlcpy(buffer, copy, sizeof(buffer));
1.1       deraadt   492:                                free(copy);
                    493:                                return buffer;
                    494:                        }
                    495:                }
                    496:                if (copy[strlen(copy) - 1] == 'e') {
                    497:                        copy[strlen(copy) - 1] = 0;
                    498:                        for (i = 0; i < unitcount; i++) {
                    499:                                if (!strcmp(unittable[i].uname, copy)) {
1.7       deraadt   500:                                        strlcpy(buffer, copy, sizeof(buffer));
1.1       deraadt   501:                                        free(copy);
                    502:                                        return buffer;
                    503:                                }
                    504:                        }
                    505:                }
                    506:                free(copy);
                    507:        }
                    508:        for (i = 0; i < prefixcount; i++) {
                    509:                if (!strncmp(prefixtable[i].prefixname, unit,
                    510:                        strlen(prefixtable[i].prefixname))) {
                    511:                        unit += strlen(prefixtable[i].prefixname);
                    512:                        if (!strlen(unit) || lookupunit(unit)) {
1.5       millert   513:                                snprintf(buffer, sizeof(buffer),
                    514:                                    "%s %s", prefixtable[i].prefixval, unit);
1.1       deraadt   515:                                return buffer;
                    516:                        }
                    517:                }
                    518:        }
                    519:        return 0;
                    520: }
                    521:
                    522:
                    523:
                    524: /*
                    525:    reduces a product of symbolic units to primitive units.
                    526:    The three low bits are used to return flags:
                    527:
                    528:      bit 0 (1) set on if reductions were performed without error.
                    529:      bit 1 (2) set on if no reductions are performed.
                    530:      bit 2 (4) set on if an unknown unit is discovered.
                    531: */
                    532:
                    533:
                    534: #define ERROR 4
                    535:
1.9       deraadt   536: int
                    537: reduceproduct(struct unittype *theunit, int flip)
1.1       deraadt   538: {
1.9       deraadt   539:        char *toadd, **product;
1.1       deraadt   540:        int didsomething = 2;
                    541:
                    542:        if (flip)
                    543:                product = theunit->denominator;
                    544:        else
                    545:                product = theunit->numerator;
                    546:
                    547:        for (; *product; product++) {
                    548:
                    549:                for (;;) {
                    550:                        if (!strlen(*product))
                    551:                                break;
                    552:                        toadd = lookupunit(*product);
                    553:                        if (!toadd) {
                    554:                                printf("unknown unit '%s'\n", *product);
                    555:                                return ERROR;
                    556:                        }
                    557:                        if (strchr(toadd, PRIMITIVECHAR))
                    558:                                break;
                    559:                        didsomething = 1;
                    560:                        if (*product != NULLUNIT) {
                    561:                                free(*product);
                    562:                                *product = NULLUNIT;
                    563:                        }
                    564:                        if (addunit(theunit, toadd, flip))
                    565:                                return ERROR;
                    566:                }
                    567:        }
                    568:        return didsomething;
                    569: }
                    570:
                    571:
                    572: /*
                    573:    Reduces numerator and denominator of the specified unit.
                    574:    Returns 0 on success, or 1 on unknown unit error.
                    575: */
                    576:
1.9       deraadt   577: int
                    578: reduceunit(struct unittype *theunit)
1.1       deraadt   579: {
                    580:        int ret;
                    581:
                    582:        ret = 1;
                    583:        while (ret & 1) {
                    584:                ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
                    585:                if (ret & 4)
                    586:                        return 1;
                    587:        }
                    588:        return 0;
                    589: }
                    590:
                    591:
1.9       deraadt   592: int
1.1       deraadt   593: compareproducts(char **one, char **two)
                    594: {
                    595:        while (*one || *two) {
                    596:                if (!*one && *two != NULLUNIT)
                    597:                        return 1;
                    598:                if (!*two && *one != NULLUNIT)
                    599:                        return 1;
                    600:                if (*one == NULLUNIT)
                    601:                        one++;
                    602:                else if (*two == NULLUNIT)
                    603:                        two++;
                    604:                else if (strcmp(*one, *two))
                    605:                        return 1;
                    606:                else
                    607:                        one++, two++;
                    608:        }
                    609:        return 0;
                    610: }
                    611:
                    612:
                    613: /* Return zero if units are compatible, nonzero otherwise */
                    614:
1.9       deraadt   615: int
                    616: compareunits(struct unittype *first, struct unittype *second)
1.1       deraadt   617: {
1.9       deraadt   618:        return compareproducts(first->numerator, second->numerator) ||
                    619:            compareproducts(first->denominator, second->denominator);
1.1       deraadt   620: }
                    621:
                    622:
1.9       deraadt   623: int
                    624: completereduce(struct unittype *unit)
1.1       deraadt   625: {
                    626:        if (reduceunit(unit))
                    627:                return 1;
                    628:        sortunit(unit);
                    629:        cancelunit(unit);
                    630:        return 0;
                    631: }
                    632:
                    633:
1.9       deraadt   634: void
                    635: showanswer(struct unittype *have, struct unittype *want)
1.1       deraadt   636: {
                    637:        if (compareunits(have, want)) {
                    638:                printf("conformability error\n");
                    639:                showunit(have);
                    640:                showunit(want);
1.9       deraadt   641:        } else
1.1       deraadt   642:                printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
                    643:                    want->factor / have->factor);
                    644: }
                    645:
                    646:
1.9       deraadt   647: void
1.8       deraadt   648: usage(void)
1.1       deraadt   649: {
1.4       deraadt   650:        fprintf(stderr, "units [-f unitsfile] [-q] [-v] [from-unit to-unit]\n");
                    651:        fprintf(stderr, "    -f specify units file\n");
1.6       pjanzen   652:        fprintf(stderr, "    -q suppress prompting (quiet)\n");
1.1       deraadt   653:        fprintf(stderr, "    -v print version number\n");
                    654:        exit(3);
                    655: }
                    656:
                    657:
1.2       deraadt   658: int
1.1       deraadt   659: main(int argc, char **argv)
                    660: {
                    661:
                    662:        struct unittype have, want;
                    663:        char havestr[81], wantstr[81];
1.2       deraadt   664:        int optchar;
1.1       deraadt   665:        char *userfile = 0;
                    666:        int quiet = 0;
                    667:
                    668:        extern char *optarg;
                    669:        extern int optind;
                    670:
1.2       deraadt   671:        while ((optchar = getopt(argc, argv, "vqf:")) != -1) {
1.1       deraadt   672:                switch (optchar) {
                    673:                case 'f':
                    674:                        userfile = optarg;
                    675:                        break;
                    676:                case 'q':
                    677:                        quiet = 1;
                    678:                        break;
                    679:                case 'v':
1.4       deraadt   680:                        fprintf(stderr,
                    681:                            "units version %s Copyright (c) 1993 by Adrian Mariano\n",
1.1       deraadt   682:                            VERSION);
1.4       deraadt   683:                        fprintf(stderr,
                    684:                            "This program may be freely distributed\n");
1.1       deraadt   685:                        usage();
                    686:                default:
                    687:                        usage();
                    688:                        break;
                    689:                }
                    690:        }
                    691:
                    692:        if (optind != argc - 2 && optind != argc)
                    693:                usage();
                    694:
                    695:        readunits(userfile);
                    696:
                    697:        if (optind == argc - 2) {
1.7       deraadt   698:                strlcpy(havestr, argv[optind], sizeof(havestr));
                    699:                strlcpy(wantstr, argv[optind + 1], sizeof(wantstr));
1.1       deraadt   700:                initializeunit(&have);
                    701:                addunit(&have, havestr, 0);
                    702:                completereduce(&have);
                    703:                initializeunit(&want);
                    704:                addunit(&want, wantstr, 0);
                    705:                completereduce(&want);
                    706:                showanswer(&have, &want);
1.9       deraadt   707:        } else {
1.1       deraadt   708:                if (!quiet)
1.4       deraadt   709:                        printf("%d units, %d prefixes\n", unitcount,
1.1       deraadt   710:                            prefixcount);
                    711:                for (;;) {
                    712:                        do {
                    713:                                initializeunit(&have);
                    714:                                if (!quiet)
                    715:                                        printf("You have: ");
1.12    ! ray       716:                                if (!fgets(havestr, sizeof(havestr), stdin)) {
1.4       deraadt   717:                                        if (!quiet)
                    718:                                                putchar('\n');
1.1       deraadt   719:                                        exit(0);
                    720:                                }
                    721:                        } while (addunit(&have, havestr, 0) ||
                    722:                            completereduce(&have));
                    723:                        do {
                    724:                                initializeunit(&want);
                    725:                                if (!quiet)
                    726:                                        printf("You want: ");
1.12    ! ray       727:                                if (!fgets(wantstr, sizeof(wantstr), stdin)) {
1.1       deraadt   728:                                        if (!quiet)
                    729:                                                putchar('\n');
                    730:                                        exit(0);
                    731:                                }
                    732:                        } while (addunit(&want, wantstr, 0) ||
                    733:                            completereduce(&want));
                    734:                        showanswer(&have, &want);
                    735:                }
                    736:        }
1.4       deraadt   737:        return (0);
1.1       deraadt   738: }