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

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