📄 fortune.c
字号:
#else register struct direct *dirent;#endif auto FILEDESC *tailp; auto char *name; (void) close(fp->fd); fp->fd = -1; if ((dir = opendir(fp->path)) == NULL) { perror(fp->path); return FALSE; } tailp = NULL; DPRINTF(1, (stderr, "adding dir \"%s\"\n", fp->path)); fp->num_children = 0; while ((dirent = readdir(dir)) != NULL) { if (dirent->d_namlen == 0) continue; name = copy(dirent->d_name, dirent->d_namlen); if (add_file(NO_PROB, name, fp->path, &fp->child, &tailp, fp)) fp->num_children++; else free(name); } if (fp->num_children == 0) { (void) fprintf(stderr, "fortune: %s: No fortune files in directory.\n", fp->path); return FALSE; } return TRUE;}/* * is_dir: * Return TRUE if the file is a directory, FALSE otherwise. */intis_dir(file)char *file;{ auto struct stat sbuf; if (stat(file, &sbuf) < 0) return FALSE; return (sbuf.st_mode & S_IFDIR);}/* * is_fortfile: * Return TRUE if the file is a fortune database file. We try and * exclude files without reading them if possible to avoid * overhead. Files which start with ".", or which have "illegal" * suffixes, as contained in suflist[], are ruled out. *//* ARGSUSED */intis_fortfile(file, datp, posp, check_for_offend)char *file, **datp, **posp;int check_for_offend;{ register int i; register char *sp; register char *datfile; static char *suflist[] = { /* list of "illegal" suffixes" */ "dat", "pos", "c", "h", "p", "i", "f", "pas", "ftn", "ins.c", "ins,pas", "ins.ftn", "sml", NULL }; DPRINTF(2, (stderr, "is_fortfile(%s) returns ", file)); /* * Preclude any -o files for offendable people, and any non -o * files for completely offensive people. */ if (check_for_offend && !All_forts) { i = strlen(file); if (Offend ^ (file[i - 2] == '-' && file[i - 1] == 'o')) return FALSE; } if ((sp = rindex(file, '/')) == NULL) sp = file; else sp++; if (*sp == '.') { DPRINTF(2, (stderr, "FALSE (file starts with '.')\n")); return FALSE; } if ((sp = rindex(sp, '.')) != NULL) { sp++; for (i = 0; suflist[i] != NULL; i++) if (strcmp(sp, suflist[i]) == 0) { DPRINTF(2, (stderr, "FALSE (file has suffix \".%s\")\n", sp)); return FALSE; } } datfile = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */ strcat(datfile, ".dat"); if (access(datfile, R_OK) < 0) { free(datfile); DPRINTF(2, (stderr, "FALSE (no \".dat\" file)\n")); return FALSE; } if (datp != NULL) *datp = datfile; else free(datfile);#ifdef OK_TO_WRITE_DISK if (posp != NULL) { *posp = copy(file, (unsigned int) (strlen(file) + 4)); /* +4 for ".dat" */ (void) strcat(*posp, ".pos"); }#endif /* OK_TO_WRITE_DISK */ DPRINTF(2, (stderr, "TRUE\n")); return TRUE;}/* * copy: * Return a malloc()'ed copy of the string */char *copy(str, len)char *str;unsigned int len;{ char *new, *sp; new = do_malloc(len + 1); sp = new; do { *sp++ = *str; } while (*str++); return new;}/* * do_malloc: * Do a malloc, checking for NULL return. */void *do_malloc(size)unsigned int size;{ void *new; if ((new = malloc(size)) == NULL) { (void) fprintf(stderr, "fortune: out of memory.\n"); exit(1); } return new;}/* * do_free: * Free malloc'ed space, if any. */voiddo_free(ptr)void *ptr;{ if (ptr != NULL) free(ptr);}/* * init_prob: * Initialize the fortune probabilities. */voidinit_prob(){ register FILEDESC *fp, *last; register int percent, num_noprob, frac; /* * Distribute the residual probability (if any) across all * files with unspecified probability (i.e., probability of 0) * (if any). */ percent = 0; num_noprob = 0; for (fp = File_tail; fp != NULL; fp = fp->prev) if (fp->percent == NO_PROB) { num_noprob++; if (Equal_probs) last = fp; } else percent += fp->percent; DPRINTF(1, (stderr, "summing probabilities:%d%% with %d NO_PROB's", percent, num_noprob)); if (percent > 100) { (void) fprintf(stderr, "fortune: probabilities sum to %d%%!\n", percent); exit(1); } else if (percent < 100 && num_noprob == 0) { (void) fprintf(stderr, "fortune: no place to put residual probability (%d%%)\n", percent); exit(1); } else if (percent == 100 && num_noprob != 0) { (void) fprintf(stderr, "fortune: no probability left to put in residual files\n"); exit(1); } percent = 100 - percent; if (Equal_probs) if (num_noprob != 0) { if (num_noprob > 1) { frac = percent / num_noprob; DPRINTF(1, (stderr, ", frac = %d%%", frac)); for (fp = File_list; fp != last; fp = fp->next) if (fp->percent == NO_PROB) { fp->percent = frac; percent -= frac; } } last->percent = percent; DPRINTF(1, (stderr, ", residual = %d%%", percent)); } else { DPRINTF(1, (stderr, ", %d%% distributed over remaining fortunes\n", percent)); } DPRINTF(1, (stderr, "\n"));#ifdef DEBUG if (Debug >= 1) print_file_list();#endif}/* * get_fort: * Get the fortune data file's seek pointer for the next fortune. */voidget_fort(){ register FILEDESC *fp; register int choice; if (File_list->next == NULL || File_list->percent == NO_PROB) fp = File_list; else { choice = random() % 100; DPRINTF(1, (stderr, "choice = %d\n", choice)); for (fp = File_list; fp->percent != NO_PROB; fp = fp->next) if (choice < fp->percent) break; else { choice -= fp->percent; DPRINTF(1, (stderr, " skip \"%s\", %d%% (choice = %d)\n", fp->name, fp->percent, choice)); } DPRINTF(1, (stderr, "using \"%s\", %d%% (choice = %d)\n", fp->name, fp->percent, choice)); } if (fp->percent != NO_PROB) get_tbl(fp); else { if (fp->next != NULL) { sum_noprobs(fp); choice = random() % Noprob_tbl.str_numstr; DPRINTF(1, (stderr, "choice = %d (of %d) \n", choice, Noprob_tbl.str_numstr)); while (choice >= fp->tbl.str_numstr) { choice -= fp->tbl.str_numstr; fp = fp->next; DPRINTF(1, (stderr, " skip \"%s\", %d (choice = %d)\n", fp->name, fp->tbl.str_numstr, choice)); } DPRINTF(1, (stderr, "using \"%s\", %d\n", fp->name, fp->tbl.str_numstr)); } get_tbl(fp); } if (fp->child != NULL) { DPRINTF(1, (stderr, "picking child\n")); fp = pick_child(fp); } Fortfile = fp; get_pos(fp); open_dat(fp); (void) lseek(fp->datfd, (off_t) (sizeof fp->tbl + fp->pos * sizeof Seekpts[0]), 0); read(fp->datfd, Seekpts, sizeof Seekpts); Seekpts[0] = ntohl(Seekpts[0]); Seekpts[1] = ntohl(Seekpts[1]);}/* * pick_child * Pick a child from a chosen parent. */FILEDESC *pick_child(parent)FILEDESC *parent;{ register FILEDESC *fp; register int choice; if (Equal_probs) { choice = random() % parent->num_children; DPRINTF(1, (stderr, " choice = %d (of %d)\n", choice, parent->num_children)); for (fp = parent->child; choice--; fp = fp->next) continue; DPRINTF(1, (stderr, " using %s\n", fp->name)); return fp; } else { get_tbl(parent); choice = random() % parent->tbl.str_numstr; DPRINTF(1, (stderr, " choice = %d (of %d)\n", choice, parent->tbl.str_numstr)); for (fp = parent->child; choice >= fp->tbl.str_numstr; fp = fp->next) { choice -= fp->tbl.str_numstr; DPRINTF(1, (stderr, "\tskip %s, %d (choice = %d)\n", fp->name, fp->tbl.str_numstr, choice)); } DPRINTF(1, (stderr, " using %s, %d\n", fp->name, fp->tbl.str_numstr)); return fp; }}/* * sum_noprobs: * Sum up all the noprob probabilities, starting with fp. */voidsum_noprobs(fp)register FILEDESC *fp;{ static bool did_noprobs = FALSE; if (did_noprobs) return; zero_tbl(&Noprob_tbl); while (fp != NULL) { get_tbl(fp); sum_tbl(&Noprob_tbl, &fp->tbl); fp = fp->next; } did_noprobs = TRUE;}intmax(i, j)register int i, j;{ return (i >= j ? i : j);}/* * open_fp: * Assocatiate a FILE * with the given FILEDESC. */voidopen_fp(fp)FILEDESC *fp;{ if (fp->inf == NULL && (fp->inf = fdopen(fp->fd, "r")) == NULL) { perror(fp->path); exit(1); }}/* * open_dat: * Open up the dat file if we need to. */voidopen_dat(fp)FILEDESC *fp;{ if (fp->datfd < 0 && (fp->datfd = open(fp->datfile, 0)) < 0) { perror(fp->datfile); exit(1); }}/* * get_pos: * Get the position from the pos file, if there is one. If not, * return a random number. */voidget_pos(fp)FILEDESC *fp;{#ifdef OK_TO_WRITE_DISK int fd;#endif /* OK_TO_WRITE_DISK */ assert(fp->read_tbl); if (fp->pos == POS_UNKNOWN) {#ifdef OK_TO_WRITE_DISK if ((fd = open(fp->posfile, 0)) < 0 || read(fd, &fp->pos, sizeof fp->pos) != sizeof fp->pos) fp->pos = random() % fp->tbl.str_numstr; else if (fp->pos >= fp->tbl.str_numstr) fp->pos %= fp->tbl.str_numstr; if (fd >= 0) (void) close(fd);#else fp->pos = random() % fp->tbl.str_numstr;#endif /* OK_TO_WRITE_DISK */ } if (++(fp->pos) >= fp->tbl.str_numstr) fp->pos -= fp->tbl.str_numstr; DPRINTF(1, (stderr, "pos for %s is %qd\n", fp->name, fp->pos));}/* * get_tbl: * Get the tbl data file the datfile. */voidget_tbl(fp)FILEDESC *fp;{ auto int fd; register FILEDESC *child; if (fp->read_tbl) return; if (fp->child == NULL) { if ((fd = open(fp->datfile, 0)) < 0) { perror(fp->datfile); exit(1); } if (read(fd, (char *) &fp->tbl, sizeof fp->tbl) != sizeof fp->tbl) { (void)fprintf(stderr, "fortune: %s corrupted\n", fp->path); exit(1); } /* fp->tbl.str_version = ntohl(fp->tbl.str_version); */ fp->tbl.str_numstr = ntohl(fp->tbl.str_numstr); fp->tbl.str_longlen = ntohl(fp->tbl.str_longlen); fp->tbl.str_shortlen = ntohl(fp->tbl.str_shortlen); fp->tbl.str_flags = ntohl(fp->tbl.str_flags); (void) close(fd); } else { zero_tbl(&fp->tbl); for (child = fp->child; child != NULL; child = child->next) { get_tbl(child); sum_tbl(&fp->tbl, &child->tbl); } } fp->read_tbl = TRUE;}/* * zero_tbl: * Zero out the fields we care about in a tbl structure. */voidzero_tbl(tp)register STRFILE *tp;{ tp->str_numstr = 0; tp->str_longlen = 0; tp->str_shortlen = -1;}/* * sum_tbl: * Merge the tbl data of t2 into t1. */voidsum_tbl(t1, t2)register STRFILE *t1, *t2;{ t1->str_numstr += t2->str_numstr; if (t1->str_longlen < t2->str_longlen) t1->str_longlen = t2->str_longlen; if (t1->str_shortlen > t2->str_shortlen) t1->str_shortlen = t2->str_shortlen;}#define STR(str) ((str) == NULL ? "NULL" : (str))/* * print_file_list: * Print out the file list */voidprint_file_list(){ print_list(File_list, 0);}/* * print_list: * Print out the actual list, recursively. */voidprint_list(list, lev)register FILEDESC *list;int lev;{ while (list != NULL) { fprintf(stderr, "%*s", lev * 4, ""); if (list->percent == NO_PROB) fprintf(stderr, "___%%"); else fprintf(stderr, "%3d%%", list->percent); fprintf(stderr, " %s", STR(list->name)); DPRINTF(1, (stderr, " (%s, %s, %s)\n", STR(list->path), STR(list->datfile), STR(list->posfile))); putc('\n', stderr); if (list->child != NULL) print_list(list->child, lev + 1); list = list->next; }}#ifndef NO_REGEX/* * conv_pat: * Convert the pattern to an ignore-case equivalent. */char *conv_pat(orig)register char *orig;{ register char *sp; register unsigned int cnt; register char *new; cnt = 1; /* allow for '\0' */ for (sp = orig; *sp != '\0'; sp++) if (isalpha(*sp)) cnt += 4; else cnt++; if ((new = malloc(cnt)) == NULL) { fprintf(stderr, "pattern too long for ignoring case\n"); exit(1); } for (sp = new; *orig != '\0'; orig++) { if (islower(*orig)) { *sp++ = '['; *sp++ = *orig; *sp++ = toupper(*orig); *sp++ = ']'; } else if (isupper(*orig)) { *sp++ = '['; *sp++ = *orig; *sp++ = tolower(*orig); *sp++ = ']'; } else *sp++ = *orig; } *sp = '\0'; return new;}/* * find_matches: * Find all the fortunes which match the pattern we've been given. */intfind_matches(){ Fort_len = maxlen_in_list(File_list); DPRINTF(2, (stderr, "Maximum length is %d\n", Fort_len)); /* extra length, "%\n" is appended */ Fortbuf = do_malloc((unsigned int) Fort_len + 10); Found_one = FALSE; matches_in_list(File_list); return Found_one; /* NOTREACHED */}/* * maxlen_in_list * Return the maximum fortune len in the file list. */intmaxlen_in_list(list)FILEDESC *list;{ register FILEDESC *fp; register int len, maxlen; maxlen = 0; for (fp = list; fp != NULL; fp = fp->next) { if (fp->child != NULL) { if ((len = maxlen_in_list(fp->child)) > maxlen) maxlen = len; } else { get_tbl(fp); if (fp->tbl.str_longlen > maxlen) maxlen = fp->tbl.str_longlen; } } return maxlen;}/* * matches_in_list * Print out the matches from the files in the list. */voidmatches_in_list(list)FILEDESC *list;{ register char *sp; register FILEDESC *fp; int in_file; for (fp = list; fp != NULL; fp = fp->next) { if (fp->child != NULL) { matches_in_list(fp->child); continue; } DPRINTF(1, (stderr, "searching in %s\n", fp->path)); open_fp(fp); sp = Fortbuf; in_file = FALSE; while (fgets(sp, Fort_len, fp->inf) != NULL) if (!STR_ENDSTRING(sp, fp->tbl)) sp += strlen(sp); else { *sp = '\0'; if (RE_EXEC(Fortbuf)) { printf("%c%c", fp->tbl.str_delim, fp->tbl.str_delim); if (!in_file) { printf(" (%s)", fp->name); Found_one = TRUE; in_file = TRUE; } putchar('\n'); (void) fwrite(Fortbuf, 1, (sp - Fortbuf), stdout); } sp = Fortbuf; } }}# endif /* NO_REGEX */voidusage(){ (void) fprintf(stderr, "fortune [-a");#ifdef DEBUG (void) fprintf(stderr, "D");#endif /* DEBUG */ (void) fprintf(stderr, "f");#ifndef NO_REGEX (void) fprintf(stderr, "i");#endif /* NO_REGEX */ (void) fprintf(stderr, "losw]");#ifndef NO_REGEX (void) fprintf(stderr, " [-m pattern]");#endif /* NO_REGEX */ (void) fprintf(stderr, "[ [#%%] file/directory/all]\n"); exit(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -