⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fortune.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -