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

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