Path: utzoo!attcan!uunet!husc6!bloom-beacon!mit-eddie!uw-beaver!tektronix!tekgen!tekred!games From: games@tekred.TEK.COM Newsgroups: comp.sources.games Subject: v04i015: cookie - another fortune cookie program, Part01/03 Message-ID: <2543@tekred.TEK.COM> Date: 20 May 88 22:35:13 GMT Sender: billr@tekred.TEK.COM Lines: 329 Approved: billr@saab.CNA.TEK.COM Submitted by: uunet.uu.net!nuchat!sugar!karl (Karl Lehenbauer) Comp.sources.games: Volume 4, Issue 15 Archive-name: cookie/Part01 [Although not as extensive as fortune(6), this program is smaller. It runs OK on my Sun 3/60. -br] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh MANIFEST <<'END_OF_MANIFEST' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 This shipping list X Makefile 1 X README 1 X cookhash.c 1 X cookie.c 1 X cookie.h 1 X cookies.aa 2 X cookies.ab 3 END_OF_MANIFEST if test 354 -ne `wc -c README <<'END_OF_README' XCookie programs and cookie file X------------------------------- X XVersion 0.0, By Karl Lehenbauer, 4/7/88 X XYet another fortune cookie program... The main thing that makes this Xone interesting is the cookie file, which is abundantly full of quotes, Xcookies and such, of varying quality and accuracy. In particular, Xit has many good quotes about software engineering, humanism, church Xand state, and the human condition. X XThe only machine that it for sure works on is a PC/AT clone running XMicroport System V/AT. It should, however, work perfectly well on Xother System V systems. To run under BSD, really_random() needs to Xbe twiddled. Similarly small efforts should be required to get it Xto run under V7, MS-DOS, etc. X XTo use, set the paths for the cookie and cookie hash files in cookie.h Xthen move the cookie file, "cookies", to its final resting place. X XCompile and link cookie.c and cookhash.c "make" should do it. X XGenerate the hash file to go along with the cookies, something like: Xcookhash cookie.hash X X$ cookie X XDirect flames, kudos and questions to X ..!{uunet!nuchat}|{bellcore!tness1}!sugar!karl END_OF_README if test 1126 -ne `wc -c Makefile <<'END_OF_Makefile' X# makefile for cookie program 4/8/88 remote from sugar X Xall: cookie cookhash cookies X Xcookie: cookie.c X cc -O -o cookie cookie.c X Xcookhash: cookhash.c X cc -O -o cookhash cookhash.c X Xcookies: cookies.aa cookies.ab X cat cookies.aa cookies.ab >cookies END_OF_Makefile if test 251 -ne `wc -c cookie.h <<'END_OF_cookie.h' X/* cookie.h - include file for karl's cookie program */ X X#define COOKIEFILE "/usr/local/lib/cookies" X#define HASHFILE "/usr/local/lib/cookie.hash" X X/* end of cookie.h */ END_OF_cookie.h if test 170 -ne `wc -c cookhash.c <<'END_OF_cookhash.c' X/* cookhash - read a sayings file and generate an index file */ X/* %M% %I% %H% */ X X#include 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 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_cookhash.c if test 875 -ne `wc -c cookie.c <<'END_OF_cookie.c' X/* cookie - print out an entry from the sayings file */ X/* %M% %I% %H% */ X X#include 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 %I% %H% 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 fputs("cookie: fseek failed\n",stderr); 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_cookie.c if test 2654 -ne `wc -c