]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - fortune/fortune/fortune.c
86a17b7a8a845ab71e48c3d80127892bfce45995
1 /* $NetBSD: fortune.c,v 1.21 1999/09/22 18:56:32 jsm Exp $ */
4 * Copyright (c) 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <sys/cdefs.h>
41 __COPYRIGHT("@(#) Copyright (c) 1986, 1993\n\
42 The Regents of the University of California. All rights reserved.\n");
47 static char sccsid
[] = "@(#)fortune.c 8.1 (Berkeley) 5/31/93";
49 __RCSID("$NetBSD: fortune.c,v 1.21 1999/09/22 18:56:32 jsm Exp $");
53 # include <sys/param.h>
54 # include <sys/stat.h>
67 # include "pathnames.h"
73 # define MINW 6 /* minimum wait if desired */
74 # define CPERS 20 /* # of chars for each sec */
75 # define SLEN 160 /* # of chars in short fortune */
77 # define POS_UNKNOWN ((off_t) -1) /* pos for file unknown */
78 # define NO_PROB (-1) /* no prob specified for file */
81 # define DPRINTF(l,x) if (Debug >= l) fprintf x; else
95 char *datfile
, *posfile
;
100 struct fd
*child
, *parent
;
101 struct fd
*next
, *prev
;
104 bool Found_one
; /* did we find a match? */
105 bool Find_files
= FALSE
; /* just find a list of proper fortune 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 off_t 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 const char *, const char *, FILEDESC
**, FILEDESC
**, FILEDESC
*));
134 void all_forts
__P((FILEDESC
*, const char *));
135 char *copy
__P((const 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((const char *));
147 int is_fortfile
__P((const char *, char **, char **, int));
148 int is_off_name
__P((const char *));
149 int main
__P((int, char *[]));
150 int max
__P((int, int));
153 char *off_name
__P((const char *));
154 void open_dat
__P((FILEDESC
*));
155 void open_fp
__P((FILEDESC
*));
157 pick_child
__P((FILEDESC
*));
158 void print_file_list
__P((void));
159 void print_list
__P((FILEDESC
*, int));
160 void sum_noprobs
__P((FILEDESC
*));
161 void sum_tbl
__P((STRFILE
*, STRFILE
*));
162 void usage
__P((void)) __attribute__((__noreturn__
));
163 void zero_tbl
__P((STRFILE
*));
166 char *conv_pat
__P((char *));
167 int find_matches
__P((void));
168 void matches_in_list
__P((FILEDESC
*));
169 int maxlen_in_list
__P((FILEDESC
*));
175 # define RE_COMP(p) (Re_pat = regcmp(p, NULL))
176 # define BAD_COMP(f) ((f) == NULL)
177 # define RE_EXEC(p) regex(Re_pat, (p))
182 char *regcmp(), *regex();
185 # define RE_COMP(p) (p = re_comp(p))
186 # define BAD_COMP(f) ((f) != NULL)
187 # define RE_EXEC(p) re_exec(p)
191 regex_t
*Re_pat
= NULL
;
192 # define RE_INIT() if (Re_pat == NULL && \
193 (Re_pat = calloc(sizeof(*Re_pat), 1)) == NULL)\
195 # define RE_COMP(p) (regcomp(Re_pat, p, REG_EXTENDED))
196 # define BAD_COMP(f) ((f) != 0)
197 # define RE_EXEC(p) (!regexec(Re_pat, p, 0, NULL, 0))
198 # define RE_FREE() if (Re_pat != NULL) \
199 regfree(Re_pat), Re_pat = NULL
201 #error "Need to define HAVE_REGCMP, HAVE_RE_COMP, or HAVE_REGCOMP"
206 #define NAMLEN(d) ((d)->d_namlen)
214 #ifdef OK_TO_WRITE_DISK
216 #endif /* OK_TO_WRITE_DISK */
222 exit(find_matches() != 0);
226 srandom((int)(time((time_t *) NULL
) + getpid()));
229 } while ((Short_only
&& fortlen() > SLEN
) ||
230 (Long_only
&& fortlen() <= SLEN
));
234 #ifdef OK_TO_WRITE_DISK
235 if ((fd
= creat(Fortfile
->posfile
, 0666)) < 0)
236 err(1, "Can't create `%s'", Fortfile
->posfile
);
239 * if we can, we exclusive lock, but since it isn't very
240 * important, we just punt if we don't have easy locking
243 (void) flock(fd
, LOCK_EX
);
245 write(fd
, (char *) &Fortfile
->pos
, sizeof Fortfile
->pos
);
246 if (!Fortfile
->was_pos_file
)
247 (void) chmod(Fortfile
->path
, 0666);
249 (void) flock(fd
, LOCK_UN
);
251 #endif /* OK_TO_WRITE_DISK */
255 sleep((unsigned int) max(Fort_len
/ CPERS
, MINW
));
268 (void) fseek(fp
->inf
, (long)Seekpts
[0], SEEK_SET
);
269 for (Fort_len
= 0; fgets(line
, sizeof line
, fp
->inf
) != NULL
&&
270 !STR_ENDSTRING(line
, fp
->tbl
); Fort_len
++) {
271 if (fp
->tbl
.str_flags
& STR_ROTATED
) {
272 for (p
= line
; (ch
= *p
) != 0; ++p
)
274 *p
= 'A' + (ch
- 'A' + 13) % 26;
275 else if (islower(ch
))
276 *p
= 'a' + (ch
- 'a' + 13) % 26;
280 (void) fflush(stdout
);
285 * Return the length of the fortune.
293 if (!(Fortfile
->tbl
.str_flags
& (STR_RANDOM
| STR_ORDERED
)))
294 nchar
= (Seekpts
[1] - Seekpts
[0] <= SLEN
);
297 (void) fseek(Fortfile
->inf
, (long)Seekpts
[0], SEEK_SET
);
299 while (fgets(line
, sizeof line
, Fortfile
->inf
) != NULL
&&
300 !STR_ENDSTRING(line
, Fortfile
->tbl
))
301 nchar
+= strlen(line
);
308 * This routine evaluates the arguments on the command line
318 # endif /* NO_REGEX */
326 while ((ch
= getopt(argc
, argv
, "aDefilm:osw")) != -1)
328 while ((ch
= getopt(argc
, argv
, "aefilm:osw")) != -1)
331 case 'a': /* any fortune */
340 Equal_probs
++; /* scatter un-allocted prob equally */
342 case 'f': /* find fortune files */
345 case 'l': /* long ones only */
349 case 'o': /* offensive ones only */
352 case 's': /* short ones only */
356 case 'w': /* give time to read */
360 case 'i': /* case-insensitive match */
361 case 'm': /* dump out the fortunes */
362 errx(1, "Can't match fortunes on this system (Sorry)");
363 # else /* NO_REGEX */
364 case 'm': /* dump out the fortunes */
368 case 'i': /* case-insensitive match */
371 # endif /* NO_REGEX */
379 if (!form_file_list(argv
, argc
))
380 exit(1); /* errors printed through form_file_list() */
395 if (BAD_COMP(RE_COMP(pat
))) {
397 warnx("bad pattern: %s\n", pat
);
398 #else /* !HAVE_REGCMP */
400 #endif /* !HAVE_REGCMP */
404 # endif /* NO_REGEX */
409 * Form the file list from the file specifications.
412 form_file_list(files
, file_cnt
)
421 return add_file(NO_PROB
, FORTDIR
, NULL
, &File_list
,
424 return add_file(NO_PROB
, "fortunes", FORTDIR
,
425 &File_list
, &File_tail
, NULL
);
427 for (i
= 0; i
< file_cnt
; i
++) {
429 if (!isdigit(files
[i
][0]))
433 for (sp
= files
[i
]; isdigit(*sp
); sp
++)
434 percent
= percent
* 10 + *sp
- '0';
436 warnx("Percentages must be <= 100");
440 warnx("Percentages must be integers");
444 * If the number isn't followed by a '%', then
445 * it was not a percentage, just the first part
446 * of a file name which starts with digits.
452 else if (*++sp
== '\0') {
453 if (++i
>= file_cnt
) {
454 warnx("Percentages must precede files");
460 if (strcmp(sp
, "all") == 0)
462 if (!add_file(percent
, sp
, NULL
, &File_list
, &File_tail
, NULL
))
470 * Add a file to the file list.
473 add_file(percent
, file
, dir
, head
, tail
, parent
)
477 FILEDESC
**head
, **tail
;
483 char *tpath
, *offensive
;
493 tpath
= do_malloc((unsigned int) (strlen(dir
) + strlen(file
) + 2));
494 (void) strcat(strcat(strcpy(tpath
, dir
), "/"), file
);
498 if ((isdir
= is_dir(path
)) && parent
!= NULL
) {
501 return FALSE
; /* don't recurse */
504 if (!isdir
&& parent
== NULL
&& (All_forts
|| Offend
) &&
505 !is_off_name(path
)) {
506 offensive
= off_name(path
);
512 file
= off_name(file
);
516 DPRINTF(1, (stderr
, "adding file \"%s\"\n", path
));
518 if ((fd
= open(path
, O_RDONLY
)) < 0) {
520 * This is a sneak. If the user said -a, and if the
521 * file we're given isn't a file, we check to see if
522 * there is a -o version. If there is, we treat it as
523 * if *that* were the file given. We only do this for
524 * individual files -- if we're scanning a directory,
525 * we'll pick up the -o file anyway.
527 if (All_forts
&& offensive
!= NULL
) {
533 DPRINTF(1, (stderr
, "\ttrying \"%s\"\n", path
));
534 file
= off_name(file
);
537 if (dir
== NULL
&& file
[0] != '/')
538 return add_file(percent
, file
, FORTDIR
, head
, tail
,
541 warn("Cannot open `%s'", path
);
547 DPRINTF(2, (stderr
, "path = \"%s\"\n", path
));
551 fp
->percent
= percent
;
556 if ((isdir
&& !add_dir(fp
)) ||
558 !is_fortfile(path
, &fp
->datfile
, &fp
->posfile
, (parent
!= NULL
))))
561 warnx("`%s' not a fortune file or directory", path
);
565 do_free(fp
->datfile
);
566 do_free(fp
->posfile
);
571 * If the user said -a, we need to make this node a pointer to
572 * both files, if there are two. We don't need to do this if
573 * we are scanning a directory, since the scan will pick up the
576 if (All_forts
&& parent
== NULL
&& !is_off_name(path
))
577 all_forts(fp
, offensive
);
580 else if (fp
->percent
== NO_PROB
) {
590 #ifdef OK_TO_WRITE_DISK
591 fp
->was_pos_file
= (access(fp
->posfile
, W_OK
) >= 0);
592 #endif /* OK_TO_WRITE_DISK */
599 * Return a pointer to an initialized new FILEDESC.
606 fp
= (FILEDESC
*) do_malloc(sizeof *fp
);
608 fp
->pos
= POS_UNKNOWN
;
611 fp
->percent
= NO_PROB
;
612 fp
->read_tbl
= FALSE
;
624 * Return a pointer to the offensive version of a file of this name.
632 new = copy(file
, (unsigned int) (strlen(file
) + 2));
633 return strcat(new, "-o");
638 * Is the file an offensive-style name?
647 return (len
>= 3 && file
[len
- 2] == '-' && file
[len
- 1] == 'o');
652 * Modify a FILEDESC element to be the parent of two children if
653 * there are two children to be a parent of.
656 all_forts(fp
, offensive
)
658 const char *offensive
;
661 FILEDESC
*scene
, *obscene
;
663 char *datfile
, *posfile
;
665 if (fp
->child
!= NULL
) /* this is a directory, not a file */
667 if (!is_fortfile(offensive
, &datfile
, &posfile
, FALSE
))
669 if ((fd
= open(offensive
, O_RDONLY
)) < 0)
671 DPRINTF(1, (stderr
, "adding \"%s\" because of -a\n", offensive
));
676 fp
->num_children
= 2;
678 scene
->next
= obscene
;
679 obscene
->next
= NULL
;
680 scene
->child
= obscene
->child
= NULL
;
681 scene
->parent
= obscene
->parent
= fp
;
684 scene
->percent
= obscene
->percent
= NO_PROB
;
688 obscene
->path
= offensive
;
689 if ((sp
= rindex(offensive
, '/')) == NULL
)
690 obscene
->name
= offensive
;
692 obscene
->name
= ++sp
;
693 obscene
->datfile
= datfile
;
694 obscene
->posfile
= posfile
;
695 obscene
->read_tbl
= FALSE
;
696 #ifdef OK_TO_WRITE_DISK
697 obscene
->was_pos_file
= (access(obscene
->posfile
, W_OK
) >= 0);
698 #endif /* OK_TO_WRITE_DISK */
703 * Add the contents of an entire directory.
710 struct dirent
*dirent
;
714 (void) close(fp
->fd
);
716 if ((dir
= opendir(fp
->path
)) == NULL
) {
717 warn("Cannot open `%s'", fp
->path
);
721 DPRINTF(1, (stderr
, "adding dir \"%s\"\n", fp
->path
));
722 fp
->num_children
= 0;
723 while ((dirent
= readdir(dir
)) != NULL
) {
724 if (NAMLEN(dirent
) == 0)
726 name
= copy(dirent
->d_name
, NAMLEN(dirent
));
727 if (add_file(NO_PROB
, name
, fp
->path
, &fp
->child
, &tailp
, fp
))
732 if (fp
->num_children
== 0) {
733 warnx("`%s': No fortune files in directory.\n", fp
->path
);
741 * Return TRUE if the file is a directory, FALSE otherwise.
749 if (stat(file
, &sbuf
) < 0)
751 return (S_ISDIR(sbuf
.st_mode
));
756 * Return TRUE if the file is a fortune database file. We try and
757 * exclude files without reading them if possible to avoid
758 * overhead. Files which start with ".", or which have "illegal"
759 * suffixes, as contained in suflist[], are ruled out.
763 is_fortfile(file
, datp
, posp
, check_for_offend
)
766 # ifndef OK_TO_WRITE_DISK
767 __attribute__((__unused__
))
770 int check_for_offend
;
775 static const char *const suflist
[] = { /* list of "illegal" suffixes" */
776 "dat", "pos", "c", "h", "p", "i", "f",
777 "pas", "ftn", "ins.c", "ins,pas",
782 DPRINTF(2, (stderr
, "is_fortfile(%s) returns ", file
));
785 * Preclude any -o files for offendable people, and any non -o
786 * files for completely offensive people.
788 if (check_for_offend
&& !All_forts
) {
790 if (Offend
^ (file
[i
- 2] == '-' && file
[i
- 1] == 'o'))
794 if ((sp
= rindex(file
, '/')) == NULL
)
799 DPRINTF(2, (stderr
, "FALSE (file starts with '.')\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) {
815 DPRINTF(2, (stderr
, "FALSE (no \".dat\" file)\n"));
822 #ifdef OK_TO_WRITE_DISK
824 *posp
= copy(file
, (unsigned int) (strlen(file
) + 4)); /* +4 for ".dat" */
825 (void) strcat(*posp
, ".pos");
827 #endif /* OK_TO_WRITE_DISK */
828 DPRINTF(2, (stderr
, "TRUE\n"));
834 * Return a malloc()'ed copy of the string
843 new = do_malloc(len
+ 1);
853 * Do a malloc, checking for NULL return.
861 if ((new = malloc(size
)) == NULL
)
868 * Free malloc'ed space, if any.
880 * Initialize the fortune probabilities.
886 int percent
, num_noprob
, frac
;
890 * Distribute the residual probability (if any) across all
891 * files with unspecified probability (i.e., probability of 0)
897 for (fp
= File_tail
; fp
!= NULL
; fp
= fp
->prev
)
898 if (fp
->percent
== NO_PROB
) {
903 percent
+= fp
->percent
;
904 DPRINTF(1, (stderr
, "summing probabilities:%d%% with %d NO_PROB's",
905 percent
, num_noprob
));
907 errx(1, "Probabilities sum to %d%%!", percent
);
908 else if (percent
< 100 && num_noprob
== 0)
909 errx(1, "No place to put residual probability (%d%%)",
911 else if (percent
== 100 && num_noprob
!= 0)
912 errx(1, "No probability left to put in residual files");
913 percent
= 100 - percent
;
915 if (num_noprob
!= 0) {
916 if (num_noprob
> 1) {
917 frac
= percent
/ num_noprob
;
918 DPRINTF(1, (stderr
, ", frac = %d%%", frac
));
919 for (fp
= File_list
; fp
!= last
; fp
= fp
->next
)
920 if (fp
->percent
== NO_PROB
) {
925 last
->percent
= percent
;
926 DPRINTF(1, (stderr
, ", residual = %d%%", percent
));
930 ", %d%% distributed over remaining fortunes\n",
933 DPRINTF(1, (stderr
, "\n"));
943 * Get the fortune data file's seek pointer for the next fortune.
951 if (File_list
->next
== NULL
|| File_list
->percent
== NO_PROB
)
954 choice
= random() % 100;
955 DPRINTF(1, (stderr
, "choice = %d\n", choice
));
956 for (fp
= File_list
; fp
->percent
!= NO_PROB
; fp
= fp
->next
)
957 if (choice
< fp
->percent
)
960 choice
-= fp
->percent
;
962 " skip \"%s\", %d%% (choice = %d)\n",
963 fp
->name
, fp
->percent
, choice
));
966 "using \"%s\", %d%% (choice = %d)\n",
967 fp
->name
, fp
->percent
, choice
));
969 if (fp
->percent
!= NO_PROB
)
972 if (fp
->next
!= NULL
) {
974 choice
= random() % Noprob_tbl
.str_numstr
;
975 DPRINTF(1, (stderr
, "choice = %d (of %d) \n", choice
,
976 Noprob_tbl
.str_numstr
));
977 while ((u_int32_t
)choice
>= fp
->tbl
.str_numstr
) {
978 choice
-= fp
->tbl
.str_numstr
;
981 " skip \"%s\", %d (choice = %d)\n",
982 fp
->name
, fp
->tbl
.str_numstr
,
985 DPRINTF(1, (stderr
, "using \"%s\", %d\n", fp
->name
,
986 fp
->tbl
.str_numstr
));
990 if (fp
->child
!= NULL
) {
991 DPRINTF(1, (stderr
, "picking child\n"));
997 (void) lseek(fp
->datfd
,
998 (off_t
) (sizeof fp
->tbl
+ fp
->pos
* sizeof Seekpts
[0]), SEEK_SET
);
999 read(fp
->datfd
, Seekpts
, sizeof Seekpts
);
1000 BE64TOH(Seekpts
[0]);
1001 BE64TOH(Seekpts
[1]);
1006 * Pick a child from a chosen parent.
1016 choice
= random() % parent
->num_children
;
1017 DPRINTF(1, (stderr
, " choice = %d (of %d)\n",
1018 choice
, parent
->num_children
));
1019 for (fp
= parent
->child
; choice
--; fp
= fp
->next
)
1021 DPRINTF(1, (stderr
, " using %s\n", fp
->name
));
1026 choice
= random() % parent
->tbl
.str_numstr
;
1027 DPRINTF(1, (stderr
, " choice = %d (of %d)\n",
1028 choice
, parent
->tbl
.str_numstr
));
1029 for (fp
= parent
->child
; (u_int32_t
)choice
>= fp
->tbl
.str_numstr
;
1031 choice
-= fp
->tbl
.str_numstr
;
1032 DPRINTF(1, (stderr
, "\tskip %s, %d (choice = %d)\n",
1033 fp
->name
, fp
->tbl
.str_numstr
, choice
));
1035 DPRINTF(1, (stderr
, " using %s, %d\n", fp
->name
,
1036 fp
->tbl
.str_numstr
));
1043 * Sum up all the noprob probabilities, starting with fp.
1049 static bool did_noprobs
= FALSE
;
1053 zero_tbl(&Noprob_tbl
);
1054 while (fp
!= NULL
) {
1056 sum_tbl(&Noprob_tbl
, &fp
->tbl
);
1066 return (i
>= j
? i
: j
);
1071 * Assocatiate a FILE * with the given FILEDESC.
1077 if (fp
->inf
== NULL
&& (fp
->inf
= fdopen(fp
->fd
, "r")) == NULL
)
1078 err(1, "Cannot open `%s'", fp
->path
);
1083 * Open up the dat file if we need to.
1089 if (fp
->datfd
< 0 && (fp
->datfd
= open(fp
->datfile
, O_RDONLY
)) < 0)
1090 err(1, "Cannot open `%s'", fp
->datfile
);
1095 * Get the position from the pos file, if there is one. If not,
1096 * return a random number.
1102 #ifdef OK_TO_WRITE_DISK
1104 #endif /* OK_TO_WRITE_DISK */
1106 assert(fp
->read_tbl
);
1107 if (fp
->pos
== POS_UNKNOWN
) {
1108 #ifdef OK_TO_WRITE_DISK
1109 if ((fd
= open(fp
->posfile
, O_RDONLY
)) < 0 ||
1110 read(fd
, &fp
->pos
, sizeof fp
->pos
) != sizeof fp
->pos
)
1111 fp
->pos
= random() % fp
->tbl
.str_numstr
;
1112 else if (fp
->pos
>= fp
->tbl
.str_numstr
)
1113 fp
->pos
%= fp
->tbl
.str_numstr
;
1117 fp
->pos
= random() % fp
->tbl
.str_numstr
;
1118 #endif /* OK_TO_WRITE_DISK */
1120 if ((u_int64_t
)++(fp
->pos
) >= fp
->tbl
.str_numstr
)
1121 fp
->pos
-= fp
->tbl
.str_numstr
;
1122 DPRINTF(1, (stderr
, "pos for %s is %qd\n", fp
->name
, fp
->pos
));
1127 * Get the tbl data file the datfile.
1138 if (fp
->child
== NULL
) {
1139 if ((fd
= open(fp
->datfile
, O_RDONLY
)) < 0)
1140 err(1, "Cannot open `%s'", fp
->datfile
);
1141 if (read(fd
, (char *) &fp
->tbl
, sizeof fp
->tbl
) != sizeof fp
->tbl
) {
1142 errx(1, "Database `%s' corrupted", fp
->path
);
1144 /* BE32TOH(fp->tbl.str_version); */
1145 BE32TOH(fp
->tbl
.str_numstr
);
1146 BE32TOH(fp
->tbl
.str_longlen
);
1147 BE32TOH(fp
->tbl
.str_shortlen
);
1148 BE32TOH(fp
->tbl
.str_flags
);
1153 for (child
= fp
->child
; child
!= NULL
; child
= child
->next
) {
1155 sum_tbl(&fp
->tbl
, &child
->tbl
);
1158 fp
->read_tbl
= TRUE
;
1163 * Zero out the fields we care about in a tbl structure.
1170 tp
->str_longlen
= 0;
1171 tp
->str_shortlen
= -1;
1176 * Merge the tbl data of t2 into t1.
1182 t1
->str_numstr
+= t2
->str_numstr
;
1183 if (t1
->str_longlen
< t2
->str_longlen
)
1184 t1
->str_longlen
= t2
->str_longlen
;
1185 if (t1
->str_shortlen
> t2
->str_shortlen
)
1186 t1
->str_shortlen
= t2
->str_shortlen
;
1189 #define STR(str) ((str) == NULL ? "NULL" : (str))
1193 * Print out the file list
1198 print_list(File_list
, 0);
1203 * Print out the actual list, recursively.
1206 print_list(list
, lev
)
1210 while (list
!= NULL
) {
1211 fprintf(stderr
, "%*s", lev
* 4, "");
1212 if (list
->percent
== NO_PROB
)
1213 fprintf(stderr
, "___%%");
1215 fprintf(stderr
, "%3d%%", list
->percent
);
1216 fprintf(stderr
, " %s", STR(list
->name
));
1217 DPRINTF(1, (stderr
, " (%s, %s, %s)\n", STR(list
->path
),
1218 STR(list
->datfile
), STR(list
->posfile
)));
1220 if (list
->child
!= NULL
)
1221 print_list(list
->child
, lev
+ 1);
1229 * Convert the pattern to an ignore-case equivalent.
1239 cnt
= 1; /* allow for '\0' */
1240 for (sp
= orig
; *sp
!= '\0'; sp
++)
1245 if ((new = malloc(cnt
)) == NULL
)
1248 for (sp
= new; *orig
!= '\0'; orig
++) {
1249 if (islower(*orig
)) {
1252 *sp
++ = toupper(*orig
);
1255 else if (isupper(*orig
)) {
1258 *sp
++ = tolower(*orig
);
1270 * Find all the fortunes which match the pattern we've been given.
1275 Fort_len
= maxlen_in_list(File_list
);
1276 DPRINTF(2, (stderr
, "Maximum length is %d\n", Fort_len
));
1277 /* extra length, "%\n" is appended */
1278 Fortbuf
= do_malloc((unsigned int) Fort_len
+ 10);
1281 matches_in_list(File_list
);
1288 * Return the maximum fortune len in the file list.
1291 maxlen_in_list(list
)
1298 for (fp
= list
; fp
!= NULL
; fp
= fp
->next
) {
1299 if (fp
->child
!= NULL
) {
1300 if ((len
= maxlen_in_list(fp
->child
)) > maxlen
)
1305 if (fp
->tbl
.str_longlen
> (u_int32_t
)maxlen
)
1306 maxlen
= fp
->tbl
.str_longlen
;
1314 * Print out the matches from the files in the list.
1317 matches_in_list(list
)
1324 for (fp
= list
; fp
!= NULL
; fp
= fp
->next
) {
1325 if (fp
->child
!= NULL
) {
1326 matches_in_list(fp
->child
);
1329 DPRINTF(1, (stderr
, "searching in %s\n", fp
->path
));
1333 while (fgets(sp
, Fort_len
, fp
->inf
) != NULL
)
1334 if (!STR_ENDSTRING(sp
, fp
->tbl
))
1338 if (RE_EXEC(Fortbuf
)) {
1339 printf("%c%c", fp
->tbl
.str_delim
,
1342 printf(" (%s)", fp
->name
);
1347 (void) fwrite(Fortbuf
, 1, (sp
- Fortbuf
), stdout
);
1354 # endif /* NO_REGEX */
1359 extern char *__progname
;
1360 (void) fprintf(stderr
, "%s [-a", __progname
);
1362 (void) fprintf(stderr
, "D");
1364 (void) fprintf(stderr
, "f");
1366 (void) fprintf(stderr
, "i");
1367 #endif /* NO_REGEX */
1368 (void) fprintf(stderr
, "losw]");
1370 (void) fprintf(stderr
, " [-m pattern]");
1371 #endif /* NO_REGEX */
1372 (void) fprintf(stderr
, "[ [#%%] file/directory/all]\n");