2 * Copyright (c) 1986, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 /* $FreeBSD: src/games/fortune/fortune/fortune.c,v 1.18.2.1 2001/07/02 00:35:27 dd Exp $ */
39 static const char copyright[] =
40 "@(#) Copyright (c) 1986, 1993\n\
41 The Regents of the University of California. All rights reserved.\n";
46 static const char sccsid[] = "@(#)fortune.c 8.1 (Berkeley) 5/31/93";
48 static const char rcsid[] =
49 "$FreeBSD: src/games/fortune/fortune/fortune.c,v 1.18.2.1 2001/07/02 00:35:27 dd Exp $";
52 # include <sys/param.h>
53 # include <sys/stat.h>
66 # include "pathnames.h"
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 */
76 # define POS_UNKNOWN ((long) -1) /* pos for file unknown */
77 # define NO_PROB (-1) /* no prob specified for file */
80 # define DPRINTF(l,x) { if (Debug >= l) fprintf x; }
94 char *datfile, *posfile;
99 struct fd *child, *parent;
100 struct fd *next, *prev;
103 bool Found_one; /* did we find a match? */
104 bool Find_files = FALSE; /* just find a list of proper fortune files */
105 bool Fortunes_only = FALSE; /* check only "fortunes" files */
106 bool Wait = FALSE; /* wait desired after fortune */
107 bool Short_only = FALSE; /* short fortune desired */
108 bool Long_only = FALSE; /* long fortune desired */
109 bool Offend = FALSE; /* offensive fortunes only */
110 bool All_forts = FALSE; /* any fortune allowed */
111 bool Equal_probs = FALSE; /* scatter un-allocted prob equally */
113 bool Match = FALSE; /* dump fortunes matching a pattern */
116 bool Debug = FALSE; /* print debug messages */
119 char *Fortbuf = NULL; /* fortune buffer for -m */
123 long Seekpts[2]; /* seek pointers to fortunes */
125 FILEDESC *File_list = NULL, /* Head of file list */
126 *File_tail = NULL; /* Tail of file list */
127 FILEDESC *Fortfile; /* Fortune file to use */
129 STRFILE Noprob_tbl; /* sum of data for all no prob files */
131 int add_dir __P((FILEDESC *));
132 int add_file __P((int,
133 char *, char *, FILEDESC **, FILEDESC **, FILEDESC *));
134 void all_forts __P((FILEDESC *, char *));
135 char *copy __P((char *, u_int));
136 void display __P((FILEDESC *));
137 void do_free __P((void *));
138 void *do_malloc __P((u_int));
139 int form_file_list __P((char **, int));
140 int fortlen __P((void));
141 void get_fort __P((void));
142 void get_pos __P((FILEDESC *));
143 void get_tbl __P((FILEDESC *));
144 void getargs __P((int, char *[]));
145 void init_prob __P((void));
146 int is_dir __P((char *));
147 int is_fortfile __P((char *, char **, char **, int));
148 int is_off_name __P((char *));
149 int max __P((int, int));
152 char *off_name __P((char *));
153 void open_dat __P((FILEDESC *));
154 void open_fp __P((FILEDESC *));
156 pick_child __P((FILEDESC *));
157 void print_file_list __P((void));
158 void print_list __P((FILEDESC *, int));
159 void sum_noprobs __P((FILEDESC *));
160 void sum_tbl __P((STRFILE *, STRFILE *));
161 void usage __P((void));
162 void zero_tbl __P((STRFILE *));
165 char *conv_pat __P((char *));
166 int find_matches __P((void));
167 void matches_in_list __P((FILEDESC *));
168 int maxlen_in_list __P((FILEDESC *));
173 # define RE_COMP(p) (Re_pat = regcmp(p, NULL))
174 # define BAD_COMP(f) ((f) == NULL)
175 # define RE_EXEC(p) regex(Re_pat, (p))
179 char *regcmp(), *regex();
181 # define RE_COMP(p) (p = re_comp(p))
182 # define BAD_COMP(f) ((f) != NULL)
183 # define RE_EXEC(p) re_exec(p)
193 #ifdef OK_TO_WRITE_DISK
195 #endif /* OK_TO_WRITE_DISK */
197 (void) setlocale(LC_ALL, "");
203 exit(find_matches() != 0);
210 } while ((Short_only && fortlen() > SLEN) ||
211 (Long_only && fortlen() <= SLEN));
215 #ifdef OK_TO_WRITE_DISK
216 if ((fd = creat(Fortfile->posfile, 0666)) < 0) {
217 perror(Fortfile->posfile);
222 * if we can, we exclusive lock, but since it isn't very
223 * important, we just punt if we don't have easy locking
226 (void) flock(fd, LOCK_EX);
228 write(fd, (char *) &Fortfile->pos, sizeof Fortfile->pos);
229 if (!Fortfile->was_pos_file)
230 (void) chmod(Fortfile->path, 0666);
232 (void) flock(fd, LOCK_UN);
234 #endif /* OK_TO_WRITE_DISK */
238 sleep((unsigned int) max(Fort_len / CPERS, MINW));
253 (void) fseek(fp->inf, Seekpts[0], 0);
254 for (Fort_len = 0; fgets(line, sizeof line, fp->inf) != NULL &&
255 !STR_ENDSTRING(line, fp->tbl); Fort_len++) {
256 if (fp->tbl.str_flags & STR_ROTATED)
257 for (p = line; (ch = *p) != '\0'; ++p) {
260 *p = 'A' + (ch - 'A' + 13) % 26;
261 else if (islower(ch))
262 *p = 'a' + (ch - 'a' + 13) % 26;
265 if (fp->tbl.str_flags & STR_COMMENTS
266 && line[0] == fp->tbl.str_delim
267 && line[1] == fp->tbl.str_delim)
271 (void) fflush(stdout);
276 * Return the length of the fortune.
284 if (!(Fortfile->tbl.str_flags & (STR_RANDOM | STR_ORDERED)))
285 nchar = (Seekpts[1] - Seekpts[0] <= SLEN);
288 (void) fseek(Fortfile->inf, Seekpts[0], 0);
290 while (fgets(line, sizeof line, Fortfile->inf) != NULL &&
291 !STR_ENDSTRING(line, Fortfile->tbl))
292 nchar += strlen(line);
299 * This routine evaluates the arguments on the command line
309 # endif /* NO_REGEX */
317 # endif /* NO_REGEX */
320 while ((ch = getopt(argc, argv, "aDefilm:osw")) != -1)
322 while ((ch = getopt(argc, argv, "aefilm:osw")) != -1)
325 case 'a': /* any fortune */
334 Equal_probs++; /* scatter un-allocted prob equally */
336 case 'f': /* find fortune files */
339 case 'l': /* long ones only */
343 case 'o': /* offensive ones only */
346 case 's': /* short ones only */
350 case 'w': /* give time to read */
354 case 'i': /* case-insensitive match */
355 case 'm': /* dump out the fortunes */
356 (void) fprintf(stderr,
357 "fortune: can't match fortunes on this system (Sorry)\n");
359 # else /* NO_REGEX */
360 case 'm': /* dump out the fortunes */
364 case 'i': /* case-insensitive match */
367 # endif /* NO_REGEX */
375 if (!form_file_list(argv, argc))
376 exit(1); /* errors printed through form_file_list() */
390 if (BAD_COMP(RE_COMP(pat))) {
392 fprintf(stderr, "%s\n", pat);
394 fprintf(stderr, "bad pattern: %s\n", pat);
398 # endif /* NO_REGEX */
403 * Form the file list from the file specifications.
406 form_file_list(files, file_cnt)
415 Fortunes_only = TRUE;
416 i = add_file(NO_PROB, FORTDIR, NULL, &File_list,
418 Fortunes_only = FALSE;
421 return add_file(NO_PROB, "fortunes", FORTDIR,
422 &File_list, &File_tail, NULL);
424 for (i = 0; i < file_cnt; i++) {
426 if (!isdigit((unsigned char)files[i][0]))
430 for (sp = files[i]; isdigit((unsigned char)*sp); sp++)
431 percent = percent * 10 + *sp - '0';
433 fprintf(stderr, "percentages must be <= 100\n");
437 fprintf(stderr, "percentages must be integers\n");
441 * If the number isn't followed by a '%', then
442 * it was not a percentage, just the first part
443 * of a file name which starts with digits.
449 else if (*++sp == '\0') {
450 if (++i >= file_cnt) {
451 fprintf(stderr, "percentages must precede files\n");
457 if (strcmp(sp, "all") == 0)
459 if (!add_file(percent, sp, NULL, &File_list, &File_tail, NULL))
467 * Add a file to the file list.
470 add_file(percent, file, dir, head, tail, parent)
474 FILEDESC **head, **tail;
479 char *path, *offensive;
488 path = do_malloc((unsigned int) (strlen(dir) + strlen(file) + 2));
489 (void) strcat(strcat(strcpy(path, dir), "/"), file);
492 if ((isdir = is_dir(path)) && parent != NULL) {
495 return FALSE; /* don't recurse */
498 if (!isdir && parent == NULL && (All_forts || Offend) &&
499 !is_off_name(path)) {
500 offensive = off_name(path);
507 DPRINTF(1, (stderr, "\ttrying \"%s\"\n", path));
508 file = off_name(file);
512 DPRINTF(1, (stderr, "adding file \"%s\"\n", path));
514 if ((fd = open(path, 0)) < 0) {
516 * This is a sneak. If the user said -a, and if the
517 * file we're given isn't a file, we check to see if
518 * there is a -o version. If there is, we treat it as
519 * if *that* were the file given. We only do this for
520 * individual files -- if we're scanning a directory,
521 * we'll pick up the -o file anyway.
523 if (All_forts && offensive != NULL) {
529 DPRINTF(1, (stderr, "\ttrying \"%s\"\n", path));
530 file = off_name(file);
533 if (dir == NULL && file[0] != '/')
534 return add_file(percent, file, FORTDIR, head, tail,
543 DPRINTF(2, (stderr, "path = \"%s\"\n", path));
547 fp->percent = percent;
552 if ((isdir && !add_dir(fp)) ||
554 !is_fortfile(path, &fp->datfile, &fp->posfile, (parent != NULL))))
558 "fortune:%s not a fortune file or directory\n",
562 do_free(fp->datfile);
563 do_free(fp->posfile);
569 * If the user said -a, we need to make this node a pointer to
570 * both files, if there are two. We don't need to do this if
571 * we are scanning a directory, since the scan will pick up the
574 if (All_forts && parent == NULL && !is_off_name(path))
575 all_forts(fp, offensive);
578 else if (fp->percent == NO_PROB) {
588 #ifdef OK_TO_WRITE_DISK
589 fp->was_pos_file = (access(fp->posfile, W_OK) >= 0);
590 #endif /* OK_TO_WRITE_DISK */
597 * Return a pointer to an initialized new FILEDESC.
604 fp = (FILEDESC *) do_malloc(sizeof *fp);
606 fp->pos = POS_UNKNOWN;
609 fp->percent = NO_PROB;
610 fp->read_tbl = FALSE;
622 * Return a pointer to the offensive version of a file of this name.
630 new = copy(file, (unsigned int) (strlen(file) + 2));
631 return strcat(new, "-o");
636 * Is the file an offensive-style name?
645 return (len >= 3 && file[len - 2] == '-' && file[len - 1] == 'o');
650 * Modify a FILEDESC element to be the parent of two children if
651 * there are two children to be a parent of.
654 all_forts(fp, offensive)
659 FILEDESC *scene, *obscene;
661 auto char *datfile, *posfile;
663 if (fp->child != NULL) /* this is a directory, not a file */
665 if (!is_fortfile(offensive, &datfile, &posfile, FALSE))
667 if ((fd = open(offensive, 0)) < 0)
669 DPRINTF(1, (stderr, "adding \"%s\" because of -a\n", offensive));
674 fp->num_children = 2;
676 scene->next = obscene;
677 obscene->next = NULL;
678 scene->child = obscene->child = NULL;
679 scene->parent = obscene->parent = fp;
682 scene->percent = obscene->percent = NO_PROB;
686 obscene->path = offensive;
687 if ((sp = rindex(offensive, '/')) == NULL)
688 obscene->name = offensive;
690 obscene->name = ++sp;
691 obscene->datfile = datfile;
692 obscene->posfile = posfile;
693 obscene->read_tbl = FALSE;
694 #ifdef OK_TO_WRITE_DISK
695 obscene->was_pos_file = (access(obscene->posfile, W_OK) >= 0);
696 #endif /* OK_TO_WRITE_DISK */
701 * Add the contents of an entire directory.
708 struct dirent *dirent;
709 auto FILEDESC *tailp;
712 (void) close(fp->fd);
714 if ((dir = opendir(fp->path)) == NULL) {
719 DPRINTF(1, (stderr, "adding dir \"%s\"\n", fp->path));
720 fp->num_children = 0;
721 while ((dirent = readdir(dir)) != NULL) {
722 if (dirent->d_namlen == 0)
724 name = copy(dirent->d_name, dirent->d_namlen);
725 if (add_file(NO_PROB, name, fp->path, &fp->child, &tailp, fp))
730 if (fp->num_children == 0) {
731 (void) fprintf(stderr,
732 "fortune: %s: No fortune files in directory.\n", fp->path);
740 * Return TRUE if the file is a directory, FALSE otherwise.
746 auto struct stat sbuf;
748 if (stat(file, &sbuf) < 0)
750 return (sbuf.st_mode & S_IFDIR);
755 * Return TRUE if the file is a fortune database file. We try and
756 * exclude files without reading them if possible to avoid
757 * overhead. Files which start with ".", or which have "illegal"
758 * suffixes, as contained in suflist[], are ruled out.
762 is_fortfile(file, datp, posp, check_for_offend)
763 char *file, **datp, **posp;
764 int check_for_offend;
769 static char *suflist[] = { /* list of "illegal" suffixes" */
770 "dat", "pos", "c", "h", "p", "i", "f",
771 "pas", "ftn", "ins.c", "ins,pas",
776 DPRINTF(2, (stderr, "is_fortfile(%s) returns ", file));
779 * Preclude any -o files for offendable people, and any non -o
780 * files for completely offensive people.
782 if (check_for_offend && !All_forts) {
784 if (Offend ^ (file[i - 2] == '-' && file[i - 1] == 'o')) {
785 DPRINTF(2, (stderr, "FALSE (offending file)\n"));
790 if ((sp = rindex(file, '/')) == NULL)
795 DPRINTF(2, (stderr, "FALSE (file starts with '.')\n"));
798 if (Fortunes_only && strncmp(sp, "fortunes", 8) != 0) {
799 DPRINTF(2, (stderr, "FALSE (check fortunes only)\n"));
802 if ((sp = rindex(sp, '.')) != NULL) {
804 for (i = 0; suflist[i] != NULL; i++)
805 if (strcmp(sp, suflist[i]) == 0) {
806 DPRINTF(2, (stderr, "FALSE (file has suffix \".%s\")\n", sp));
811 datfile = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */
812 strcat(datfile, ".dat");
813 if (access(datfile, R_OK) < 0) {
814 DPRINTF(2, (stderr, "FALSE (no readable \".dat\" file)\n"));
817 DPRINTF(0, (stderr, "Warning: file \"%s\" unreadable\n", datfile));
827 #ifdef OK_TO_WRITE_DISK
828 *posp = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */
829 (void) strcat(*posp, ".pos");
832 #endif /* OK_TO_WRITE_DISK */
834 DPRINTF(2, (stderr, "TRUE\n"));
840 * Return a malloc()'ed copy of the string
849 new = do_malloc(len + 1);
859 * Do a malloc, checking for NULL return.
867 if ((new = malloc(size)) == NULL) {
868 (void) fprintf(stderr, "fortune: out of memory.\n");
876 * Free malloc'ed space, if any.
888 * Initialize the fortune probabilities.
893 FILEDESC *fp, *last = NULL;
894 int percent, num_noprob, frac;
897 * Distribute the residual probability (if any) across all
898 * files with unspecified probability (i.e., probability of 0)
904 for (fp = File_tail; fp != NULL; fp = fp->prev)
905 if (fp->percent == NO_PROB) {
911 percent += fp->percent;
912 DPRINTF(1, (stderr, "summing probabilities:%d%% with %d NO_PROB's",
913 percent, num_noprob));
915 (void) fprintf(stderr,
916 "fortune: probabilities sum to %d%% > 100%%!\n", percent);
919 else if (percent < 100 && num_noprob == 0) {
920 (void) fprintf(stderr,
921 "fortune: no place to put residual probability (%d%% < 100%%)\n",
925 else if (percent == 100 && num_noprob != 0) {
926 (void) fprintf(stderr,
927 "fortune: no probability left to put in residual files (100%%)\n");
930 percent = 100 - percent;
932 if (num_noprob != 0) {
933 if (num_noprob > 1) {
934 frac = percent / num_noprob;
935 DPRINTF(1, (stderr, ", frac = %d%%", frac));
936 for (fp = File_list; fp != last; fp = fp->next)
937 if (fp->percent == NO_PROB) {
942 last->percent = percent;
943 DPRINTF(1, (stderr, ", residual = %d%%", percent));
947 ", %d%% distributed over remaining fortunes\n",
950 DPRINTF(1, (stderr, "\n"));
960 * Get the fortune data file's seek pointer for the next fortune.
968 if (File_list->next == NULL || File_list->percent == NO_PROB)
971 choice = random() % 100;
972 DPRINTF(1, (stderr, "choice = %d\n", choice));
973 for (fp = File_list; fp->percent != NO_PROB; fp = fp->next)
974 if (choice < fp->percent)
977 choice -= fp->percent;
979 " skip \"%s\", %d%% (choice = %d)\n",
980 fp->name, fp->percent, choice));
983 "using \"%s\", %d%% (choice = %d)\n",
984 fp->name, fp->percent, choice));
986 if (fp->percent != NO_PROB)
989 if (fp->next != NULL) {
991 choice = random() % Noprob_tbl.str_numstr;
992 DPRINTF(1, (stderr, "choice = %d (of %ld) \n", choice,
993 Noprob_tbl.str_numstr));
994 while (choice >= fp->tbl.str_numstr) {
995 choice -= fp->tbl.str_numstr;
998 " skip \"%s\", %ld (choice = %d)\n",
999 fp->name, fp->tbl.str_numstr,
1002 DPRINTF(1, (stderr, "using \"%s\", %ld\n", fp->name,
1003 fp->tbl.str_numstr));
1007 if (fp->child != NULL) {
1008 DPRINTF(1, (stderr, "picking child\n"));
1009 fp = pick_child(fp);
1014 (void) lseek(fp->datfd,
1015 (off_t) (sizeof fp->tbl + fp->pos * sizeof Seekpts[0]), 0);
1016 read(fp->datfd, Seekpts, sizeof Seekpts);
1017 Seekpts[0] = ntohl(Seekpts[0]);
1018 Seekpts[1] = ntohl(Seekpts[1]);
1023 * Pick a child from a chosen parent.
1033 choice = random() % parent->num_children;
1034 DPRINTF(1, (stderr, " choice = %d (of %d)\n",
1035 choice, parent->num_children));
1036 for (fp = parent->child; choice--; fp = fp->next)
1038 DPRINTF(1, (stderr, " using %s\n", fp->name));
1043 choice = random() % parent->tbl.str_numstr;
1044 DPRINTF(1, (stderr, " choice = %d (of %ld)\n",
1045 choice, parent->tbl.str_numstr));
1046 for (fp = parent->child; choice >= fp->tbl.str_numstr;
1048 choice -= fp->tbl.str_numstr;
1049 DPRINTF(1, (stderr, "\tskip %s, %ld (choice = %d)\n",
1050 fp->name, fp->tbl.str_numstr, choice));
1052 DPRINTF(1, (stderr, " using %s, %ld\n", fp->name,
1053 fp->tbl.str_numstr));
1060 * Sum up all the noprob probabilities, starting with fp.
1066 static bool did_noprobs = FALSE;
1070 zero_tbl(&Noprob_tbl);
1071 while (fp != NULL) {
1073 sum_tbl(&Noprob_tbl, &fp->tbl);
1083 return (i >= j ? i : j);
1088 * Assocatiate a FILE * with the given FILEDESC.
1094 if (fp->inf == NULL && (fp->inf = fdopen(fp->fd, "r")) == NULL) {
1102 * Open up the dat file if we need to.
1108 if (fp->datfd < 0 && (fp->datfd = open(fp->datfile, 0)) < 0) {
1109 perror(fp->datfile);
1116 * Get the position from the pos file, if there is one. If not,
1117 * return a random number.
1123 #ifdef OK_TO_WRITE_DISK
1125 #endif /* OK_TO_WRITE_DISK */
1127 assert(fp->read_tbl);
1128 if (fp->pos == POS_UNKNOWN) {
1129 #ifdef OK_TO_WRITE_DISK
1130 if ((fd = open(fp->posfile, 0)) < 0 ||
1131 read(fd, &fp->pos, sizeof fp->pos) != sizeof fp->pos)
1132 fp->pos = random() % fp->tbl.str_numstr;
1133 else if (fp->pos >= fp->tbl.str_numstr)
1134 fp->pos %= fp->tbl.str_numstr;
1138 fp->pos = random() % fp->tbl.str_numstr;
1139 #endif /* OK_TO_WRITE_DISK */
1141 if (++(fp->pos) >= fp->tbl.str_numstr)
1142 fp->pos -= fp->tbl.str_numstr;
1143 DPRINTF(1, (stderr, "pos for %s is %ld\n", fp->name, fp->pos));
1148 * Get the tbl data file the datfile.
1159 if (fp->child == NULL) {
1160 if ((fd = open(fp->datfile, 0)) < 0) {
1161 perror(fp->datfile);
1164 if (read(fd, (char *) &fp->tbl, sizeof fp->tbl) != sizeof fp->tbl) {
1165 (void)fprintf(stderr,
1166 "fortune: %s corrupted\n", fp->path);
1169 /* fp->tbl.str_version = ntohl(fp->tbl.str_version); */
1170 fp->tbl.str_numstr = ntohl(fp->tbl.str_numstr);
1171 fp->tbl.str_longlen = ntohl(fp->tbl.str_longlen);
1172 fp->tbl.str_shortlen = ntohl(fp->tbl.str_shortlen);
1173 fp->tbl.str_flags = ntohl(fp->tbl.str_flags);
1178 for (child = fp->child; child != NULL; child = child->next) {
1180 sum_tbl(&fp->tbl, &child->tbl);
1183 fp->read_tbl = TRUE;
1188 * Zero out the fields we care about in a tbl structure.
1195 tp->str_longlen = 0;
1196 tp->str_shortlen = ~((unsigned long)0);
1201 * Merge the tbl data of t2 into t1.
1207 t1->str_numstr += t2->str_numstr;
1208 if (t1->str_longlen < t2->str_longlen)
1209 t1->str_longlen = t2->str_longlen;
1210 if (t1->str_shortlen > t2->str_shortlen)
1211 t1->str_shortlen = t2->str_shortlen;
1214 #define STR(str) ((str) == NULL ? "NULL" : (str))
1218 * Print out the file list
1223 print_list(File_list, 0);
1228 * Print out the actual list, recursively.
1231 print_list(list, lev)
1235 while (list != NULL) {
1236 fprintf(stderr, "%*s", lev * 4, "");
1237 if (list->percent == NO_PROB)
1238 fprintf(stderr, "___%%");
1240 fprintf(stderr, "%3d%%", list->percent);
1241 fprintf(stderr, " %s", STR(list->name));
1242 DPRINTF(1, (stderr, " (%s, %s, %s)", STR(list->path),
1243 STR(list->datfile), STR(list->posfile)));
1244 fprintf(stderr, "\n");
1245 if (list->child != NULL)
1246 print_list(list->child, lev + 1);
1254 * Convert the pattern to an ignore-case equivalent.
1264 cnt = 1; /* allow for '\0' */
1265 for (sp = orig; *sp != '\0'; sp++)
1266 if (isalpha((unsigned char)*sp))
1270 if ((new = malloc(cnt)) == NULL) {
1271 fprintf(stderr, "pattern too long for ignoring case\n");
1275 for (sp = new; *orig != '\0'; orig++) {
1276 if (islower((unsigned char)*orig)) {
1279 *sp++ = toupper((unsigned char)*orig);
1282 else if (isupper((unsigned char)*orig)) {
1285 *sp++ = tolower((unsigned char)*orig);
1297 * Find all the fortunes which match the pattern we've been given.
1302 Fort_len = maxlen_in_list(File_list);
1303 DPRINTF(2, (stderr, "Maximum length is %d\n", Fort_len));
1304 /* extra length, "%\n" is appended */
1305 Fortbuf = do_malloc((unsigned int) Fort_len + 10);
1308 matches_in_list(File_list);
1315 * Return the maximum fortune len in the file list.
1318 maxlen_in_list(list)
1325 for (fp = list; fp != NULL; fp = fp->next) {
1326 if (fp->child != NULL) {
1327 if ((len = maxlen_in_list(fp->child)) > maxlen)
1332 if (fp->tbl.str_longlen > maxlen)
1333 maxlen = fp->tbl.str_longlen;
1341 * Print out the matches from the files in the list.
1344 matches_in_list(list)
1352 for (fp = list; fp != NULL; fp = fp->next) {
1353 if (fp->child != NULL) {
1354 matches_in_list(fp->child);
1357 DPRINTF(1, (stderr, "searching in %s\n", fp->path));
1361 while (fgets(sp, Fort_len, fp->inf) != NULL)
1362 if (fp->tbl.str_flags & STR_COMMENTS
1363 && sp[0] == fp->tbl.str_delim
1364 && sp[1] == fp->tbl.str_delim)
1366 else if (!STR_ENDSTRING(sp, fp->tbl))
1370 if (fp->tbl.str_flags & STR_ROTATED)
1371 for (p = Fortbuf; (ch = *p) != '\0'; ++p) {
1374 *p = 'A' + (ch - 'A' + 13) % 26;
1375 else if (islower(ch))
1376 *p = 'a' + (ch - 'a' + 13) % 26;
1379 if (RE_EXEC(Fortbuf)) {
1380 printf("%c%c", fp->tbl.str_delim,
1383 printf(" (%s)", fp->name);
1388 (void) fwrite(Fortbuf, 1, (sp - Fortbuf), stdout);
1394 # endif /* NO_REGEX */
1399 (void) fprintf(stderr, "fortune [-a");
1401 (void) fprintf(stderr, "D");
1403 (void) fprintf(stderr, "f");
1405 (void) fprintf(stderr, "i");
1406 #endif /* NO_REGEX */
1407 (void) fprintf(stderr, "losw]");
1409 (void) fprintf(stderr, " [-m pattern]");
1410 #endif /* NO_REGEX */
1411 (void) fprintf(stderr, "[[#%%] file/directory/all]\n");