[alt.sources] karl's public domain fortune cookie program

karl@sugar.uu.net (Karl Lehenbauer) (01/13/89)

Below is a shar archive of my fortune cookie program.  It has not changed
since its first release about a year ago.  Following this posting will
be the fortune cookie data file, split up into six parts. It has grown
substantially since its first release, plus I fixed typos throughout.

You may of course add your own cookies to the file or create your own cookie 
file.

-karl

--------------------- cut here ---------------------
:
#! /bin/sh
# This is a shell archive, created on Sugar Land Unix (..!uunet!sugar)
# (bbs: 713-438-5018) by karl (Karl Lehenbauer) on Thu Jan 12 19:59:01 1989
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file".  If you do not have sh, you need 
# unshar, a dearchiving program which is widely available.  In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'README'
# 'makefile'
# 'cookie.h'
# 'cookie.c'
# 'cookhash.c'
# To extract them, run the following through /bin/sh
echo x - README
sed 's/^X//' > README << '//END_OF_FILE'
X
XThe second release of Karl's fortune cookie program, with cookies...  12-Jan-89
X-------------------------------------------------------------------------------
X
XActually, the cookie file contains fortune cookies, sayings, jokes, aphorisms,
Xquotes and so on.  Those likely to be offended by words and ideas that are
Xalien to them are asked to not read the cookie file.
X
XThe code and cookies are released into the public domain without restriction.
XI ask that you retain my name in the source code if you redistribute this stuff,
Xand that you redistribute source along with binaries.
X
XNo warranties are expressed or implied -- this is free code.  We do not have
Xa contract.
X
XThe code is written for System V but the only area of incompatibility should be
Xthe rand() function.  Only minor hacking should be necessary to port to BSD,
Xfor example.
X
XTo use, unshar this archive and do a 'make' to compile 'cookie' and 'cookhash'.
XCollect the six parts of the cookie file, strip off the headers and trailers,
Xand 'cat' them (in proper order) into one file.  The include file "cookie.h"
Xdefines the location of the cookie file as being "/usr/local/lib/sayings".
XIf you want to put it elsewhere, change cookie.h and rebuild 'cookie'.
X
XCookie needs a hash file for the cookie file, by default called
X"/usr/local/lib/sayhash".  This is created by the 'cookhash' program.
XCookhash is simply a filter that reads a cookie file in as stdin and writes
Xa cookie hash file to stdout.  (Cookies are delineated in the cookie file
Xby a line containing two percent signs and nothing else.)  Thus, if you've
Xmoved the cookie file to /usr/local/lib, 'cd' there and do a
X"cookhash <sayings >sayhash" to create the hash file.
X
XAfter that, 'cookie' should produce a cookie.  Cookie can also be executed
Xwith two arguments, the name of a cookie file followed by the name of
Xits hash file.
X
XIf you find quotes in the file that are unattributed and you know the
Xattributions, please mail them to karl@sugar.uu.net or uunet!sugar!karl
X
XRegards,
Xkarl @ The Hacker's Haven, Missouri City, Texas -- 12-Jan-89
//END_OF_FILE
echo x - makefile
sed 's/^X//' > makefile << '//END_OF_FILE'
X# makefile for karl's PD fortune cookie program
X
Xall:	cookie cookhash
X
Xcookie:	cookie.h
X	cc -o cookie cookie.c
X
Xcookhash:
X	cc -o cookhash cookhash.c
//END_OF_FILE
echo x - cookie.h
sed 's/^X//' > cookie.h << '//END_OF_FILE'
X/* cookie.h - include file for karl's PD fortune cookie program 
X * by Karl Lehenbauer (karl@sugar.uu.net, uunet!sugar!karl)
X * cookie.h 1.1 1/12/89
X */
X
X#define COOKIEFILE "/usr/local/lib/sayings"
X#define HASHFILE "/usr/local/lib/sayhash"
X
X/* end of cookie.h */
//END_OF_FILE
echo x - cookie.c
sed 's/^X//' > cookie.c << '//END_OF_FILE'
X/* cookie - print out an entry from the sayings file
X * by Karl Lehenbauer (karl@sugar.uu.net, uunet!sugar!karl)
X *  cookie.c  1.1  1/12/89
X */
X
X#include <stdio.h>
X#include "cookie.h"
X
X#define ENTSIZE 7L
X#define METACHAR '%'
X#define YES 1
X#define NO 0
X
Xchar *sccs_id = "@(#) fortune cookie program 1.1 1/12/89 by K. Lehenbauer";
X
Xextern long lseek(), time();
Xextern int rand();
X
Xchar *cookiename = COOKIEFILE;
Xchar *hashname = HASHFILE;
X
X/* really_random - insure a good random return for a range, unlike an arbitrary
X * random() % n, thanks to Ken Arnold, Unix Review, October 1987
X * ...likely needs a little hacking to run under Berkely
X */
X#define RANDOM_RANGE ((1 << 15) - 1)
Xint really_random(my_range)
Xint my_range;
X{
X	int max_multiple, rnum;
X
X	max_multiple = RANDOM_RANGE / my_range;
X	max_multiple *= my_range;
X	while ((rnum = rand()) >= max_multiple)
X		continue;
X	return(rnum % my_range);
X}
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	int nentries, oneiwant, c, sawmeta = 0;
X	FILE *hashf, *cookief;
X	long cookiepos;
X
X	/* if we got exactly three arguments, use the cookie and hash
X	 * files specified
X	 */
X	if (argc == 3)
X	{
X		cookiename = argv[1];
X		hashname = argv[2];
X	}
X	/* otherwise if argc isn't one (no arguments, specifying the
X	 * default cookie file), barf
X	 */
X	else if (argc != 1)
X	{
X		fputs("usage: cookie cookiefile hashfile\n",stderr);
X		exit(1);
X	}
X
X	/* open the cookie file for read */
X	if ((cookief = fopen(cookiename,"r")) == NULL)
X	{
X		perror(cookiename);
X		exit(2);
X	}
X
X	/* open the hash file for read */
X	if ((hashf = fopen(hashname,"r")) == NULL)
X	{
X		perror(hashname);
X		exit(2);
X	}
X
X	/* compute number of cookie addresses in the hash file by
X	 * dividing the file length by the size of a cookie address
X	 */
X	if (fseek(hashf,0L,2) != 0)
X	{
X		perror(hashname);
X		exit(3);
X	}
X	nentries = ftell(hashf) / 7L;
X
X	/* seed the random number generator with time in seconds plus
X	 * the program's process ID - it yields a pretty good seed
X	 * again, thanks to Ken Arnold
X	 */
X	srand(getpid() + time(NULL));
X
X	/* generate a not really random number */
X	oneiwant = really_random(nentries);
X
X	/* locate the one I want in the hash file and read the
X	 * address found there
X	 */
X	fseek(hashf,(long)oneiwant * ENTSIZE, 0);
X	fscanf(hashf,"%lx",&cookiepos);
X
X	/* seek cookie file to cookie starting at address read from hash */
X	fseek(cookief,cookiepos,0);
X
X	/* get characters from the cookie file and write them out
X	 * until finding the end-of-fortune sequence, '%%'
X	 */
X	while ((c = fgetc(cookief)) != EOF && sawmeta < 2)
X	{
X		if (c != METACHAR)
X		{
X			if (sawmeta)
X				putchar(METACHAR);
X			putchar(c);
X			sawmeta = 0;
X		}
X		else
X			sawmeta++;
X	}
X	exit(0);
X}
X
X/* end of cookie.c */
//END_OF_FILE
echo x - cookhash.c
sed 's/^X//' > cookhash.c << '//END_OF_FILE'
X/* cookhash - read a sayings file and generate an index file
X * by Karl Lehenbauer (karl@sugar.uu.net, uunet!sugar!karl)
X *  cookhash.c  1.1  1/12/89
X */
X
X#include <stdio.h>
X
X#define YES 1
X#define NO 0
X#define METACHAR '%'
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	int c, sawmeta;
X	long charpos = 0;
X
X	if (argc != 1)
X	{
X		fprintf(stderr,"usage: cookhash <cookiefile >hashfile\n");
X		exit(1);
X	}
X
X	/* write out the "address" of the first cookie */
X	puts("000000");
X
X	/* read the cookie until the end,
X	 *   whenever the end-of-cookie ("%%") sequence is found,
X	 *   the "address" (file position) of the first byte following
X	 *   it (start of next cookie) is written to the index (hash) file
X	 */
X	while ((c = getchar()) != EOF)
X	{
X		if (c == METACHAR)
X		{
X			if (sawmeta)
X			{
X				printf("%06lx\n",charpos+2);
X				sawmeta = NO;
X			}
X			else
X				sawmeta = YES;
X		}
X		else
X			sawmeta = NO;
X		charpos++;
X	}
X	exit(0);
X}
X
X/* end of cookhash.c */
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0
-- 
-- uunet!sugar!karl  | "We've been following your progress with considerable 
-- karl@sugar.uu.net |  interest, not to say contempt."  -- Zaphod Beeblebrox IV
-- Usenet BBS (713) 438-5018