Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 2/19/85; site seismo.UUCP
Path: utzoo!watmath!clyde!cbosgd!seismo!keith
From: keith@seismo.UUCP (Keith Bostic)
Newsgroups: net.sources.games
Subject: fortune(6)
Message-ID: <1549@seismo.UUCP>
Date: Sun, 3-Mar-85 14:44:00 EST
Article-I.D.: seismo.1549
Posted: Sun Mar  3 14:44:00 1985
Date-Received: Mon, 4-Mar-85 20:17:20 EST
Organization: Center for Seismic Studies, Arlington, VA
Lines: 563

A few days ago, a "new" version of fortune(6) was posted in
net.sources.games.  This fortune program is Berkeley's and
was written by Ken Arnold.  Do not run it unless you are
properly licensed for Berkeley's software.

If you are not so licensed and you'd like to run fortune, I
have posted a complete rewrite of the fortune software
to net.sources.games.  This software is explicitly placed
in the public domain and anyone may use/abuse it. It
does everything that *any* of the posted/available fortune(6)
programs do.

I have not included seismo's fortune database, mostly because
it currently contains about 10K items.  If you would like
a copy of said database, please contact me personally.  We are
also always interested in obtaining new fortune entries.  If
you have any local/new items, I'd be very interested in hearing
about them.

Enjoy!

		Keith Bostic
			ARPA: keith@seismo 
			UUCP: seismo!keith

======  cut here  ======

echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
XCFLAGS=	-O -I.
XDIR=/usr/games
XLIB=/usr/games/lib
X
Xall: strfile unstr fortune
X
Xfortune: strfile.h fortune.o getopts.o
X	$(CC) -o $@ fortune.o getopts.o
X
Xstrfile: strfile.h strfile.o getopts.o
X	$(CC) -o $@ strfile.o getopts.o
X
Xunstr: strfile.h unstr.o getopts.o
X	$(CC) -o $@ unstr.o getopts.o
X
Xinstall: fortune
X	install -s -m 711 -o bin -g bin fortune $(DIR)
X	install -m 644 -o bin -g bin fortunes.dat $(LIB)
X
Xtar:
X	tar cvf fort.src.tar Makefile README do_sort fortune.6 fortune.c getopts.c strfile.c strfile.h unstr.c
END-of-Makefile
echo x - README
sed 's/^X//' >README << 'END-of-README'
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XFortune format is:
X
X1: For credits, DON'T skip a line after the fortune,
X   then, \t\t--credit#1 [credit2, credit3]
X
X2: Definitions, are in all caps, colon, CR, tab rest of lines.
X   If definition is credited treat as a non-definition.
X
X3: Laws, rules, etc.  treat as non-definition.
X
X4: Dates are [January 4, 1984] or [1832-1865]
X
XExamples:
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XThis is a normal fortune.
X%%
XThis is a credited fortune, with 3 credits.
X		--Credit #1 [Credit #2, 1984]
X%%
XJohns Law:
X	This is a law.
X%%
XJohns Law:
X	This is a credited law.
X		--Bill Johns
X%%
XDEFINITION:
X	This is a definition.
X%%
XCreddef:
X	This is a credited definition.
X		--Joe Schmoe [McCalls, 1984]
X%%
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XWARNING:
X	DO NOT run the standard BSD/USG sorts on the fortune files;
X	Some of them are larger than 1024 bytes.
X
XMISCELLANEOUS:
X	This is the Keith Bostic/Guy Harris memorial fortune file.
X	If you add any fortunes, or, if you have some we don't have,
X	please let us know.  Any problems, feel free to call, we
X	think this works, but hey, what can we say, we'll be glad to bug fix.
X
X	Enjoy...
X	rlgvax!guy@seismo
X	...!seismo!rlgvax!guy
X
X	keith@seismo
X	...!seismo!keith
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
END-of-README
echo x - do_sort
sed 's/^X//' >do_sort << 'END-of-do_sort'
X#! /bin/sh
X#
X# an aggressive little script for sorting the fortune files
X# depends on '\002' and '@' not being anywhere in the files.
X#
X# note:	If you have a fortune file with entries that are more
X#	than 1024 characters long, DON'T use the standard
X#	Bell/Berkeley sort; it silently truncates lines longer
X#	than 1024.
X
Xsp=./sort
X
Xsed 's/^%%$//' | tr '\012' '@' | tr '\002' '\012' | $sp -d -u | sed 'a\
X	%%' | sed -e 's/^@//' -e 's/@$//' | tr '@' '\012'
END-of-do_sort
echo x - fortune.6
sed 's/^X//' >fortune.6 << 'END-of-fortune.6'
X.TH FORTUNE 6 "1 February 1983"
X.UC 4
X.SH NAME
Xfortune \- print a random, hopefully interesting, adage
X.SH SYNOPSIS
X.B /usr/games/fortune
X[
X.B \-
X] [
X.B \-almosw
X]
X..[ -f file ]
X.SH DESCRIPTION
X.I Fortune
Xwith no arguments prints out a random adage. The flags mean:
X.PP
X.TP 5
X.B \-a
XSelect from both standard and potentially offensive messages and limericks.
X.TP 5
X.B \-f
XUse the given file as the fortune file.  This file
Xmust have been created by the program strfile.
X.TP 5
X.B \-l
XSelect from long messages only.
X.TP 5
X.B \-m
XSelect from potentially offensive limericks.
X.TP 5
X.B \-o
XSelect from potentially offensive messages.
X.TP 5
X.B \-s
XSelect from short messages only.
X.TP 5
X.B \-w
XWaits before termination
Xfor an amount of time calculated from the number of characters in the message.
XThis is useful if it is executed as part of the logout procedure
Xto guarantee that the message can be read before the screen is cleared.
X.PP
X.SH FILES
X/usr/games/lib/fortunes.dat
X.SH AUTHOR
XOriginal: Ken Arnold
XPublic Domain: Keith Bostic
END-of-fortune.6
echo x - fortune.c
sed 's/^X//' >fortune.c << 'END-of-fortune.c'
X#include 
X#include 
X#include 
X
X/*
X * produce a fortune from the database
X *	Keith Bostic
X *		ARPA: keith@seismo
X *		UUCP: seismo!keith
X */
X
X#define CPERS		30		/* # of chars for each sec */
X#define MAXTRY		20		/* try 20 times, then fuck it */
X#define MINW		6		/* minimum wait */
X#define SLEN		80		/* # of chars in short fortune */
X#define LLEN		240		/* # of chars in longer fortune */
X#define FFILE		"/usr/games/lib/fortunes.dat"
X
Xmain(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X	extern int	optind;		/* getopt variables */
X	extern char	*optarg;
X	static char	*ffile = FFILE;	/* fortune file */
X	register long	len;		/* length of the fortune */
X	long	bottom,			/* low fortune */
X		num,			/* number of fortunes to choose from */
X		try,			/* random number to try */
X		*seekpts,		/* point to all of table */
X		hold[SECTIONS + 1],	/* hold first part of table */
X		random(), getpid();
X	int	ch;			/* argument character */
X	short	cnt,			/* general counter */
X		do_all = NO,		/* all fortunes */
X		do_lim = NO,		/* limericks */
X		do_long = NO,		/* long fortune */
X		do_off = NO,		/* offensive */
X		do_shrt = NO,		/* short fortune */
X		do_wait = NO;		/* wait afterward */
X	char	*malloc();
X
X	while ((ch = getopt(argc,argv,"af:lmosw")) != EOF)
X		switch((char)ch) {
X			case 'a':	/* obscene, scene, limericks  */
X				do_all = YES;
X				break;
X			case 'f':	/* different fortune file */
X				ffile = optarg;
X				break;
X			case 'l':	/* long */
X				do_long = YES;
X				break;
X			case 'm':	/* limericks */
X				do_lim = YES;
X				break;
X			case 'o':	/* offensive */
X				do_off = YES;
X				break;
X			case 's':	/* short */
X				do_shrt = YES;
X				break;
X			case 'w':	/* wait afterward */
X				do_wait = YES;
X				break;
X			default:
X				fprintf(stderr,"usage: %s [-a] [-f file] [-l] [-m] [-o] [-s] [-w]\n",*argv);
X				exit(ERR);
X		}
X
X	if (!(freopen(ffile,"r",stdin))) {
X		perror(ffile);
X		exit(ERR);
X	}
X	fread(hold,sizeof(*hold),SECTIONS + 1,stdin);
X	if (!(seekpts = (long *)malloc((unsigned)hold[SECTIONS]))) {
X		perror("malloc");
X		exit(ERR);
X	}
X	rewind(stdin);
X	fread(seekpts,sizeof(*seekpts),(hold[SECTIONS] + 1) / sizeof(*seekpts),stdin);
X
X	if (do_all) num = hold[END] - (bottom = hold[SCENE]);
X	else if (do_off)
X		if (do_lim) num = hold[END] - (bottom = hold[OBS]);
X		else num = hold[OBSLIM] - (bottom = hold[OBS]);
X	else if (do_lim) num = hold[END] - (bottom = hold[OBSLIM]);
X	else num = hold[OBS] - (bottom = hold[SCENE]);
X
X	srandom((int)getpid());
X	for (cnt = 0;cnt < MAXTRY;++cnt) {
X		try = random() % num;
X		len = seekpts[bottom + try + 1] - seekpts[bottom + try];
X		if (do_shrt && len > SLEN || do_long && len < LLEN) continue;
X		break;
X	}
X	fseek(stdin,seekpts[bottom + try],(int)0);
X	while (len--) putchar(getchar());
X	if (do_wait) sleep(MAX(len/CPERS,MINW));
X}
END-of-fortune.c
echo x - getopts.c
sed 's/^X//' >getopts.c << 'END-of-getopts.c'
X#include 
X
X/*
X * get option letter from argument vector
X * public domain version of getopt(3), USG.
X *	Keith Bostic
X *		seismo!keith.UUCP
X *		keith@seismo.ARPA
X */
X
Xint	opterr = 1,		/* useless, never set or used */
X	optind = 1,		/* index into parent argv vector */
X	optopt;			/* character checked for validity */
Xchar	*optarg;		/* argument associated with option */
X
X#define BADCH	(int)'?'
X#define EMSG	""
X#define tell(s)	fputs(*nargv,stderr);fputs(s,stderr); \
X		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
X
Xgetopt(nargc,nargv,ostr)
Xint	nargc;
Xchar	**nargv,
X	*ostr;
X{
X	static char	*place = EMSG;	/* option letter processing */
X	register char	*oli;		/* option letter list index */
X	char	*index();
X
X	if(!*place) {			/* update scanning pointer */
X		if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
X		if (*place == '-') {	/* found "--" */
X			++optind;
X			return(EOF);
X		}
X	}				/* option letter okay? */
X	if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
X		if(!*place) ++optind;
X		tell(": illegal option -- ");
X	}
X	if (*++oli != ':') {		/* don't need argument */
X		optarg = NULL;
X		if (!*place) ++optind;
X	}
X	else {				/* need an argument */
X		if (*place) optarg = place;	/* no white space */
X		else if (nargc <= ++optind) {	/* no arg */
X			place = EMSG;
X			tell(": option requires an argument -- ");
X		}
X	 	else optarg = nargv[optind];	/* white space */
X		place = EMSG;
X		++optind;
X	}
X	return(optopt);			/* dump back option letter */
X}
END-of-getopts.c
echo x - strfile.c
sed 's/^X//' >strfile.c << 'END-of-strfile.c'
X#include 
X#include 
X#include 
X
X/*
X * create the database from the various fortune files
X *	Keith Bostic
X *		ARPA: keith@seismo
X *		UUCP: seismo!keith
X */
X
X#define LSIZE		100		/* max single line length */
X
Xmain(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X	extern int	optind;		/* getopts variables */
X	extern char	*optarg;
X	static char	del_str[3] = "%%";	/* delimiter string */
X	register long	*lp,			/* pointer for seek table */
X			*seekpts;		/* seek table */
X	STRF	*spnt;			/* file table */
X	long	len,			/* length of fortune */
X		longest,		/* longest fortune */
X		shortest,		/* shortest fortune */
X		ftell();
X	int	ch,			/* argument character */
X		numforts;		/* total number of fortunes */
X	short	match = NO;		/* flag for empty fortunes */
X	char	ibuf[BUFSIZ],		/* buffer standard input */
X		lbuf[LSIZE],		/* hold each line of fortune */
X		*malloc();
X
X	while ((ch = getopt(argc,argv,"c:")) != EOF)
X		switch((char)ch) {
X			case 'c':	/* new delimiting char */
X				del_str[0] = del_str[1] = *optarg;
X				break;
X			default:
X				fprintf(stderr,"usage: %s [-cC] [-s]\n",*argv);
X				exit(ERR);
X		}
X
X	setbuf(stdin,ibuf);		/* guarantee block buffering */
X
X	/* pass 1: find out how many strings there are */
X
X	for (numforts = 0,spnt = tbl;*spnt->fname;++spnt) {
X		if (access(spnt->fname,F_OK)) {
X			fprintf(stderr,"%s: unable to find the file.\n",spnt->fname);
X			exit(ERR);
X		}
X		if (!(freopen(spnt->fname,"r",stdin))) {
X			perror(spnt->fname);
X			exit(ERR);
X		}
X		while (gets(lbuf))
X			if (!strcmp(lbuf,del_str)) ++numforts;
X	}
X
X	/* save space at beginning of file for tables */
X
X	if (!(freopen(OUTFILE,"w",stdout))) {
X		perror(OUTFILE);
X		exit(ERR);
X	}
X	if (!(seekpts = (long *)malloc((unsigned)(sizeof(long) * numforts)))) {
X		perror("malloc");
X		exit(ERR);
X	}
X
X	fseek(stdout,(long)((SECTIONS + numforts + 1) * sizeof(*seekpts)),0);
X
X	/* write the strings into the file, set offsets */
X
X	lable();
X	for (lp = seekpts + SECTIONS,spnt = tbl;*spnt->fname;++spnt)
X		if (!(freopen(spnt->fname,"r",stdin))) {
X			perror(spnt->fname);
X			exit(ERR);
X		}
X		else {
X			seekpts[spnt->entry] = lp - seekpts;
X			for (*lp = ftell(stdout);gets(lbuf);)
X				if (strcmp(lbuf,del_str)) {
X					puts(lbuf);
X					match = NO;
X				}
X				else if (match) fprintf(stderr,"%s: there is an empty fortune in %s.\n",*argv,spnt->fname);
X				else {
X					match = YES;
X					++lp;
X					len = (*lp = ftell(stdout)) - lp[-1] - 1;
X					if (lp > seekpts + SECTIONS + 1) {
X						if (longest < len) longest = len;
X						else if (shortest > len) shortest = len;
X					}
X					else longest = shortest = len;
X					++spnt->number;
X				}
X			fprintf(stderr,"%d\tfortunes in section %d (%s)\n",spnt->number,spnt->entry + 1,spnt->fname);
X		}
X	seekpts[spnt->entry] = lp - seekpts;
X	fprintf(stderr,"%d\tcharacters in the longest fortune.\n%d\tcharacters in the shortest fortune.\n",longest,shortest);
X
X	/* write the tables into the file */
X
X	rewind(stdout);
X	fwrite(seekpts,sizeof(*seekpts),numforts + SECTIONS + 1,stdout);
X}
X
Xstatic
Xlable()
X{
X	long	thold,
X		time();
X	char	*ctime();
X
X	time(&thold);
X	fputs("==== FORTUNE FILE ==== ",stderr);
X	fputs(ctime(&thold),stderr);
X}
END-of-strfile.c
echo x - strfile.h
sed 's/^X//' >strfile.h << 'END-of-strfile.h'
X#define OUTFILE		"fortunes.dat"	/* standard output file */
X
X#define ERR		-1		/* general error condition */
X#define NO		0		/* general no, false */
X#define YES		1		/* general yes, true */
X
X#define SCENE		0		/* the first is scene fortunes */
X#define OBS		1		/* the second is obscene fortunes */
X#define OBSLIM		2		/* the third is obscene limericks */
X#define END		3		/* end of offsets */
X#define SECTIONS	4		/* number of sections */
X
Xstruct strf {
X	char	*fname;
X	long	entry;
X	int	number;
X};
Xtypedef struct strf STRF;
X
Xstatic STRF	tbl[SECTIONS] = {
X	"scene",	SCENE,		0,
X	"obscene",	OBS,		0,
X	"obs.lim",	OBSLIM,		0,
X	"",		END,		0,
X};
END-of-strfile.h
echo x - unstr.c
sed 's/^X//' >unstr.c << 'END-of-unstr.c'
X#include 
X#include 
X
X/*
X * create the various fortune files from the database file
X *	Keith Bostic
X *		ARPA: keith@seismo
X *		UUCP: seismo!keith
X */
X
Xmain(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X	extern int	optind;			/* getopts variables */
X	extern char	*optarg;
X	static char	del_str[3] = "%%";	/* delimiter string */
X	long	hold[SECTIONS + 1],		/* part of table */
X		off,				/* travel through table */
X		choff,				/* fortune offset */
X		*seekpts;			/* hold table */
X	STRF	*spnt;				/* table structure pointer */
X	int	ch,				/* argument character */
X		cnt;				/* general counter */
X	char	*malloc();
X
X	while ((ch = getopt(argc,argv,"c:")) != EOF)
X		switch((char)ch) {
X			case 'c':	/* new delimiting char */
X				del_str[0] = del_str[1] = *optarg;
X				break;
X			default:
X				fprintf(stderr,"usage: %s [-cC]\n",*argv);
X				exit(ERR);
X		}
X	if (!freopen(OUTFILE,"r",stdin)) {
X		perror(OUTFILE);
X		exit(ERR);
X	}
X
X	/* read the table */
X
X	fread(hold,sizeof(*hold),SECTIONS + 1,stdin);
X	if (!(seekpts = (long *)malloc((unsigned)hold[SECTIONS]))) {
X		perror("malloc");
X		exit(ERR);
X	}
X	rewind(stdin);
X	fread(seekpts,sizeof(*seekpts),(hold[SECTIONS] + 1) / sizeof(*seekpts),stdin);
X
X	/* go to the first fortune */
X
X	fseek(stdin,seekpts[*seekpts],(long)0);
X
X	/* read the fortunes */
X
X	for (spnt = tbl;*spnt->fname;++spnt) {
X		if (!freopen(spnt->fname,"w",stdout)) {
X			perror(spnt->fname);
X			exit(ERR);
X		}
X		for (cnt = 0,off = seekpts[spnt->entry];off < seekpts[spnt->entry + 1];++off,++cnt) {
X			for (choff = seekpts[off];choff < seekpts[off + 1];++choff)
X				putchar(getchar());
X			puts(del_str);
X		}
X		fprintf(stderr,"%d\tfortunes placed in %s.\n",cnt,spnt->fname);
X	}
X}
END-of-unstr.c
exit