Annotation of 43BSDReno/games/fortune/fortune.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1986 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * Ken Arnold.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms are permitted
        !             9:  * provided that the above copyright notice and this paragraph are
        !            10:  * duplicated in all such forms and that any documentation,
        !            11:  * advertising materials, and other materials related to such
        !            12:  * distribution and use acknowledge that the software was developed
        !            13:  * by the University of California, Berkeley.  The name of the
        !            14:  * University may not be used to endorse or promote products derived
        !            15:  * from this software without specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  */
        !            20: 
        !            21: #ifndef lint
        !            22: char copyright[] =
        !            23: "@(#) Copyright (c) 1986 The Regents of the University of California.\n\
        !            24:  All rights reserved.\n";
        !            25: #endif /* not lint */
        !            26: 
        !            27: #ifndef lint
        !            28: static char sccsid[] = "@(#)fortune.c  5.12 (Berkeley) 12/15/89";
        !            29: #endif /* not lint */
        !            30: 
        !            31: # include      <machine/endian.h>
        !            32: # include      <sys/param.h>
        !            33: # include      <sys/stat.h>
        !            34: # include      <sys/dir.h>
        !            35: # include      <stdio.h>
        !            36: # include      <assert.h>
        !            37: # include      "strfile.h"
        !            38: # include      "pathnames.h"
        !            39: 
        !            40: #ifdef SYSV
        !            41: # include      <dirent.h>
        !            42: 
        !            43: # define       NO_LOCK
        !            44: # define       REGCMP
        !            45: # ifdef        NO_REGEX
        !            46: #      undef    NO_REGEX
        !            47: # endif        /* NO_REGEX */
        !            48: # define       index   strchr
        !            49: # define       rindex  strrchr
        !            50: #endif /* SYSV */
        !            51: 
        !            52: #ifndef NO_REGEX
        !            53: # include      <ctype.h>
        !            54: #endif /* NO_REGEX */
        !            55: 
        !            56: # ifndef NO_LOCK
        !            57: # include      <sys/file.h>
        !            58: # endif        /* NO_LOCK */
        !            59: 
        !            60: # ifndef F_OK
        !            61: /* codes for access() */
        !            62: # define       F_OK            0       /* does file exist */
        !            63: # define       X_OK            1       /* is it executable by caller */
        !            64: # define       W_OK            2       /* writable by caller */
        !            65: # define       R_OK            4       /* readable by caller */
        !            66: # endif        /* F_OK */
        !            67: 
        !            68: # define       TRUE    1
        !            69: # define       FALSE   0
        !            70: # define       bool    short
        !            71: 
        !            72: # define       MINW    6               /* minimum wait if desired */
        !            73: # define       CPERS   20              /* # of chars for each sec */
        !            74: # define       SLEN    160             /* # of chars in short fortune */
        !            75: 
        !            76: # define       POS_UNKNOWN     ((unsigned long) -1)    /* pos for file unknown */
        !            77: # define       NO_PROB         (-1)            /* no prob specified for file */
        !            78: 
        !            79: # ifdef DEBUG
        !            80: # define       DPRINTF(l,x)    if (Debug >= l) fprintf x; else
        !            81: # undef                NDEBUG
        !            82: # else /* DEBUG */
        !            83: # define       DPRINTF(l,x)
        !            84: # define       NDEBUG  1
        !            85: # endif        /* DEBUG */
        !            86: 
        !            87: typedef struct fd {
        !            88:        int             percent;
        !            89:        int             fd, datfd;
        !            90:        unsigned long   pos;
        !            91:        FILE            *inf;
        !            92:        char            *name;
        !            93:        char            *path;
        !            94:        char            *datfile, *posfile;
        !            95:        bool            read_tbl;
        !            96:        bool            was_pos_file;
        !            97:        STRFILE         tbl;
        !            98:        int             num_children;
        !            99:        struct fd       *child, *parent;
        !           100:        struct fd       *next, *prev;
        !           101: } FILEDESC;
        !           102: 
        !           103: bool   Found_one;                      /* did we find a match? */
        !           104: bool   Find_files      = FALSE;        /* just find a list of proper fortune files */
        !           105: bool   Wait            = FALSE;        /* wait desired after fortune */
        !           106: bool   Short_only      = FALSE;        /* short fortune desired */
        !           107: bool   Long_only       = FALSE;        /* long fortune desired */
        !           108: bool   Offend          = FALSE;        /* offensive fortunes only */
        !           109: bool   All_forts       = FALSE;        /* any fortune allowed */
        !           110: bool   Equal_probs     = FALSE;        /* scatter un-allocted prob equally */
        !           111: #ifndef NO_REGEX
        !           112: bool   Match           = FALSE;        /* dump fortunes matching a pattern */
        !           113: #endif
        !           114: #ifdef DEBUG
        !           115: bool   Debug = FALSE;                  /* print debug messages */
        !           116: #endif
        !           117: 
        !           118: char   *Fortbuf = NULL;                        /* fortune buffer for -m */
        !           119: 
        !           120: int    Fort_len = 0;
        !           121: 
        !           122: off_t  Seekpts[2];                     /* seek pointers to fortunes */
        !           123: 
        !           124: FILEDESC       *File_list = NULL,      /* Head of file list */
        !           125:                *File_tail = NULL;      /* Tail of file list */
        !           126: FILEDESC       *Fortfile;              /* Fortune file to use */
        !           127: 
        !           128: STRFILE                Noprob_tbl;             /* sum of data for all no prob files */
        !           129: 
        !           130: char   *do_malloc(), *copy(), *off_name();
        !           131: 
        !           132: FILEDESC       *pick_child(), *new_fp();
        !           133: 
        !           134: extern char    *malloc(), *index(), *rindex(), *strcpy(), *strcat();
        !           135: 
        !           136: extern time_t  time();
        !           137: 
        !           138: #ifndef NO_REGEX
        !           139: char   *conv_pat();
        !           140: #endif
        !           141: 
        !           142: #ifndef NO_REGEX
        !           143: #ifdef REGCMP
        !           144: # define       RE_COMP(p)      (Re_pat = regcmp(p, NULL))
        !           145: # define       BAD_COMP(f)     ((f) == NULL)
        !           146: # define       RE_EXEC(p)      regex(Re_pat, (p))
        !           147: 
        !           148: char   *Re_pat;
        !           149: 
        !           150: char   *regcmp(), *regex();
        !           151: #else
        !           152: # define       RE_COMP(p)      (p = re_comp(p))
        !           153: # define       BAD_COMP(f)     ((f) != NULL)
        !           154: # define       RE_EXEC(p)      re_exec(p)
        !           155: 
        !           156: char   *re_comp();
        !           157: #ifdef SYSV
        !           158: char   *re_exec();
        !           159: #else
        !           160: int    re_exec();
        !           161: #endif
        !           162: #endif
        !           163: #endif
        !           164: 
        !           165: main(ac, av)
        !           166: int    ac;
        !           167: char   *av[];
        !           168: {
        !           169: #ifdef OK_TO_WRITE_DISK
        !           170:        int     fd;
        !           171: #endif /* OK_TO_WRITE_DISK */
        !           172: 
        !           173:        getargs(ac, av);
        !           174: 
        !           175: #ifndef NO_REGEX
        !           176:        if (Match)
        !           177:                exit(find_matches() != 0);
        !           178: #endif
        !           179: 
        !           180:        init_prob();
        !           181:        srandom((int)(time((time_t *) NULL) + getpid()));
        !           182:        do {
        !           183:                get_fort();
        !           184:        } while ((Short_only && fortlen() > SLEN) ||
        !           185:                 (Long_only && fortlen() <= SLEN));
        !           186: 
        !           187:        display(Fortfile);
        !           188: 
        !           189: #ifdef OK_TO_WRITE_DISK
        !           190:        if ((fd = creat(Fortfile->posfile, 0666)) < 0) {
        !           191:                perror(Fortfile->posfile);
        !           192:                exit(1);
        !           193:        }
        !           194: #ifdef LOCK_EX
        !           195:        /*
        !           196:         * if we can, we exclusive lock, but since it isn't very
        !           197:         * important, we just punt if we don't have easy locking
        !           198:         * available.
        !           199:         */
        !           200:        (void) flock(fd, LOCK_EX);
        !           201: #endif /* LOCK_EX */
        !           202:        write(fd, (char *) &Fortfile->pos, sizeof Fortfile->pos);
        !           203:        if (!Fortfile->was_pos_file)
        !           204:                (void) chmod(Fortfile->path, 0666);
        !           205: #ifdef LOCK_EX
        !           206:        (void) flock(fd, LOCK_UN);
        !           207: #endif /* LOCK_EX */
        !           208: #endif /* OK_TO_WRITE_DISK */
        !           209:        if (Wait) {
        !           210:                if (Fort_len == 0)
        !           211:                        (void) fortlen();
        !           212:                sleep((unsigned int) max(Fort_len / CPERS, MINW));
        !           213:        }
        !           214:        exit(0);
        !           215:        /* NOTREACHED */
        !           216: }
        !           217: 
        !           218: display(fp)
        !           219: FILEDESC       *fp;
        !           220: {
        !           221:        register char   *p, ch;
        !           222:        char    line[BUFSIZ];
        !           223: 
        !           224:        open_fp(fp);
        !           225:        (void) fseek(fp->inf, Seekpts[0], 0);
        !           226:        for (Fort_len = 0; fgets(line, sizeof line, fp->inf) != NULL &&
        !           227:            !STR_ENDSTRING(line, fp->tbl); Fort_len++) {
        !           228:                if (fp->tbl.str_flags & STR_ROTATED)
        !           229:                        for (p = line; ch = *p; ++p)
        !           230:                                if (isupper(ch))
        !           231:                                        *p = 'A' + (ch - 'A' + 13) % 26;
        !           232:                                else if (islower(ch))
        !           233:                                        *p = 'a' + (ch - 'a' + 13) % 26;
        !           234:                fputs(line, stdout);
        !           235:        }
        !           236:        (void) fflush(stdout);
        !           237: }
        !           238: 
        !           239: /*
        !           240:  * fortlen:
        !           241:  *     Return the length of the fortune.
        !           242:  */
        !           243: fortlen()
        !           244: {
        !           245:        register int    nchar;
        !           246:        char            line[BUFSIZ];
        !           247: 
        !           248:        if (!(Fortfile->tbl.str_flags & (STR_RANDOM | STR_ORDERED)))
        !           249:                nchar = (Seekpts[1] - Seekpts[0] <= SLEN);
        !           250:        else {
        !           251:                open_fp(Fortfile);
        !           252:                (void) fseek(Fortfile->inf, Seekpts[0], 0);
        !           253:                nchar = 0;
        !           254:                while (fgets(line, sizeof line, Fortfile->inf) != NULL &&
        !           255:                       !STR_ENDSTRING(line, Fortfile->tbl))
        !           256:                        nchar += strlen(line);
        !           257:        }
        !           258:        Fort_len = nchar;
        !           259:        return nchar;
        !           260: }
        !           261: 
        !           262: /*
        !           263:  *     This routine evaluates the arguments on the command line
        !           264:  */
        !           265: getargs(argc, argv)
        !           266: register int   argc;
        !           267: register char  **argv;
        !           268: {
        !           269:        register int    ignore_case;
        !           270: # ifndef NO_REGEX
        !           271:        register char   *pat;
        !           272: # endif        /* NO_REGEX */
        !           273:        extern char *optarg;
        !           274:        extern int optind;
        !           275:        int ch;
        !           276: 
        !           277:        ignore_case = FALSE;
        !           278:        pat = NULL;
        !           279: 
        !           280: # ifdef DEBUG
        !           281:        while ((ch = getopt(argc, argv, "aDefilm:osw")) != EOF)
        !           282: #else
        !           283:        while ((ch = getopt(argc, argv, "aefilm:osw")) != EOF)
        !           284: #endif /* DEBUG */
        !           285:                switch(ch) {
        !           286:                case 'a':               /* any fortune */
        !           287:                        All_forts++;
        !           288:                        break;
        !           289: # ifdef DEBUG
        !           290:                case 'D':
        !           291:                        Debug++;
        !           292:                        break;
        !           293: # endif /* DEBUG */
        !           294:                case 'e':
        !           295:                        Equal_probs++;  /* scatter un-allocted prob equally */
        !           296:                        break;
        !           297:                case 'f':               /* find fortune files */
        !           298:                        Find_files++;
        !           299:                        break;
        !           300:                case 'l':               /* long ones only */
        !           301:                        Long_only++;
        !           302:                        Short_only = FALSE;
        !           303:                        break;
        !           304:                case 'o':               /* offensive ones only */
        !           305:                        Offend++;
        !           306:                        break;
        !           307:                case 's':               /* short ones only */
        !           308:                        Short_only++;
        !           309:                        Long_only = FALSE;
        !           310:                        break;
        !           311:                case 'w':               /* give time to read */
        !           312:                        Wait++;
        !           313:                        break;
        !           314: # ifdef        NO_REGEX
        !           315:                case 'i':                       /* case-insensitive match */
        !           316:                case 'm':                       /* dump out the fortunes */
        !           317:                        (void) fprintf(stderr,
        !           318:                            "fortune: can't match fortunes on this system (Sorry)\n");
        !           319:                        exit(0);
        !           320: # else /* NO_REGEX */
        !           321:                case 'm':                       /* dump out the fortunes */
        !           322:                        Match++;
        !           323:                        pat = optarg;
        !           324:                        break;
        !           325:                case 'i':                       /* case-insensitive match */
        !           326:                        ignore_case++;
        !           327:                        break;
        !           328: # endif        /* NO_REGEX */
        !           329:                case '?':
        !           330:                default:
        !           331:                        usage();
        !           332:                }
        !           333:        argc -= optind;
        !           334:        argv += optind;
        !           335: 
        !           336:        if (!form_file_list(argv, argc))
        !           337:                exit(1);        /* errors printed through form_file_list() */
        !           338: #ifdef DEBUG
        !           339:        if (Debug >= 1)
        !           340:                print_file_list();
        !           341: #endif /* DEBUG */
        !           342:        if (Find_files) {
        !           343:                print_file_list();
        !           344:                exit(0);
        !           345:        }
        !           346: 
        !           347: # ifndef NO_REGEX
        !           348:        if (pat != NULL) {
        !           349:                if (ignore_case)
        !           350:                        pat = conv_pat(pat);
        !           351:                if (BAD_COMP(RE_COMP(pat))) {
        !           352: #ifndef REGCMP
        !           353:                        fprintf(stderr, "%s\n", pat);
        !           354: #else  /* REGCMP */
        !           355:                        fprintf(stderr, "bad pattern: %s\n", pat);
        !           356: #endif /* REGCMP */
        !           357:                }
        !           358:        }
        !           359: # endif        /* NO_REGEX */
        !           360: }
        !           361: 
        !           362: /*
        !           363:  * form_file_list:
        !           364:  *     Form the file list from the file specifications.
        !           365:  */
        !           366: form_file_list(files, file_cnt)
        !           367: register char  **files;
        !           368: register int   file_cnt;
        !           369: {
        !           370:        register int    i, percent;
        !           371:        register char   *sp;
        !           372: 
        !           373:        if (file_cnt == 0)
        !           374:                if (Find_files)
        !           375:                        return add_file(NO_PROB, FORTDIR, NULL, &File_list,
        !           376:                                        &File_tail, NULL);
        !           377:                else
        !           378:                        return add_file(NO_PROB, "fortunes", FORTDIR,
        !           379:                                        &File_list, &File_tail, NULL);
        !           380:        for (i = 0; i < file_cnt; i++) {
        !           381:                percent = NO_PROB;
        !           382:                if (!isdigit(files[i][0]))
        !           383:                        sp = files[i];
        !           384:                else {
        !           385:                        percent = 0;
        !           386:                        for (sp = files[i]; isdigit(*sp); sp++)
        !           387:                                percent = percent * 10 + *sp - '0';
        !           388:                        if (percent > 100) {
        !           389:                                fprintf(stderr, "percentages must be <= 100\n");
        !           390:                                return FALSE;
        !           391:                        }
        !           392:                        if (*sp == '.') {
        !           393:                                fprintf(stderr, "percentages must be integers\n");
        !           394:                                return FALSE;
        !           395:                        }
        !           396:                        /*
        !           397:                         * If the number isn't followed by a '%', then
        !           398:                         * it was not a percentage, just the first part
        !           399:                         * of a file name which starts with digits.
        !           400:                         */
        !           401:                        if (*sp != '%') {
        !           402:                                percent = NO_PROB;
        !           403:                                sp = files[i];
        !           404:                        }
        !           405:                        else if (*++sp == '\0') {
        !           406:                                if (++i >= file_cnt) {
        !           407:                                        fprintf(stderr, "percentages must precede files\n");
        !           408:                                        return FALSE;
        !           409:                                }
        !           410:                                sp = files[i];
        !           411:                        }
        !           412:                }
        !           413:                if (strcmp(sp, "all") == 0)
        !           414:                        sp = FORTDIR;
        !           415:                if (!add_file(percent, sp, NULL, &File_list, &File_tail, NULL))
        !           416:                        return FALSE;
        !           417:        }
        !           418:        return TRUE;
        !           419: }
        !           420: 
        !           421: /*
        !           422:  * add_file:
        !           423:  *     Add a file to the file list.
        !           424:  */
        !           425: add_file(percent, file, dir, head, tail, parent)
        !           426: int            percent;
        !           427: register char  *file;
        !           428: char           *dir;
        !           429: FILEDESC       **head, **tail;
        !           430: FILEDESC       *parent;
        !           431: {
        !           432:        register FILEDESC       *fp;
        !           433:        register int            fd;
        !           434:        register char           *path, *offensive;
        !           435:        register bool           was_malloc;
        !           436:        register bool           isdir;
        !           437: 
        !           438:        if (dir == NULL) {
        !           439:                path = file;
        !           440:                was_malloc = FALSE;
        !           441:        }
        !           442:        else {
        !           443:                path = do_malloc((unsigned int) (strlen(dir) + strlen(file) + 2));
        !           444:                (void) strcat(strcat(strcpy(path, dir), "/"), file);
        !           445:                was_malloc = TRUE;
        !           446:        }
        !           447:        if ((isdir = is_dir(path)) && parent != NULL) {
        !           448:                if (was_malloc)
        !           449:                        free(path);
        !           450:                return FALSE;   /* don't recurse */
        !           451:        }
        !           452:        offensive = NULL;
        !           453:        if (!isdir && parent == NULL && (All_forts || Offend) &&
        !           454:            !is_off_name(path)) {
        !           455:                offensive = off_name(path);
        !           456:                was_malloc = TRUE;
        !           457:                if (Offend) {
        !           458:                        if (was_malloc)
        !           459:                                free(path);
        !           460:                        path = offensive;
        !           461:                        file = off_name(file);
        !           462:                }
        !           463:        }
        !           464: 
        !           465:        DPRINTF(1, (stderr, "adding file \"%s\"\n", path));
        !           466: over:
        !           467:        if ((fd = open(path, 0)) < 0) {
        !           468:                /*
        !           469:                 * This is a sneak.  If the user said -a, and if the
        !           470:                 * file we're given isn't a file, we check to see if
        !           471:                 * there is a -o version.  If there is, we treat it as
        !           472:                 * if *that* were the file given.  We only do this for
        !           473:                 * individual files -- if we're scanning a directory,
        !           474:                 * we'll pick up the -o file anyway.
        !           475:                 */
        !           476:                if (All_forts && offensive != NULL) {
        !           477:                        path = offensive;
        !           478:                        if (was_malloc)
        !           479:                                free(path);
        !           480:                        offensive = NULL;
        !           481:                        was_malloc = TRUE;
        !           482:                        DPRINTF(1, (stderr, "\ttrying \"%s\"\n", path));
        !           483:                        file = off_name(file);
        !           484:                        goto over;
        !           485:                }
        !           486:                if (dir == NULL && file[0] != '/')
        !           487:                        return add_file(percent, file, FORTDIR, head, tail,
        !           488:                                        parent);
        !           489:                if (parent == NULL)
        !           490:                        perror(path);
        !           491:                if (was_malloc)
        !           492:                        free(path);
        !           493:                return FALSE;
        !           494:        }
        !           495: 
        !           496:        DPRINTF(2, (stderr, "path = \"%s\"\n", path));
        !           497: 
        !           498:        fp = new_fp();
        !           499:        fp->fd = fd;
        !           500:        fp->percent = percent;
        !           501:        fp->name = file;
        !           502:        fp->path = path;
        !           503:        fp->parent = parent;
        !           504: 
        !           505:        if ((isdir && !add_dir(fp)) ||
        !           506:            (!isdir &&
        !           507:             !is_fortfile(path, &fp->datfile, &fp->posfile, (parent != NULL))))
        !           508:        {
        !           509:                if (parent == NULL)
        !           510:                        fprintf(stderr,
        !           511:                                "fortune:%s not a fortune file or directory\n",
        !           512:                                path);
        !           513:                free((char *) fp);
        !           514:                if (was_malloc)
        !           515:                        free(path);
        !           516:                do_free(fp->datfile);
        !           517:                do_free(fp->posfile);
        !           518:                do_free(offensive);
        !           519:                return FALSE;
        !           520:        }
        !           521:        /*
        !           522:         * If the user said -a, we need to make this node a pointer to
        !           523:         * both files, if there are two.  We don't need to do this if
        !           524:         * we are scanning a directory, since the scan will pick up the
        !           525:         * -o file anyway.
        !           526:         */
        !           527:        if (All_forts && parent == NULL && !is_off_name(path))
        !           528:                all_forts(fp, offensive);
        !           529:        if (*head == NULL)
        !           530:                *head = *tail = fp;
        !           531:        else if (fp->percent == NO_PROB) {
        !           532:                (*tail)->next = fp;
        !           533:                fp->prev = *tail;
        !           534:                *tail = fp;
        !           535:        }
        !           536:        else {
        !           537:                (*head)->prev = fp;
        !           538:                fp->next = *head;
        !           539:                *head = fp;
        !           540:        }
        !           541: #ifdef OK_TO_WRITE_DISK
        !           542:        fp->was_pos_file = (access(fp->posfile, W_OK) >= 0);
        !           543: #endif /* OK_TO_WRITE_DISK */
        !           544: 
        !           545:        return TRUE;
        !           546: }
        !           547: 
        !           548: /*
        !           549:  * new_fp:
        !           550:  *     Return a pointer to an initialized new FILEDESC.
        !           551:  */
        !           552: FILEDESC *
        !           553: new_fp()
        !           554: {
        !           555:        register FILEDESC       *fp;
        !           556: 
        !           557:        fp = (FILEDESC *) do_malloc(sizeof *fp);
        !           558:        fp->datfd = -1;
        !           559:        fp->pos = POS_UNKNOWN;
        !           560:        fp->inf = NULL;
        !           561:        fp->fd = -1;
        !           562:        fp->percent = NO_PROB;
        !           563:        fp->read_tbl = FALSE;
        !           564:        fp->next = NULL;
        !           565:        fp->prev = NULL;
        !           566:        fp->child = NULL;
        !           567:        fp->parent = NULL;
        !           568:        fp->datfile = NULL;
        !           569:        fp->posfile = NULL;
        !           570:        return fp;
        !           571: }
        !           572: 
        !           573: /*
        !           574:  * off_name:
        !           575:  *     Return a pointer to the offensive version of a file of this name.
        !           576:  */
        !           577: char *
        !           578: off_name(file)
        !           579: char   *file;
        !           580: {
        !           581:        char    *new;
        !           582: 
        !           583:        new = copy(file, (unsigned int) (strlen(file) + 2));
        !           584:        return strcat(new, "-o");
        !           585: }
        !           586: 
        !           587: /*
        !           588:  * is_off_name:
        !           589:  *     Is the file an offensive-style name?
        !           590:  */
        !           591: is_off_name(file)
        !           592: char   *file;
        !           593: {
        !           594:        int     len;
        !           595: 
        !           596:        len = strlen(file);
        !           597:        return (len >= 3 && file[len - 2] == '-' && file[len - 1] == 'o');
        !           598: }
        !           599: 
        !           600: /*
        !           601:  * all_forts:
        !           602:  *     Modify a FILEDESC element to be the parent of two children if
        !           603:  *     there are two children to be a parent of.
        !           604:  */
        !           605: all_forts(fp, offensive)
        !           606: register FILEDESC      *fp;
        !           607: char                   *offensive;
        !           608: {
        !           609:        register char           *sp;
        !           610:        register FILEDESC       *scene, *obscene;
        !           611:        register int            fd;
        !           612:        auto char               *datfile, *posfile;
        !           613: 
        !           614:        if (fp->child != NULL)  /* this is a directory, not a file */
        !           615:                return;
        !           616:        if (!is_fortfile(offensive, &datfile, &posfile, FALSE))
        !           617:                return;
        !           618:        if ((fd = open(offensive, 0)) < 0)
        !           619:                return;
        !           620:        DPRINTF(1, (stderr, "adding \"%s\" because of -a\n", offensive));
        !           621:        scene = new_fp();
        !           622:        obscene = new_fp();
        !           623:        *scene = *fp;
        !           624: 
        !           625:        fp->num_children = 2;
        !           626:        fp->child = scene;
        !           627:        scene->next = obscene;
        !           628:        obscene->next = NULL;
        !           629:        scene->child = obscene->child = NULL;
        !           630:        scene->parent = obscene->parent = fp;
        !           631: 
        !           632:        fp->fd = -1;
        !           633:        scene->percent = obscene->percent = NO_PROB;
        !           634: 
        !           635:        obscene->fd = fd;
        !           636:        obscene->inf = NULL;
        !           637:        obscene->path = offensive;
        !           638:        if ((sp = rindex(offensive, '/')) == NULL)
        !           639:                obscene->name = offensive;
        !           640:        else
        !           641:                obscene->name = ++sp;
        !           642:        obscene->datfile = datfile;
        !           643:        obscene->posfile = posfile;
        !           644:        obscene->read_tbl = FALSE;
        !           645: #ifdef OK_TO_WRITE_DISK
        !           646:        obscene->was_pos_file = (access(obscene->posfile, W_OK) >= 0);
        !           647: #endif /* OK_TO_WRITE_DISK */
        !           648: }
        !           649: 
        !           650: /*
        !           651:  * add_dir:
        !           652:  *     Add the contents of an entire directory.
        !           653:  */
        !           654: add_dir(fp)
        !           655: register FILEDESC      *fp;
        !           656: {
        !           657:        register DIR            *dir;
        !           658: #ifdef SYSV
        !           659:        register struct dirent  *dirent;        /* NIH, of course! */
        !           660: #else
        !           661:        register struct direct  *dirent;
        !           662: #endif
        !           663:        auto FILEDESC           *tailp;
        !           664:        auto char               *name;
        !           665: 
        !           666:        (void) close(fp->fd);
        !           667:        fp->fd = -1;
        !           668:        if ((dir = opendir(fp->path)) == NULL) {
        !           669:                perror(fp->path);
        !           670:                return FALSE;
        !           671:        }
        !           672:        tailp = NULL;
        !           673:        DPRINTF(1, (stderr, "adding dir \"%s\"\n", fp->path));
        !           674:        fp->num_children = 0;
        !           675:        while ((dirent = readdir(dir)) != NULL) {
        !           676:                if (dirent->d_namlen == 0)
        !           677:                        continue;
        !           678:                name = copy(dirent->d_name, dirent->d_namlen);
        !           679:                if (add_file(NO_PROB, name, fp->path, &fp->child, &tailp, fp))
        !           680:                        fp->num_children++;
        !           681:                else
        !           682:                        free(name);
        !           683:        }
        !           684:        if (fp->num_children == 0) {
        !           685:                (void) fprintf(stderr,
        !           686:                    "fortune: %s: No fortune files in directory.\n", fp->path);
        !           687:                return FALSE;
        !           688:        }
        !           689:        return TRUE;
        !           690: }
        !           691: 
        !           692: /*
        !           693:  * is_dir:
        !           694:  *     Return TRUE if the file is a directory, FALSE otherwise.
        !           695:  */
        !           696: is_dir(file)
        !           697: char   *file;
        !           698: {
        !           699:        auto struct stat        sbuf;
        !           700: 
        !           701:        if (stat(file, &sbuf) < 0)
        !           702:                return FALSE;
        !           703:        return (sbuf.st_mode & S_IFDIR);
        !           704: }
        !           705: 
        !           706: /*
        !           707:  * is_fortfile:
        !           708:  *     Return TRUE if the file is a fortune database file.  We try and
        !           709:  *     exclude files without reading them if possible to avoid
        !           710:  *     overhead.  Files which start with ".", or which have "illegal"
        !           711:  *     suffixes, as contained in suflist[], are ruled out.
        !           712:  */
        !           713: /* ARGSUSED */
        !           714: is_fortfile(file, datp, posp, check_for_offend)
        !           715: char   *file;
        !           716: char   **datp, **posp;
        !           717: int    check_for_offend;
        !           718: {
        !           719:        register int    i;
        !           720:        register char   *sp;
        !           721:        register char   *datfile;
        !           722:        static char     *suflist[] = {  /* list of "illegal" suffixes" */
        !           723:                                "dat", "pos", "c", "h", "p", "i", "f",
        !           724:                                "pas", "ftn", "ins.c", "ins,pas",
        !           725:                                "ins.ftn", "sml",
        !           726:                                NULL
        !           727:                        };
        !           728: 
        !           729:        DPRINTF(2, (stderr, "is_fortfile(%s) returns ", file));
        !           730: 
        !           731:        /*
        !           732:         * Preclude any -o files for offendable people, and any non -o
        !           733:         * files for completely offensive people.
        !           734:         */
        !           735:        if (check_for_offend && !All_forts) {
        !           736:                i = strlen(file);
        !           737:                if (Offend ^ (file[i - 2] == '-' && file[i - 1] == 'o'))
        !           738:                        return FALSE;
        !           739:        }
        !           740: 
        !           741:        if ((sp = rindex(file, '/')) == NULL)
        !           742:                sp = file;
        !           743:        else
        !           744:                sp++;
        !           745:        if (*sp == '.') {
        !           746:                DPRINTF(2, (stderr, "FALSE (file starts with '.')\n"));
        !           747:                return FALSE;
        !           748:        }
        !           749:        if ((sp = rindex(sp, '.')) != NULL) {
        !           750:                sp++;
        !           751:                for (i = 0; suflist[i] != NULL; i++)
        !           752:                        if (strcmp(sp, suflist[i]) == 0) {
        !           753:                                DPRINTF(2, (stderr, "FALSE (file has suffix \".%s\")\n", sp));
        !           754:                                return FALSE;
        !           755:                        }
        !           756:        }
        !           757: 
        !           758:        datfile = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */
        !           759:        strcat(datfile, ".dat");
        !           760:        if (access(datfile, R_OK) < 0) {
        !           761:                free(datfile);
        !           762:                DPRINTF(2, (stderr, "FALSE (no \".dat\" file)\n"));
        !           763:                return FALSE;
        !           764:        }
        !           765:        if (datp != NULL)
        !           766:                *datp = datfile;
        !           767:        else
        !           768:                free(datfile);
        !           769: #ifdef OK_TO_WRITE_DISK
        !           770:        if (posp != NULL) {
        !           771:                *posp = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */
        !           772:                (void) strcat(*posp, ".pos");
        !           773:        }
        !           774: #endif /* OK_TO_WRITE_DISK */
        !           775:        DPRINTF(2, (stderr, "TRUE\n"));
        !           776:        return TRUE;
        !           777: }
        !           778: 
        !           779: /*
        !           780:  * copy:
        !           781:  *     Return a malloc()'ed copy of the string
        !           782:  */
        !           783: char *
        !           784: copy(str, len)
        !           785: char           *str;
        !           786: unsigned int   len;
        !           787: {
        !           788:        char    *new, *sp;
        !           789: 
        !           790:        new = do_malloc(len + 1);
        !           791:        sp = new;
        !           792:        do {
        !           793:                *sp++ = *str;
        !           794:        } while (*str++);
        !           795:        return new;
        !           796: }
        !           797: 
        !           798: /*
        !           799:  * do_malloc:
        !           800:  *     Do a malloc, checking for NULL return.
        !           801:  */
        !           802: char *
        !           803: do_malloc(size)
        !           804: unsigned int   size;
        !           805: {
        !           806:        char    *new;
        !           807: 
        !           808:        if ((new = malloc(size)) == NULL) {
        !           809:                (void) fprintf(stderr, "fortune: out of memory.\n");
        !           810:                exit(1);
        !           811:        }
        !           812:        return new;
        !           813: }
        !           814: 
        !           815: /*
        !           816:  * do_free:
        !           817:  *     Free malloc'ed space, if any.
        !           818:  */
        !           819: do_free(ptr)
        !           820: char   *ptr;
        !           821: {
        !           822:        if (ptr != NULL)
        !           823:                free(ptr);
        !           824: }
        !           825: 
        !           826: /*
        !           827:  * init_prob:
        !           828:  *     Initialize the fortune probabilities.
        !           829:  */
        !           830: init_prob()
        !           831: {
        !           832:        register FILEDESC       *fp, *last;
        !           833:        register int            percent, num_noprob, frac;
        !           834: 
        !           835:        /*
        !           836:         * Distribute the residual probability (if any) across all
        !           837:         * files with unspecified probability (i.e., probability of 0)
        !           838:         * (if any).
        !           839:         */
        !           840: 
        !           841:        percent = 0;
        !           842:        num_noprob = 0;
        !           843:        for (fp = File_tail; fp != NULL; fp = fp->prev)
        !           844:                if (fp->percent == NO_PROB) {
        !           845:                        num_noprob++;
        !           846:                        if (Equal_probs)
        !           847:                                last = fp;
        !           848:                }
        !           849:                else
        !           850:                        percent += fp->percent;
        !           851:        DPRINTF(1, (stderr, "summing probabilities:%d%% with %d NO_PROB's",
        !           852:                    percent, num_noprob));
        !           853:        if (percent > 100) {
        !           854:                (void) fprintf(stderr,
        !           855:                    "fortune: probabilities sum to %d%%!\n", percent);
        !           856:                exit(1);
        !           857:        }
        !           858:        else if (percent < 100 && num_noprob == 0) {
        !           859:                (void) fprintf(stderr,
        !           860:                    "fortune: no place to put residual probability (%d%%)\n",
        !           861:                    percent);
        !           862:                exit(1);
        !           863:        }
        !           864:        else if (percent == 100 && num_noprob != 0) {
        !           865:                (void) fprintf(stderr,
        !           866:                    "fortune: no probability left to put in residual files\n");
        !           867:                exit(1);
        !           868:        }
        !           869:        percent = 100 - percent;
        !           870:        if (Equal_probs)
        !           871:                if (num_noprob != 0) {
        !           872:                        if (num_noprob > 1) {
        !           873:                                frac = percent / num_noprob;
        !           874:                                DPRINTF(1, (stderr, ", frac = %d%%", frac));
        !           875:                                for (fp = File_list; fp != last; fp = fp->next)
        !           876:                                        if (fp->percent == NO_PROB) {
        !           877:                                                fp->percent = frac;
        !           878:                                                percent -= frac;
        !           879:                                        }
        !           880:                        }
        !           881:                        last->percent = percent;
        !           882:                        DPRINTF(1, (stderr, ", residual = %d%%", percent));
        !           883:                }
        !           884:        else {
        !           885:                DPRINTF(1, (stderr,
        !           886:                            ", %d%% distributed over remaining fortunes\n",
        !           887:                            percent));
        !           888:        }
        !           889:        DPRINTF(1, (stderr, "\n"));
        !           890: 
        !           891: #ifdef DEBUG
        !           892:        if (Debug >= 1)
        !           893:                print_file_list();
        !           894: #endif
        !           895: }
        !           896: 
        !           897: /*
        !           898:  * get_fort:
        !           899:  *     Get the fortune data file's seek pointer for the next fortune.
        !           900:  */
        !           901: get_fort()
        !           902: {
        !           903:        register FILEDESC       *fp;
        !           904:        register int            choice;
        !           905:        long random();
        !           906: 
        !           907:        if (File_list->next == NULL || File_list->percent == NO_PROB)
        !           908:                fp = File_list;
        !           909:        else {
        !           910:                choice = random() % 100;
        !           911:                DPRINTF(1, (stderr, "choice = %d\n", choice));
        !           912:                for (fp = File_list; fp->percent != NO_PROB; fp = fp->next)
        !           913:                        if (choice < fp->percent)
        !           914:                                break;
        !           915:                        else {
        !           916:                                choice -= fp->percent;
        !           917:                                DPRINTF(1, (stderr,
        !           918:                                            "    skip \"%s\", %d%% (choice = %d)\n",
        !           919:                                            fp->name, fp->percent, choice));
        !           920:                        }
        !           921:                        DPRINTF(1, (stderr,
        !           922:                                    "using \"%s\", %d%% (choice = %d)\n",
        !           923:                                    fp->name, fp->percent, choice));
        !           924:        }
        !           925:        if (fp->percent != NO_PROB)
        !           926:                get_tbl(fp);
        !           927:        else {
        !           928:                if (fp->next != NULL) {
        !           929:                        sum_noprobs(fp);
        !           930:                        choice = random() % Noprob_tbl.str_numstr;
        !           931:                        DPRINTF(1, (stderr, "choice = %d (of %d) \n", choice,
        !           932:                                    Noprob_tbl.str_numstr));
        !           933:                        while (choice >= fp->tbl.str_numstr) {
        !           934:                                choice -= fp->tbl.str_numstr;
        !           935:                                fp = fp->next;
        !           936:                                DPRINTF(1, (stderr,
        !           937:                                            "    skip \"%s\", %d (choice = %d)\n",
        !           938:                                            fp->name, fp->tbl.str_numstr,
        !           939:                                            choice));
        !           940:                        }
        !           941:                        DPRINTF(1, (stderr, "using \"%s\", %d\n", fp->name,
        !           942:                                    fp->tbl.str_numstr));
        !           943:                }
        !           944:                get_tbl(fp);
        !           945:        }
        !           946:        if (fp->child != NULL) {
        !           947:                DPRINTF(1, (stderr, "picking child\n"));
        !           948:                fp = pick_child(fp);
        !           949:        }
        !           950:        Fortfile = fp;
        !           951:        get_pos(fp);
        !           952:        open_dat(fp);
        !           953:        (void) lseek(fp->datfd,
        !           954:                     (off_t) (sizeof fp->tbl + fp->pos * sizeof Seekpts[0]), 0);
        !           955:        read(fp->datfd, Seekpts, sizeof Seekpts);
        !           956:        Seekpts[0] = ntohl(Seekpts[0]);
        !           957:        Seekpts[1] = ntohl(Seekpts[1]);
        !           958: }
        !           959: 
        !           960: /*
        !           961:  * pick_child
        !           962:  *     Pick a child from a chosen parent.
        !           963:  */
        !           964: FILEDESC *
        !           965: pick_child(parent)
        !           966: FILEDESC       *parent;
        !           967: {
        !           968:        register FILEDESC       *fp;
        !           969:        register int            choice;
        !           970: 
        !           971:        if (Equal_probs) {
        !           972:                choice = random() % parent->num_children;
        !           973:                DPRINTF(1, (stderr, "    choice = %d (of %d)\n",
        !           974:                            choice, parent->num_children));
        !           975:                for (fp = parent->child; choice--; fp = fp->next)
        !           976:                        continue;
        !           977:                DPRINTF(1, (stderr, "    using %s\n", fp->name));
        !           978:                return fp;
        !           979:        }
        !           980:        else {
        !           981:                get_tbl(parent);
        !           982:                choice = random() % parent->tbl.str_numstr;
        !           983:                DPRINTF(1, (stderr, "    choice = %d (of %d)\n",
        !           984:                            choice, parent->tbl.str_numstr));
        !           985:                for (fp = parent->child; choice >= fp->tbl.str_numstr;
        !           986:                     fp = fp->next) {
        !           987:                        choice -= fp->tbl.str_numstr;
        !           988:                        DPRINTF(1, (stderr, "\tskip %s, %d (choice = %d)\n",
        !           989:                                    fp->name, fp->tbl.str_numstr, choice));
        !           990:                }
        !           991:                DPRINTF(1, (stderr, "    using %s, %d\n", fp->name,
        !           992:                            fp->tbl.str_numstr));
        !           993:                return fp;
        !           994:        }
        !           995: }
        !           996: 
        !           997: /*
        !           998:  * sum_noprobs:
        !           999:  *     Sum up all the noprob probabilities, starting with fp.
        !          1000:  */
        !          1001: sum_noprobs(fp)
        !          1002: register FILEDESC      *fp;
        !          1003: {
        !          1004:        static bool     did_noprobs = FALSE;
        !          1005: 
        !          1006:        if (did_noprobs)
        !          1007:                return;
        !          1008:        zero_tbl(&Noprob_tbl);
        !          1009:        while (fp != NULL) {
        !          1010:                get_tbl(fp);
        !          1011:                sum_tbl(&Noprob_tbl, &fp->tbl);
        !          1012:                fp = fp->next;
        !          1013:        }
        !          1014:        did_noprobs = TRUE;
        !          1015: }
        !          1016: 
        !          1017: max(i, j)
        !          1018: register int   i, j;
        !          1019: {
        !          1020:        return (i >= j ? i : j);
        !          1021: }
        !          1022: 
        !          1023: /*
        !          1024:  * open_fp:
        !          1025:  *     Assocatiate a FILE * with the given FILEDESC.
        !          1026:  */
        !          1027: open_fp(fp)
        !          1028: FILEDESC       *fp;
        !          1029: {
        !          1030:        if (fp->inf == NULL && (fp->inf = fdopen(fp->fd, "r")) == NULL) {
        !          1031:                perror(fp->path);
        !          1032:                exit(1);
        !          1033:        }
        !          1034: }
        !          1035: 
        !          1036: /*
        !          1037:  * open_dat:
        !          1038:  *     Open up the dat file if we need to.
        !          1039:  */
        !          1040: open_dat(fp)
        !          1041: FILEDESC       *fp;
        !          1042: {
        !          1043:        if (fp->datfd < 0 && (fp->datfd = open(fp->datfile, 0)) < 0) {
        !          1044:                perror(fp->datfile);
        !          1045:                exit(1);
        !          1046:        }
        !          1047: }
        !          1048: 
        !          1049: /*
        !          1050:  * get_pos:
        !          1051:  *     Get the position from the pos file, if there is one.  If not,
        !          1052:  *     return a random number.
        !          1053:  */
        !          1054: get_pos(fp)
        !          1055: FILEDESC       *fp;
        !          1056: {
        !          1057: #ifdef OK_TO_WRITE_DISK
        !          1058:        int     fd;
        !          1059: #endif /* OK_TO_WRITE_DISK */
        !          1060: 
        !          1061:        assert(fp->read_tbl);
        !          1062:        if (fp->pos == POS_UNKNOWN) {
        !          1063: #ifdef OK_TO_WRITE_DISK
        !          1064:                if ((fd = open(fp->posfile, 0)) < 0 ||
        !          1065:                    read(fd, &fp->pos, sizeof fp->pos) != sizeof fp->pos)
        !          1066:                        fp->pos = random() % fp->tbl.str_numstr;
        !          1067:                else if (fp->pos >= fp->tbl.str_numstr)
        !          1068:                        fp->pos %= fp->tbl.str_numstr;
        !          1069:                if (fd >= 0)
        !          1070:                        (void) close(fd);
        !          1071: #else
        !          1072:                fp->pos = random() % fp->tbl.str_numstr;
        !          1073: #endif /* OK_TO_WRITE_DISK */
        !          1074:        }
        !          1075:        if (++(fp->pos) >= fp->tbl.str_numstr)
        !          1076:                fp->pos -= fp->tbl.str_numstr;
        !          1077:        DPRINTF(1, (stderr, "pos for %s is %d\n", fp->name, fp->pos));
        !          1078: }
        !          1079: 
        !          1080: /*
        !          1081:  * get_tbl:
        !          1082:  *     Get the tbl data file the datfile.
        !          1083:  */
        !          1084: get_tbl(fp)
        !          1085: FILEDESC       *fp;
        !          1086: {
        !          1087:        auto int                fd;
        !          1088:        register FILEDESC       *child;
        !          1089: 
        !          1090:        if (fp->read_tbl)
        !          1091:                return;
        !          1092:        if (fp->child == NULL) {
        !          1093:                if ((fd = open(fp->datfile, 0)) < 0) {
        !          1094:                        perror(fp->datfile);
        !          1095:                        exit(1);
        !          1096:                }
        !          1097:                if (read(fd, (char *) &fp->tbl, sizeof fp->tbl) != sizeof fp->tbl) {
        !          1098:                        (void)fprintf(stderr,
        !          1099:                            "fortune: %s corrupted\n", fp->path);
        !          1100:                        exit(1);
        !          1101:                }
        !          1102:                /* fp->tbl.str_version = ntohl(fp->tbl.str_version); */
        !          1103:                fp->tbl.str_numstr = ntohl(fp->tbl.str_numstr);
        !          1104:                fp->tbl.str_longlen = ntohl(fp->tbl.str_longlen);
        !          1105:                fp->tbl.str_shortlen = ntohl(fp->tbl.str_shortlen);
        !          1106:                fp->tbl.str_flags = ntohl(fp->tbl.str_flags);
        !          1107:                (void) close(fd);
        !          1108:        }
        !          1109:        else {
        !          1110:                zero_tbl(&fp->tbl);
        !          1111:                for (child = fp->child; child != NULL; child = child->next) {
        !          1112:                        get_tbl(child);
        !          1113:                        sum_tbl(&fp->tbl, &child->tbl);
        !          1114:                }
        !          1115:        }
        !          1116:        fp->read_tbl = TRUE;
        !          1117: }
        !          1118: 
        !          1119: /*
        !          1120:  * zero_tbl:
        !          1121:  *     Zero out the fields we care about in a tbl structure.
        !          1122:  */
        !          1123: zero_tbl(tp)
        !          1124: register STRFILE       *tp;
        !          1125: {
        !          1126:        tp->str_numstr = 0;
        !          1127:        tp->str_longlen = 0;
        !          1128:        tp->str_shortlen = -1;
        !          1129: }
        !          1130: 
        !          1131: /*
        !          1132:  * sum_tbl:
        !          1133:  *     Merge the tbl data of t2 into t1.
        !          1134:  */
        !          1135: sum_tbl(t1, t2)
        !          1136: register STRFILE       *t1, *t2;
        !          1137: {
        !          1138:        t1->str_numstr += t2->str_numstr;
        !          1139:        if (t1->str_longlen < t2->str_longlen)
        !          1140:                t1->str_longlen = t2->str_longlen;
        !          1141:        if (t1->str_shortlen > t2->str_shortlen)
        !          1142:                t1->str_shortlen = t2->str_shortlen;
        !          1143: }
        !          1144: 
        !          1145: #define        STR(str)        ((str) == NULL ? "NULL" : (str))
        !          1146: 
        !          1147: /*
        !          1148:  * print_file_list:
        !          1149:  *     Print out the file list
        !          1150:  */
        !          1151: print_file_list()
        !          1152: {
        !          1153:        print_list(File_list, 0);
        !          1154: }
        !          1155: 
        !          1156: /*
        !          1157:  * print_list:
        !          1158:  *     Print out the actual list, recursively.
        !          1159:  */
        !          1160: print_list(list, lev)
        !          1161: register FILEDESC      *list;
        !          1162: int                    lev;
        !          1163: {
        !          1164:        while (list != NULL) {
        !          1165:                fprintf(stderr, "%*s", lev * 4, "");
        !          1166:                if (list->percent == NO_PROB)
        !          1167:                        fprintf(stderr, "___%%");
        !          1168:                else
        !          1169:                        fprintf(stderr, "%3d%%", list->percent);
        !          1170:                fprintf(stderr, " %s", STR(list->name));
        !          1171:                DPRINTF(1, (stderr, " (%s, %s, %s)\n", STR(list->path),
        !          1172:                            STR(list->datfile), STR(list->posfile)));
        !          1173:                putc('\n', stderr);
        !          1174:                if (list->child != NULL)
        !          1175:                        print_list(list->child, lev + 1);
        !          1176:                list = list->next;
        !          1177:        }
        !          1178: }
        !          1179: 
        !          1180: #ifndef        NO_REGEX
        !          1181: /*
        !          1182:  * conv_pat:
        !          1183:  *     Convert the pattern to an ignore-case equivalent.
        !          1184:  */
        !          1185: char *
        !          1186: conv_pat(orig)
        !          1187: register char  *orig;
        !          1188: {
        !          1189:        register char           *sp;
        !          1190:        register unsigned int   cnt;
        !          1191:        register char           *new;
        !          1192: 
        !          1193:        cnt = 1;        /* allow for '\0' */
        !          1194:        for (sp = orig; *sp != '\0'; sp++)
        !          1195:                if (isalpha(*sp))
        !          1196:                        cnt += 4;
        !          1197:                else
        !          1198:                        cnt++;
        !          1199:        if ((new = malloc(cnt)) == NULL) {
        !          1200:                fprintf(stderr, "pattern too long for ignoring case\n");
        !          1201:                exit(1);
        !          1202:        }
        !          1203: 
        !          1204:        for (sp = new; *orig != '\0'; orig++) {
        !          1205:                if (islower(*orig)) {
        !          1206:                        *sp++ = '[';
        !          1207:                        *sp++ = *orig;
        !          1208:                        *sp++ = toupper(*orig);
        !          1209:                        *sp++ = ']';
        !          1210:                }
        !          1211:                else if (isupper(*orig)) {
        !          1212:                        *sp++ = '[';
        !          1213:                        *sp++ = *orig;
        !          1214:                        *sp++ = tolower(*orig);
        !          1215:                        *sp++ = ']';
        !          1216:                }
        !          1217:                else
        !          1218:                        *sp++ = *orig;
        !          1219:        }
        !          1220:        *sp = '\0';
        !          1221:        return new;
        !          1222: }
        !          1223: 
        !          1224: /*
        !          1225:  * find_matches:
        !          1226:  *     Find all the fortunes which match the pattern we've been given.
        !          1227:  */
        !          1228: find_matches()
        !          1229: {
        !          1230:        Fort_len = maxlen_in_list(File_list);
        !          1231:        DPRINTF(2, (stderr, "Maximum length is %d\n", Fort_len));
        !          1232:        /* extra length, "%\n" is appended */
        !          1233:        Fortbuf = do_malloc((unsigned int) Fort_len + 10);
        !          1234: 
        !          1235:        Found_one = FALSE;
        !          1236:        matches_in_list(File_list);
        !          1237:        return Found_one;
        !          1238:        /* NOTREACHED */
        !          1239: }
        !          1240: 
        !          1241: /*
        !          1242:  * maxlen_in_list
        !          1243:  *     Return the maximum fortune len in the file list.
        !          1244:  */
        !          1245: maxlen_in_list(list)
        !          1246: FILEDESC       *list;
        !          1247: {
        !          1248:        register FILEDESC       *fp;
        !          1249:        register int            len, maxlen;
        !          1250: 
        !          1251:        maxlen = 0;
        !          1252:        for (fp = list; fp != NULL; fp = fp->next) {
        !          1253:                if (fp->child != NULL) {
        !          1254:                        if ((len = maxlen_in_list(fp->child)) > maxlen)
        !          1255:                                maxlen = len;
        !          1256:                }
        !          1257:                else {
        !          1258:                        get_tbl(fp);
        !          1259:                        if (fp->tbl.str_longlen > maxlen)
        !          1260:                                maxlen = fp->tbl.str_longlen;
        !          1261:                }
        !          1262:        }
        !          1263:        return maxlen;
        !          1264: }
        !          1265: 
        !          1266: /*
        !          1267:  * matches_in_list
        !          1268:  *     Print out the matches from the files in the list.
        !          1269:  */
        !          1270: matches_in_list(list)
        !          1271: FILEDESC       *list;
        !          1272: {
        !          1273:        register char           *sp;
        !          1274:        register FILEDESC       *fp;
        !          1275:        int                     in_file;
        !          1276: 
        !          1277:        for (fp = list; fp != NULL; fp = fp->next) {
        !          1278:                if (fp->child != NULL) {
        !          1279:                        matches_in_list(fp->child);
        !          1280:                        continue;
        !          1281:                }
        !          1282:                DPRINTF(1, (stderr, "searching in %s\n", fp->path));
        !          1283:                open_fp(fp);
        !          1284:                sp = Fortbuf;
        !          1285:                in_file = FALSE;
        !          1286:                while (fgets(sp, Fort_len, fp->inf) != NULL)
        !          1287:                        if (!STR_ENDSTRING(sp, fp->tbl))
        !          1288:                                sp += strlen(sp);
        !          1289:                        else {
        !          1290:                                *sp = '\0';
        !          1291:                                if (RE_EXEC(Fortbuf)) {
        !          1292:                                        printf("%c%c", fp->tbl.str_delim,
        !          1293:                                            fp->tbl.str_delim);
        !          1294:                                        if (!in_file) {
        !          1295:                                                printf(" (%s)", fp->name);
        !          1296:                                                Found_one = TRUE;
        !          1297:                                                in_file = TRUE;
        !          1298:                                        }
        !          1299:                                        putchar('\n');
        !          1300:                                        (void) fwrite(Fortbuf, 1, (sp - Fortbuf), stdout);
        !          1301:                                }
        !          1302:                                sp = Fortbuf;
        !          1303:                        }
        !          1304:        }
        !          1305: }
        !          1306: # endif        /* NO_REGEX */
        !          1307: 
        !          1308: usage()
        !          1309: {
        !          1310:        (void) fprintf(stderr, "fortune [-a");
        !          1311: #ifdef DEBUG
        !          1312:        (void) fprintf(stderr, "D");
        !          1313: #endif /* DEBUG */
        !          1314:        (void) fprintf(stderr, "f");
        !          1315: #ifndef        NO_REGEX
        !          1316:        (void) fprintf(stderr, "i");
        !          1317: #endif /* NO_REGEX */
        !          1318:        (void) fprintf(stderr, "losw]");
        !          1319: #ifndef        NO_REGEX
        !          1320:        (void) fprintf(stderr, " [-m pattern]");
        !          1321: #endif /* NO_REGEX */
        !          1322:        (void) fprintf(stderr, "[ [#%%] file/directory/all]\n");
        !          1323:        exit(1);
        !          1324: }

unix.superglobalmegacorp.com

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