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

📄 fortune.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1986, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Ken Arnold. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1986, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)fortune.c	8.1 (Berkeley) 5/31/93";#endif /* not lint */# include	<sys/param.h># include	<sys/stat.h># include	<sys/dir.h># include	<fcntl.h># include	<assert.h># include	<unistd.h># include	<stdio.h># include	<ctype.h># include	<stdlib.h># include	<string.h># include	"strfile.h"# include	"pathnames.h"# define	TRUE	1# define	FALSE	0# define	bool	short# define	MINW	6		/* minimum wait if desired */# define	CPERS	20		/* # of chars for each sec */# define	SLEN	160		/* # of chars in short fortune */# define	POS_UNKNOWN	((off_t) -1)	/* pos for file unknown */# define	NO_PROB		(-1)		/* no prob specified for file */# ifdef DEBUG# define	DPRINTF(l,x)	if (Debug >= l) fprintf x; else# undef		NDEBUG# else# define	DPRINTF(l,x)# define	NDEBUG	1# endiftypedef struct fd {	int		percent;	int		fd, datfd;	off_t		pos;	FILE		*inf;	char		*name;	char		*path;	char		*datfile, *posfile;	bool		read_tbl;	bool		was_pos_file;	STRFILE		tbl;	int		num_children;	struct fd	*child, *parent;	struct fd	*next, *prev;} FILEDESC;bool	Found_one;			/* did we find a match? */bool	Find_files	= FALSE;	/* just find a list of proper fortune files */bool	Wait		= FALSE;	/* wait desired after fortune */bool	Short_only	= FALSE;	/* short fortune desired */bool	Long_only	= FALSE;	/* long fortune desired */bool	Offend		= FALSE;	/* offensive fortunes only */bool	All_forts	= FALSE;	/* any fortune allowed */bool	Equal_probs	= FALSE;	/* scatter un-allocted prob equally */#ifndef NO_REGEXbool	Match		= FALSE;	/* dump fortunes matching a pattern */#endif#ifdef DEBUGbool	Debug = FALSE;			/* print debug messages */#endifchar	*Fortbuf = NULL;			/* fortune buffer for -m */int	Fort_len = 0;off_t	Seekpts[2];			/* seek pointers to fortunes */FILEDESC	*File_list = NULL,	/* Head of file list */		*File_tail = NULL;	/* Tail of file list */FILEDESC	*Fortfile;		/* Fortune file to use */STRFILE		Noprob_tbl;		/* sum of data for all no prob files */int	 add_dir __P((FILEDESC *));int	 add_file __P((int,	    char *, char *, FILEDESC **, FILEDESC **, FILEDESC *));void	 all_forts __P((FILEDESC *, char *));char	*copy __P((char *, u_int));void	 display __P((FILEDESC *));void	 do_free __P((void *));void	*do_malloc __P((u_int));int	 form_file_list __P((char **, int));int	 fortlen __P((void));void	 get_fort __P((void));void	 get_pos __P((FILEDESC *));void	 get_tbl __P((FILEDESC *));void	 getargs __P((int, char *[]));void	 init_prob __P((void));int	 is_dir __P((char *));int	 is_fortfile __P((char *, char **, char **, int));int	 is_off_name __P((char *));int	 max __P((int, int));FILEDESC *	 new_fp __P((void));char	*off_name __P((char *));void	 open_dat __P((FILEDESC *));void	 open_fp __P((FILEDESC *));FILEDESC *	 pick_child __P((FILEDESC *));void	 print_file_list __P((void));void	 print_list __P((FILEDESC *, int));void	 sum_noprobs __P((FILEDESC *));void	 sum_tbl __P((STRFILE *, STRFILE *));void	 usage __P((void));void	 zero_tbl __P((STRFILE *));#ifndef	NO_REGEXchar	*conv_pat __P((char *));int	 find_matches __P((void));void	 matches_in_list __P((FILEDESC *));int	 maxlen_in_list __P((FILEDESC *));#endif#ifndef NO_REGEX#ifdef REGCMP# define	RE_COMP(p)	(Re_pat = regcmp(p, NULL))# define	BAD_COMP(f)	((f) == NULL)# define	RE_EXEC(p)	regex(Re_pat, (p))char	*Re_pat;char	*regcmp(), *regex();#else# define	RE_COMP(p)	(p = re_comp(p))# define	BAD_COMP(f)	((f) != NULL)# define	RE_EXEC(p)	re_exec(p)#endif#endifintmain(ac, av)int	ac;char	*av[];{#ifdef	OK_TO_WRITE_DISK	int	fd;#endif	/* OK_TO_WRITE_DISK */	getargs(ac, av);#ifndef NO_REGEX	if (Match)		exit(find_matches() != 0);#endif	init_prob();	srandom((int)(time((time_t *) NULL) + getpid()));	do {		get_fort();	} while ((Short_only && fortlen() > SLEN) ||		 (Long_only && fortlen() <= SLEN));	display(Fortfile);#ifdef	OK_TO_WRITE_DISK	if ((fd = creat(Fortfile->posfile, 0666)) < 0) {		perror(Fortfile->posfile);		exit(1);	}#ifdef	LOCK_EX	/*	 * if we can, we exclusive lock, but since it isn't very	 * important, we just punt if we don't have easy locking	 * available.	 */	(void) flock(fd, LOCK_EX);#endif	/* LOCK_EX */	write(fd, (char *) &Fortfile->pos, sizeof Fortfile->pos);	if (!Fortfile->was_pos_file)		(void) chmod(Fortfile->path, 0666);#ifdef	LOCK_EX	(void) flock(fd, LOCK_UN);#endif	/* LOCK_EX */#endif	/* OK_TO_WRITE_DISK */	if (Wait) {		if (Fort_len == 0)			(void) fortlen();		sleep((unsigned int) max(Fort_len / CPERS, MINW));	}	exit(0);	/* NOTREACHED */}voiddisplay(fp)FILEDESC	*fp;{	register char	*p, ch;	char	line[BUFSIZ];	open_fp(fp);	(void) fseek(fp->inf, (long)Seekpts[0], 0);	for (Fort_len = 0; fgets(line, sizeof line, fp->inf) != NULL &&	    !STR_ENDSTRING(line, fp->tbl); Fort_len++) {		if (fp->tbl.str_flags & STR_ROTATED)			for (p = line; ch = *p; ++p)				if (isupper(ch))					*p = 'A' + (ch - 'A' + 13) % 26;				else if (islower(ch))					*p = 'a' + (ch - 'a' + 13) % 26;		fputs(line, stdout);	}	(void) fflush(stdout);}/* * fortlen: *	Return the length of the fortune. */intfortlen(){	register int	nchar;	char		line[BUFSIZ];	if (!(Fortfile->tbl.str_flags & (STR_RANDOM | STR_ORDERED)))		nchar = (Seekpts[1] - Seekpts[0] <= SLEN);	else {		open_fp(Fortfile);		(void) fseek(Fortfile->inf, (long)Seekpts[0], 0);		nchar = 0;		while (fgets(line, sizeof line, Fortfile->inf) != NULL &&		       !STR_ENDSTRING(line, Fortfile->tbl))			nchar += strlen(line);	}	Fort_len = nchar;	return nchar;}/* *	This routine evaluates the arguments on the command line */voidgetargs(argc, argv)register int	argc;register char	**argv;{	register int	ignore_case;# ifndef NO_REGEX	register char	*pat;# endif	/* NO_REGEX */	extern char *optarg;	extern int optind;	int ch;	ignore_case = FALSE;	pat = NULL;# ifdef DEBUG	while ((ch = getopt(argc, argv, "aDefilm:osw")) != EOF)#else	while ((ch = getopt(argc, argv, "aefilm:osw")) != EOF)#endif /* DEBUG */		switch(ch) {		case 'a':		/* any fortune */			All_forts++;			break;# ifdef DEBUG		case 'D':			Debug++;			break;# endif /* DEBUG */		case 'e':			Equal_probs++;	/* scatter un-allocted prob equally */			break;		case 'f':		/* find fortune files */			Find_files++;			break;		case 'l':		/* long ones only */			Long_only++;			Short_only = FALSE;			break;		case 'o':		/* offensive ones only */			Offend++;			break;		case 's':		/* short ones only */			Short_only++;			Long_only = FALSE;			break;		case 'w':		/* give time to read */			Wait++;			break;# ifdef	NO_REGEX		case 'i':			/* case-insensitive match */		case 'm':			/* dump out the fortunes */			(void) fprintf(stderr,			    "fortune: can't match fortunes on this system (Sorry)\n");			exit(0);# else	/* NO_REGEX */		case 'm':			/* dump out the fortunes */			Match++;			pat = optarg;			break;		case 'i':			/* case-insensitive match */			ignore_case++;			break;# endif	/* NO_REGEX */		case '?':		default:			usage();		}	argc -= optind;	argv += optind;	if (!form_file_list(argv, argc))		exit(1);	/* errors printed through form_file_list() */#ifdef DEBUG	if (Debug >= 1)		print_file_list();#endif /* DEBUG */	if (Find_files) {		print_file_list();		exit(0);	}# ifndef NO_REGEX	if (pat != NULL) {		if (ignore_case)			pat = conv_pat(pat);		if (BAD_COMP(RE_COMP(pat))) {#ifndef REGCMP			fprintf(stderr, "%s\n", pat);#else	/* REGCMP */			fprintf(stderr, "bad pattern: %s\n", pat);#endif	/* REGCMP */		}	}# endif	/* NO_REGEX */}/* * form_file_list: *	Form the file list from the file specifications. */intform_file_list(files, file_cnt)register char	**files;register int	file_cnt;{	register int	i, percent;	register char	*sp;	if (file_cnt == 0)		if (Find_files)			return add_file(NO_PROB, FORTDIR, NULL, &File_list,					&File_tail, NULL);		else			return add_file(NO_PROB, "fortunes", FORTDIR,					&File_list, &File_tail, NULL);	for (i = 0; i < file_cnt; i++) {		percent = NO_PROB;		if (!isdigit(files[i][0]))			sp = files[i];		else {			percent = 0;			for (sp = files[i]; isdigit(*sp); sp++)				percent = percent * 10 + *sp - '0';			if (percent > 100) {				fprintf(stderr, "percentages must be <= 100\n");				return FALSE;			}			if (*sp == '.') {				fprintf(stderr, "percentages must be integers\n");				return FALSE;			}			/*			 * If the number isn't followed by a '%', then			 * it was not a percentage, just the first part			 * of a file name which starts with digits.			 */			if (*sp != '%') {				percent = NO_PROB;				sp = files[i];			}			else if (*++sp == '\0') {				if (++i >= file_cnt) {					fprintf(stderr, "percentages must precede files\n");					return FALSE;				}				sp = files[i];			}		}		if (strcmp(sp, "all") == 0)			sp = FORTDIR;		if (!add_file(percent, sp, NULL, &File_list, &File_tail, NULL))			return FALSE;	}	return TRUE;}/* * add_file: *	Add a file to the file list. */intadd_file(percent, file, dir, head, tail, parent)int		percent;register char	*file;char		*dir;FILEDESC	**head, **tail;FILEDESC	*parent;{	register FILEDESC	*fp;	register int		fd;	register char		*path, *offensive;	register bool		was_malloc;	register bool		isdir;	if (dir == NULL) {		path = file;		was_malloc = FALSE;	}	else {		path = do_malloc((unsigned int) (strlen(dir) + strlen(file) + 2));		(void) strcat(strcat(strcpy(path, dir), "/"), file);		was_malloc = TRUE;	}	if ((isdir = is_dir(path)) && parent != NULL) {		if (was_malloc)			free(path);		return FALSE;	/* don't recurse */	}	offensive = NULL;	if (!isdir && parent == NULL && (All_forts || Offend) &&	    !is_off_name(path)) {		offensive = off_name(path);		was_malloc = TRUE;		if (Offend) {			if (was_malloc)				free(path);			path = offensive;			file = off_name(file);		}	}	DPRINTF(1, (stderr, "adding file \"%s\"\n", path));over:	if ((fd = open(path, 0)) < 0) {		/*		 * This is a sneak.  If the user said -a, and if the		 * file we're given isn't a file, we check to see if		 * there is a -o version.  If there is, we treat it as		 * if *that* were the file given.  We only do this for		 * individual files -- if we're scanning a directory,		 * we'll pick up the -o file anyway.		 */		if (All_forts && offensive != NULL) {			path = offensive;			if (was_malloc)				free(path);			offensive = NULL;			was_malloc = TRUE;			DPRINTF(1, (stderr, "\ttrying \"%s\"\n", path));			file = off_name(file);			goto over;		}		if (dir == NULL && file[0] != '/')			return add_file(percent, file, FORTDIR, head, tail,					parent);		if (parent == NULL)			perror(path);		if (was_malloc)			free(path);		return FALSE;	}	DPRINTF(2, (stderr, "path = \"%s\"\n", path));	fp = new_fp();	fp->fd = fd;	fp->percent = percent;	fp->name = file;	fp->path = path;	fp->parent = parent;	if ((isdir && !add_dir(fp)) ||	    (!isdir &&	     !is_fortfile(path, &fp->datfile, &fp->posfile, (parent != NULL))))	{		if (parent == NULL)			fprintf(stderr,				"fortune:%s not a fortune file or directory\n",				path);		free((char *) fp);		if (was_malloc)			free(path);		do_free(fp->datfile);		do_free(fp->posfile);		do_free(offensive);		return FALSE;	}	/*	 * If the user said -a, we need to make this node a pointer to	 * both files, if there are two.  We don't need to do this if	 * we are scanning a directory, since the scan will pick up the	 * -o file anyway.	 */	if (All_forts && parent == NULL && !is_off_name(path))		all_forts(fp, offensive);	if (*head == NULL)		*head = *tail = fp;	else if (fp->percent == NO_PROB) {		(*tail)->next = fp;		fp->prev = *tail;		*tail = fp;	}	else {		(*head)->prev = fp;		fp->next = *head;		*head = fp;	}#ifdef	OK_TO_WRITE_DISK	fp->was_pos_file = (access(fp->posfile, W_OK) >= 0);#endif	/* OK_TO_WRITE_DISK */	return TRUE;}/* * new_fp: *	Return a pointer to an initialized new FILEDESC. */FILEDESC *new_fp(){	register FILEDESC	*fp;	fp = (FILEDESC *) do_malloc(sizeof *fp);	fp->datfd = -1;	fp->pos = POS_UNKNOWN;	fp->inf = NULL;	fp->fd = -1;	fp->percent = NO_PROB;	fp->read_tbl = FALSE;	fp->next = NULL;	fp->prev = NULL;	fp->child = NULL;	fp->parent = NULL;	fp->datfile = NULL;	fp->posfile = NULL;	return fp;}/* * off_name: *	Return a pointer to the offensive version of a file of this name. */char *off_name(file)char	*file;{	char	*new;	new = copy(file, (unsigned int) (strlen(file) + 2));	return strcat(new, "-o");}/* * is_off_name: *	Is the file an offensive-style name? */intis_off_name(file)char	*file;{	int	len;	len = strlen(file);	return (len >= 3 && file[len - 2] == '-' && file[len - 1] == 'o');}/* * all_forts: *	Modify a FILEDESC element to be the parent of two children if *	there are two children to be a parent of. */voidall_forts(fp, offensive)register FILEDESC	*fp;char			*offensive;{	register char		*sp;	register FILEDESC	*scene, *obscene;	register int		fd;	auto char		*datfile, *posfile;	if (fp->child != NULL)	/* this is a directory, not a file */		return;	if (!is_fortfile(offensive, &datfile, &posfile, FALSE))		return;	if ((fd = open(offensive, 0)) < 0)		return;	DPRINTF(1, (stderr, "adding \"%s\" because of -a\n", offensive));	scene = new_fp();	obscene = new_fp();	*scene = *fp;	fp->num_children = 2;	fp->child = scene;	scene->next = obscene;	obscene->next = NULL;	scene->child = obscene->child = NULL;	scene->parent = obscene->parent = fp;	fp->fd = -1;	scene->percent = obscene->percent = NO_PROB;	obscene->fd = fd;	obscene->inf = NULL;	obscene->path = offensive;	if ((sp = rindex(offensive, '/')) == NULL)		obscene->name = offensive;	else		obscene->name = ++sp;	obscene->datfile = datfile;	obscene->posfile = posfile;	obscene->read_tbl = FALSE;#ifdef	OK_TO_WRITE_DISK	obscene->was_pos_file = (access(obscene->posfile, W_OK) >= 0);#endif	/* OK_TO_WRITE_DISK */}/* * add_dir: *	Add the contents of an entire directory. */intadd_dir(fp)register FILEDESC	*fp;{	register DIR		*dir;#ifdef SYSV	register struct dirent	*dirent;	/* NIH, of course! */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -