[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.23

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