Annotation of coherent/d/bin/typo.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Detect typographical errors.
        !             3:  */
        !             4: 
        !             5: #include <stdio.h>
        !             6: #include <ctype.h>
        !             7: #include <sys/stat.h>
        !             8: 
        !             9: #define        oc(c)   ((c)+'`')
        !            10: #define        NSBRK   512             /* Amount to sbrk at once in bytes */
        !            11: #define BADSBRK ((char *)-1)   /* fail from sbrk() */
        !            12: #define        NWORD   200             /* Longest word (ridiculously big) */
        !            13: #define        NHASH   64              /* Number of hash buckets (power of 2) */
        !            14: 
        !            15: char   dictfile[] = "/usr/dict/dict";
        !            16: char   digfile[] = "/usr/dict/digrams";
        !            17: char   trifile[] = "/usr/dict/trigrams";
        !            18: char   tmp[] = "/tmp/typoXXXXXX";
        !            19: char   sort[] = "sort";
        !            20: char   *tmpfile;
        !            21: char   notrimem[] = "Out of memory for trigrams";
        !            22: char   nosort[] = "Cannot locate sort";
        !            23: char   word[NWORD];
        !            24: FILE   *ifp;
        !            25: FILE   *pfp;
        !            26: 
        !            27: char   ibuf[BUFSIZ];
        !            28: char   obuf[BUFSIZ];
        !            29: char   xbuf[BUFSIZ];
        !            30: 
        !            31: unsigned hashval;
        !            32: 
        !            33: int    rflag;                  /* Raw (no removal of nroff things) input */
        !            34: int    nflag;                  /* No pre-defined statistics or exceptions */
        !            35: int    sflag;                  /* Write out statistics */
        !            36: 
        !            37: typedef        struct  EXCEPT  {
        !            38:        unsigned e_hval;
        !            39:        struct  EXCEPT  *e_next;
        !            40:        char    e_word[];
        !            41: }      EXCEPT;
        !            42: EXCEPT *except[NHASH];
        !            43: 
        !            44: /*
        !            45:  * Table of digrams, indexed by first
        !            46:  * and then second character.  [1-26]
        !            47:  * represent [a-z] inclusive and 0
        !            48:  * represents the beginning or ending of word.
        !            49:  */
        !            50: unsigned       digrams[27][27];
        !            51: 
        !            52: /*
        !            53:  * Table of trigrams, indexed by first and
        !            54:  * second letter and allocated on the third letter.
        !            55:  * After all of the input data has been
        !            56:  * sampled, the t_freq entry changes from
        !            57:  * frequency to an index of peculiarity.
        !            58:  */
        !            59: typedef        struct  TRIGRAMS {
        !            60:        struct  TRIGRAMS *t_next;
        !            61:        char    t_char;
        !            62:        unsigned char t_freq;
        !            63: }      TRIGRAMS;
        !            64: TRIGRAMS       *trigrams[27][27];
        !            65: 
        !            66: /*
        !            67:  * Table of logarithms scaled by 1000.
        !            68:  * Table from 0-99 inclusive.
        !            69:  */
        !            70: int    log1[] = {
        !            71:        0000, 0693, 1099, 1386, 1609, 1792, 1946, 2080, 2197,     /* 1-9 */
        !            72:        2303, 2398, 2485, 2565, 2639, 2708, 2772, 2833, 2890,     /* 10-18 */
        !            73:        2944, 2996, 3045, 3091, 3136, 3178, 3219, 3258, 3296,     /* 19-27 */
        !            74:        3332, 3367, 3401, 3434, 3466, 3497, 3526, 3555, 3584,     /* 28-36 */
        !            75:        3611, 3638, 3664, 3689, 3714, 3738, 3761, 3784, 3807,     /* 37-45 */
        !            76:        3829, 3850, 3871, 3892, 3912, 3932, 3951, 3970, 3989,     /* 46-54 */
        !            77:        4007, 4025, 4043, 4060, 4078, 4094, 4111, 4127, 4143,     /* 55-63 */
        !            78:        4159, 4174, 4190, 4205, 4220, 4234, 4249, 4263, 4277,     /* 64-72 */
        !            79:        4291, 4304, 4318, 4331, 4344, 4357, 4369, 4382, 4394,     /* 73-81 */
        !            80:        4407, 4419, 4431, 4443, 4454, 4466, 4477, 4489, 4500,     /* 82-90 */
        !            81:        4511, 4521, 4533, 4543, 4554, 4564, 4575, 4585, 4595,     /* 91-99 */
        !            82: };
        !            83: 
        !            84: /*
        !            85:  * Table of logarithms for each multiple
        !            86:  * of ten from 100 - 990 inclusive
        !            87:  * (scaled as above).
        !            88:  */
        !            89: int    log2[] = {
        !            90:        4605, 4701, 4788, 4868, 4942, 5011, 4075, 5136, 5193,   /* 100-180 */
        !            91:        5247, 5298, 5347, 5394, 5438, 5481, 5522, 5561, 5598,   /* 190-270 */
        !            92:        5635, 5670, 5704, 5737, 5768, 5799, 5829, 5858, 5886,   /* 280-360 */
        !            93:        5914, 5940, 5966, 5992, 6016, 6040, 6064, 6087, 6109,   /* 370-450 */
        !            94:        6131, 6153, 6174, 6194, 6215, 6234, 6254, 6273, 6292,   /* 460-540 */
        !            95:        6310, 6328, 6346, 6663, 6380, 6397, 6414, 6430, 6446,   /* 550-630 */
        !            96:        6462, 6477, 6492, 6507, 6522, 6537, 6551, 6565, 6579,   /* 640-720 */
        !            97:        6593, 6607, 6620, 6633, 6646, 6659, 6672, 6684, 6697,   /* 730-810 */
        !            98:        6709, 6721, 6733, 6745, 6757, 6769, 6780, 6791, 6802,   /* 820-900 */
        !            99:        6813, 6824, 6835, 6846, 6857, 6867, 6877, 6888, 6898,   /* 910-990 */
        !           100: };
        !           101: 
        !           102: /*
        !           103:  * Table of logarithms of multiples
        !           104:  * of 100 from 1000-9900 inclusive
        !           105:  * (scaled as before).
        !           106:  */
        !           107: int    log3[] = {
        !           108:        6908, 7003, 7090, 7170, 7244, 7313, 7378, 7438, 7496,   /* 1000-1800 */
        !           109:        7550, 7601, 7650, 7696, 7741, 7783, 7824, 7863, 7901,   /* 1900-2700 */
        !           110:        7937, 7973, 8006, 8039, 8071, 8102, 8132, 8161, 8189,   /* 2800-3600 */
        !           111:        8216, 8243, 8269, 8294, 8319, 8343, 8366, 8389, 8412,   /* 3700-4500 */
        !           112:        8434, 8455, 8476, 8497, 8517, 8537, 8556, 8576, 8594,   /* 4600-5400 */
        !           113:        8613, 8631, 8648, 8666, 8683, 8700, 8716, 8732, 8748,   /* 5500-6300 */
        !           114:        8764, 8780, 8795, 8810, 8825, 8839, 8854, 8868, 8882,   /* 6400-7200 */
        !           115:        8896, 8909, 8923, 8936, 8949, 8962, 8975, 8987, 9000,   /* 7300-8100 */
        !           116:        9012, 9024, 9036, 9048, 9060, 9071, 9083, 9094, 9105,   /* 8200-9000 */
        !           117:        9116, 9127, 9138, 9149, 9159, 9170, 9180, 9190, 9200,   /* 9100-9900 */
        !           118: };
        !           119: 
        !           120: char   *malloc();
        !           121: char   *mktemp();
        !           122: char   *sbrk();
        !           123: char   *getword();
        !           124: EXCEPT *lookup();
        !           125: FILE   *pinit();
        !           126: 
        !           127: main(argc, argv)
        !           128: char *argv[];
        !           129: {
        !           130:        register char *ap;
        !           131:        register int i;
        !           132:        FILE *fp;
        !           133: 
        !           134:        /*
        !           135:         * Because we have our own allocator.
        !           136:         */
        !           137:        setbuf(stdout, obuf);
        !           138:        setbuf(stderr, NULL);
        !           139:        while (argc>1 && *argv[1]=='-') {
        !           140:                for (ap = &argv[1][1]; *ap != '\0'; ap++)
        !           141:                        switch (*ap) {
        !           142:                        case 'n':
        !           143:                                nflag = 1;
        !           144:                                break;
        !           145: 
        !           146:                        case 'r':
        !           147:                                rflag = 1;
        !           148:                                break;
        !           149: 
        !           150:                        case 's':
        !           151:                                sflag = 1;
        !           152:                                break;
        !           153: 
        !           154:                        default:
        !           155:                                usage();
        !           156:                        }
        !           157:                argc--;
        !           158:                argv++;
        !           159:        }
        !           160:        if (sflag == 0) {
        !           161:                readdicts();
        !           162:                pfp = pinit();
        !           163:        }
        !           164:        if (argc > 1)
        !           165:                for (i=1; i<argc; i++) {
        !           166:                        if ((fp = fopen(argv[i], "r")) == NULL)
        !           167:                                tyerr("Cannot open input `%s'", argv[i]);
        !           168:                        typo(fp);
        !           169:                }
        !           170:        else
        !           171:                typo(stdin);
        !           172:        if (!sflag) {
        !           173:                pterm(pfp);
        !           174:                precompute();
        !           175:                /*
        !           176:                 * Re-read the sorted word
        !           177:                 * list.
        !           178:                 */
        !           179:                reread();
        !           180:        } else
        !           181:                outstats();
        !           182:        rmexit(0);
        !           183: }
        !           184: 
        !           185: /*
        !           186:  * Called for each input word
        !           187:  * to set up file pointer, read
        !           188:  * of individual words and enter
        !           189:  * frequency statistics into the
        !           190:  * tables.
        !           191:  */
        !           192: typo(fp)
        !           193: register FILE *fp;
        !           194: {
        !           195:        ifp = fp;
        !           196:        setbuf(fp, ibuf);
        !           197:        while (getword() != NULL) {
        !           198:                stats(word);
        !           199:                if (!sflag && lookup(word)==NULL)
        !           200:                        fprintf(pfp, "%s\n", word);
        !           201:        }
        !           202:        if (fp != stdin)
        !           203:                fclose(fp);
        !           204: }
        !           205: 
        !           206: /*
        !           207:  * Initialise the trigram and digram
        !           208:  * tables if the user requests help.
        !           209:  * Read in the exception dictionary.
        !           210:  * Put each word in a hash table.
        !           211:  */
        !           212: readdicts()
        !           213: {
        !           214:        FILE *fp;
        !           215: 
        !           216:        if (nflag)
        !           217:                return;
        !           218:        if ((fp = fopen(dictfile, "r")) != NULL) {
        !           219:                register int l;
        !           220:                register char *cp;
        !           221:                register EXCEPT *ep;
        !           222: 
        !           223:                setbuf(fp, xbuf);
        !           224:                while (fgets(cp = word, sizeof word, fp) != NULL) {
        !           225:                        l = strlen(cp);
        !           226:                        cp[l-1] = '\0';
        !           227:                        if ((ep = (EXCEPT *)malloc(l + sizeof *ep)) == NULL)
        !           228:                                tyerr("Out of memory for dictionary");
        !           229:                        hashval = 0;
        !           230:                        while (*cp)
        !           231:                                hashval += *cp++;
        !           232:                        l = hashval%NHASH;
        !           233:                        ep->e_next = except[l];
        !           234:                        except[l] = ep;
        !           235:                        ep->e_hval = hashval;
        !           236:                        strcpy(ep->e_word, word);
        !           237:                }
        !           238:                fclose(fp);
        !           239:        }
        !           240:        if ((fp = fopen(digfile, "r")) != NULL) {
        !           241:                register int t1, t2;
        !           242: 
        !           243:                setbuf(fp, xbuf);
        !           244:                while (fgets(word, NWORD, fp) != NULL) {
        !           245:                        t1 = cton(word[0]);
        !           246:                        t2 = cton(word[1]);
        !           247:                        digrams[t1][t2] = atoi(&word[2]);
        !           248:                }
        !           249:                fclose(fp);
        !           250:        }
        !           251:        if ((fp = fopen(trifile, "r")) != NULL) {
        !           252:                register TRIGRAMS *tp;
        !           253:                register int t1, t2, t3;
        !           254: 
        !           255:                setbuf(fp, xbuf);
        !           256:                while (fgets(word, NWORD, fp) != NULL) {
        !           257:                        t1 = cton(word[0]);
        !           258:                        t2 = cton(word[1]);
        !           259:                        t3 = cton(word[2]);
        !           260:                        for (tp = trigrams[t1][t2]; tp!=NULL; tp = tp->t_next) {
        !           261:                                if (tp->t_char == t3) {
        !           262:                                        tp->t_freq += atoi(&word[3]);
        !           263:                                        break;
        !           264:                                }
        !           265:                        }
        !           266:                        if (tp == NULL) {
        !           267:                                if ((tp = (TRIGRAMS *)malloc(sizeof *tp))==NULL)
        !           268:                                        tyerr(notrimem);
        !           269:                                tp->t_freq = atoi(&word[3]);
        !           270:                                tp->t_char = t3;
        !           271:                                tp->t_next = trigrams[t1][t2];
        !           272:                                trigrams[t1][t2] = tp;
        !           273:                        }
        !           274:                }
        !           275:                fclose(fp);
        !           276:        }
        !           277: }
        !           278: 
        !           279: /*
        !           280:  * Get a character from a digram or
        !           281:  * trigram file and check it.
        !           282:  * Convert character to index number
        !           283:  * for tables.
        !           284:  */
        !           285: cton(c)
        !           286: register unsigned c;
        !           287: {
        !           288:        if ((c -= '`') >= 27)
        !           289:                tyerr("Invalid digram/trigram file format");
        !           290:        return (c);
        !           291: }
        !           292: 
        !           293: /*
        !           294:  * Get the next word from the input.
        !           295:  */
        !           296: char *
        !           297: getword()
        !           298: {
        !           299:        register char *cp;
        !           300:        register int c;
        !           301: 
        !           302:        while (!isalpha(c = tgetc()))
        !           303:                if (c == EOF)
        !           304:                        return (NULL);
        !           305:        cp = word;
        !           306:        for (;;) {
        !           307:                if (isupper(c))
        !           308:                        c = tolower(c);
        !           309:                *cp++ = c;
        !           310:                if (!isalpha(c = tgetc()))
        !           311:                        break;
        !           312:        }
        !           313:        *cp = '\0';
        !           314:        return (word);
        !           315: }
        !           316: 
        !           317: /*
        !           318:  * Get a character.  This also checks
        !           319:  * for roff stuff (if -r is not specified)
        !           320:  * and hyphenated words.
        !           321:  */
        !           322: tgetc()
        !           323: {
        !           324:        static int nlflag = 1;
        !           325:        register int c;
        !           326: 
        !           327:        while (nlflag) {
        !           328:                if ((c = getc(ifp)) == '.')
        !           329:                        while ((c = getc(ifp))!='\n' && c!=EOF)
        !           330:                                ;
        !           331:                else {
        !           332:                        ungetc(c, ifp);
        !           333:                        nlflag = 0;
        !           334:                        break;
        !           335:                }
        !           336:        }
        !           337: again:
        !           338:        if ((c = getc(ifp)) == '\n')
        !           339:                nlflag = 1;
        !           340:        else if (c == '-') {
        !           341:                if ((c = getc(ifp)) == '\n')
        !           342:                        goto again;
        !           343:        } else if (c == '\'')
        !           344:                goto again;
        !           345:        else if (c == '\\') {   /* Fonts and sizes */
        !           346:                switch (c = getc(ifp)) {
        !           347:                case 'f':
        !           348:                        c = getc(ifp);
        !           349:                        goto again;
        !           350: 
        !           351:                case 's':
        !           352:                        while ((c = getc(ifp))>='0' && c<='9')
        !           353:                                ;
        !           354:                }
        !           355:        }
        !           356:        return (c);
        !           357: }
        !           358: 
        !           359: /*
        !           360:  * Lookup an input word
        !           361:  * in the exception list.
        !           362:  */
        !           363: EXCEPT *
        !           364: lookup(wp)
        !           365: char *wp;
        !           366: {
        !           367:        register char *cp = wp;
        !           368:        register EXCEPT *ep;
        !           369: 
        !           370:        hashval = 0;
        !           371:        while (*cp != '\0')
        !           372:                hashval += *cp++;
        !           373:        for (ep = except[hashval%NHASH]; ep != NULL; ep = ep->e_next)
        !           374:                if (ep->e_hval==hashval && strcmp(ep->e_word, word)==0)
        !           375:                        return (ep);
        !           376:        return (NULL);
        !           377: }
        !           378: 
        !           379: /*
        !           380:  * Compute the trigram and digram statistics
        !           381:  * on this word.
        !           382:  */
        !           383: stats(wp)
        !           384: register char *wp;
        !           385: {
        !           386:        register int t1, t2, t3;
        !           387:        register TRIGRAMS *tp;
        !           388: 
        !           389:        t1 = 0;
        !           390:        while (*wp != '\0') {
        !           391:                t2 = *wp++;
        !           392:                t3 = *wp;
        !           393:                if (t2>='a' && t2<='z')
        !           394:                        t2 -= 'a'-1;
        !           395:                if (t3>='a' && t3<='z')
        !           396:                        t3 -= 'a'-1;
        !           397:                digrams[t1][t2]++;
        !           398:                for (tp = trigrams[t1][t2]; tp != NULL; tp = tp->t_next)
        !           399:                        if (tp->t_char == t3) {
        !           400:                                tp->t_freq++;
        !           401:                                break;
        !           402:                        }
        !           403:                if (tp == NULL) {
        !           404:                        if ((tp = (TRIGRAMS *)malloc(sizeof *tp)) != NULL) {
        !           405:                                tp->t_freq = 1;
        !           406:                                tp->t_char = t3;
        !           407:                                tp->t_next = trigrams[t1][t2];
        !           408:                                trigrams[t1][t2] = tp;
        !           409:                        }
        !           410:                }
        !           411:                t1 = t2;
        !           412:        }
        !           413:        digrams[t2][t3]++;
        !           414: }
        !           415: 
        !           416: /*
        !           417:  * Output the digram and trigram statistics
        !           418:  * onto file `digram' and `trigram'.
        !           419:  */
        !           420: outstats()
        !           421: {
        !           422:        char x1buf[BUFSIZ];
        !           423:        register TRIGRAMS *tp;
        !           424:        register int t1, t2;
        !           425:        register int freq;
        !           426:        FILE *dfp, *tfp;
        !           427: 
        !           428:        if ((dfp = fopen("digrams", "w")) == NULL)
        !           429:                tyerr("Cannot create digrams file");
        !           430:        if ((tfp = fopen("trigrams", "w")) == NULL)
        !           431:                tyerr("Cannot create trigrams file");
        !           432:        setbuf(dfp, xbuf);
        !           433:        setbuf(tfp, x1buf);
        !           434:        for (t1 = 0; t1 < 27; t1++)
        !           435:                for (t2 = 0; t2 < 27; t2++) {
        !           436:                        if ((freq = digrams[t1][t2]) != 0)
        !           437:                                fprintf(dfp, "%c%c%d\n", oc(t1), oc(t2), freq);
        !           438:                        for (tp = trigrams[t1][t2]; tp!=NULL; tp = tp->t_next)
        !           439:                                fprintf(tfp, "%c%c%c%d\n", oc(t1), oc(t2),
        !           440:                                    oc(tp->t_char), tp->t_freq);
        !           441:                }
        !           442:        fclose(dfp);
        !           443:        fclose(tfp);
        !           444: }
        !           445: 
        !           446: /*
        !           447:  * Compute index of peculiarity on a
        !           448:  * word.  This is the RMS mean of the
        !           449:  * index for each trigram (say XYZ).
        !           450:  * This index is 1/2(log (xy) + log(yz)) - log(xyz)
        !           451:  * If there is only one trigram, the RMS
        !           452:  * mean is taken to be the one sample.
        !           453:  */
        !           454: pindex(wp)
        !           455: register char *wp;
        !           456: {
        !           457:        register int t1, t2, t3;
        !           458:        register TRIGRAMS *tp;
        !           459:        register long sumsq;
        !           460:        register long sum;
        !           461:        register unsigned count;
        !           462:        register int ntri;
        !           463: 
        !           464:        ntri = 0;
        !           465:        t1 = 0;
        !           466:        sum = sumsq = 0;
        !           467:        while (*wp != '\0') {
        !           468:                t2 = *wp++;
        !           469:                t3 = *wp;
        !           470:                if (t2>='a' && t2<='z')
        !           471:                        t2 -= 'a'-1;
        !           472:                if (t3>='a' && t3<='z')
        !           473:                        t3 -= 'a'-1;
        !           474:                for (tp = trigrams[t1][t2]; tp != NULL; tp = tp->t_next)
        !           475:                        if (tp->t_char == t3) {
        !           476:                                count = tp->t_freq;
        !           477:                                break;
        !           478:                        }
        !           479:                if (tp == NULL)
        !           480:                        tyerr("Missing trigram");
        !           481:                sum += count;
        !           482:                sumsq += (long)count*count;
        !           483:                ntri++;
        !           484:                t1 = t2;
        !           485:        }
        !           486:        if (ntri > 1) {
        !           487:                sum *= sum;
        !           488:                sum /= ntri;
        !           489:                sum = sumsq-sum;
        !           490:        }
        !           491:        count = (qsqrt((int)sum) + 5) / 10;
        !           492:        return (count);
        !           493: }
        !           494: 
        !           495: /*
        !           496:  * Pre-compute the trigram statistics.
        !           497:  * This essentially transforms the
        !           498:  * trigram tables from a table
        !           499:  * of frequencies to a table of
        !           500:  * indices of peculiarity for that
        !           501:  * particular trigram.
        !           502:  */
        !           503: precompute()
        !           504: {
        !           505:        register int i, j;
        !           506:        register TRIGRAMS *tp;
        !           507:        register int logij;
        !           508: 
        !           509:        for (i=0; i<27; i++)
        !           510:                for (j=0; j<27; j++) {
        !           511:                        logij = qlog(digrams[i][j]-1);
        !           512:                        for (tp = trigrams[i][j]; tp != NULL; tp = tp->t_next) {
        !           513:                                tp->t_freq = ((logij
        !           514:                                    + qlog(digrams[j][tp->t_char]-1))/2
        !           515:                                    - qlog(tp->t_freq-1)) / 100;
        !           516:                        }
        !           517:                }
        !           518: }
        !           519: 
        !           520: /*
        !           521:  * Evaluate a natural logarithm
        !           522:  * quickly by table lookup.
        !           523:  * The resulting logarithm
        !           524:  * is multiplied by 1000.
        !           525:  * By definition, the log of 0 (or less) is
        !           526:  * -10.
        !           527:  */
        !           528: qlog(n)
        !           529: register unsigned n;
        !           530: {
        !           531:        if (n <= 0)
        !           532:                return (-10*1000);
        !           533:        if (n < 100)
        !           534:                return (log1[n-1]);
        !           535:        if (n < 1000)
        !           536:                return (log2[(n-95)/10]);
        !           537:        if (n < 10000)
        !           538:                return (log3[(n-950)/100]);
        !           539:        return (10*1000);
        !           540: }
        !           541: 
        !           542: /*
        !           543:  * Quick version of sqare root.
        !           544:  * Uses Newton's method.
        !           545:  */
        !           546: qsqrt(x)
        !           547: register unsigned x;
        !           548: {
        !           549:        register int maxterm = 50;
        !           550:        register unsigned old, new;
        !           551: 
        !           552:        if ((old = x/10) == 0) {
        !           553:                old = 1;
        !           554:                if (x == 0)
        !           555:                        return (0);
        !           556:        }
        !           557:        do {
        !           558:                new = (x/old+old)/2;
        !           559:                if (old == new)
        !           560:                        break;
        !           561:                old = new;
        !           562:        } while (--maxterm);
        !           563:        return (new);
        !           564: }
        !           565: 
        !           566: /*
        !           567:  * Build pipe to a sort routine.
        !           568:  */
        !           569: FILE *
        !           570: pinit()
        !           571: {
        !           572:        int pfd[2];
        !           573:        register int pid;
        !           574:        register int fd;
        !           575:        FILE *fp;
        !           576: 
        !           577:        tmpfile = mktemp(tmp);
        !           578:        if (pipe(pfd) < 0)
        !           579:                tyerr("Cannot pipe to sort");
        !           580:        if ((pid = fork()) < 0)
        !           581:                tyerr("Cannot fork for sort");
        !           582:        if (pid) {
        !           583:                close(pfd[0]);
        !           584:                if ((fp = fdopen(pfd[1], "w")) != NULL)
        !           585:                        setbuf(fp, xbuf);
        !           586:                return (fp);
        !           587:        } else {
        !           588:                dup2(pfd[0], 0);
        !           589:                close(pfd[0]);
        !           590:                close(pfd[1]);
        !           591:                if ((fd = creat(tmp, 0666)) < 0)
        !           592:                        tyerr("Cannot create temporary file");
        !           593:                dup2(fd, 1);
        !           594:                close(fd);
        !           595:                execlp(sort, sort, "-u", NULL);
        !           596:                tyerr(nosort);
        !           597:        }
        !           598: }
        !           599: 
        !           600: /*
        !           601:  * Close off the pipe and wait
        !           602:  * for the sort command to
        !           603:  * complete.
        !           604:  */
        !           605: pterm(fp)
        !           606: FILE *fp;
        !           607: {
        !           608:        int status;
        !           609: 
        !           610:        fclose(fp);
        !           611:        while (wait(&status) >= 0)
        !           612:                if (status)
        !           613:                        tyerr("Sort failed");
        !           614: }
        !           615: 
        !           616: /*
        !           617:  * Re-read the sorted word-list
        !           618:  * from the temp file.  Because
        !           619:  * sort -u is not implemented,
        !           620:  * we have to guarantee uniqueness
        !           621:  * ourselves.
        !           622:  * The output is piped into a
        !           623:  * `sort -nr' command.
        !           624:  */
        !           625: reread()
        !           626: {
        !           627:        FILE *fp;
        !           628:        register int ind;
        !           629:        int pid, status;
        !           630:        int pfd[2];
        !           631: 
        !           632:        if ((fp = fopen(tmpfile, "r")) == NULL)
        !           633:                tyerr("Cannot re-open temp-file");
        !           634:        setbuf(fp, xbuf);
        !           635:        if (pipe(pfd) < 0)
        !           636:                tyerr("Cannot create pipe to sort output");
        !           637:        if ((pid = fork()) < 0)
        !           638:                fprintf(stderr, "Cannot fork -- output is not sorted\n");
        !           639:        else if (pid) {
        !           640:                dup2(pfd[1], 1);
        !           641:                close(pfd[0]);
        !           642:                close(pfd[1]);
        !           643:        } else {
        !           644:                dup2(pfd[0], 0);
        !           645:                close(pfd[0]);
        !           646:                close(pfd[1]);
        !           647:                execlp(sort, sort, "-nr", NULL);
        !           648:                tyerr(nosort);
        !           649:        }
        !           650:        while (fgets(word, NWORD, fp) != NULL) {
        !           651:                word[strlen(word)-1] = '\0';
        !           652:                ind = pindex(word);
        !           653:                printf("%2d  %s\n", ind, word);
        !           654:        }
        !           655:        fclose(fp);
        !           656:        fclose(stdout);
        !           657:        while (wait(&status) >= 0)
        !           658:                ;
        !           659: }
        !           660: 
        !           661: /*
        !           662:  * A simple malloc for which there
        !           663:  * is no free.  It just uses sbrk and
        !           664:  * returns a value.
        !           665:  * `size' is in bytes.
        !           666:  */
        !           667: char *
        !           668: malloc(size)
        !           669: register unsigned size;
        !           670: {
        !           671:        static int *rp, *ep;
        !           672:        register int *cp;
        !           673: 
        !           674:        if ((size = (size+sizeof(int)-1)/sizeof(int)) == 0)
        !           675:                return (NULL);
        !           676:        if (rp==NULL || rp+size>=ep) {
        !           677:                if ((ep = (int *)sbrk(NSBRK)) == BADSBRK)
        !           678:                        return (NULL);
        !           679:                if (rp == NULL)
        !           680:                        rp = ep;
        !           681:                ep += NSBRK/sizeof(int);
        !           682:        }
        !           683:        cp = rp;
        !           684:        rp += size;
        !           685:        return (cp);
        !           686: }
        !           687: 
        !           688: /*
        !           689:  * Dummy free.
        !           690:  */
        !           691: free(p)
        !           692: char *p;
        !           693: {
        !           694:        tyerr("Free not allowed");
        !           695: }
        !           696: 
        !           697: /*
        !           698:  * Dummy realloc
        !           699:  */
        !           700: char *
        !           701: realloc(p)
        !           702: char *p;
        !           703: {
        !           704:        tyerr("realloc not allowed");
        !           705: }
        !           706: 
        !           707: /*
        !           708:  * Exit, removing the temp-file
        !           709:  * if it is found.
        !           710:  */
        !           711: rmexit(s)
        !           712: {
        !           713:        if (tmpfile != NULL)
        !           714:                unlink(tmpfile);
        !           715:        exit(s);
        !           716: }
        !           717: 
        !           718: /*
        !           719:  * Error and usage messages
        !           720:  */
        !           721: /* VARARGS */
        !           722: tyerr(x)
        !           723: {
        !           724:        fprintf(stderr, "typo: %r", &x);
        !           725:        putc('\n', stderr);
        !           726:        rmexit(1);
        !           727: }
        !           728: 
        !           729: usage()
        !           730: {
        !           731:        fprintf(stderr, "Usage: typo [-nrs] file\n");
        !           732:        rmexit(1);
        !           733: }

unix.superglobalmegacorp.com

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