jeff@alberta (Curt J. Sampson @ his home computer) (02/25/85)
This is a version of fortune that I wrote. It allows multiple line fortunes, and uses an indexed fortune file to speed it up. To install it, simply su root (or games, if you use a seperate id) and type `make install'. I have included a few fortunes, but you will probably want to add more yourself. If you are using a C compiler with fewer than 12 character identifiers, you will have to change the names of a few of the variables. Otherwise it should run anywhere. I have tested it on a VAX-11/780 running 4.2 BSD and an Altos 586 running XENIX. Send any bug reports, etc. to me. ===================================================================== Curt Sampson ihnp4!alberta!jeff --------------------------------------------------------------------- -------------------------- TEAR HERE ---------------------------- # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # Makefile READ_ME fortune.6 fortune.c fortune.h fortunes makefortunes.6 makefortunes.c echo x - Makefile cat > "Makefile" << '//E*O*F Makefile//' # # Makefile for `fortune' # # by Curt Sampson # v1.0 1 Feb. 1985 # DEST=/usr/games LIB=/usr/games/lib MAN=/usr/man/man6 FORTUNES=${LIB}/fortunes.dat all: fortune makefortunes fortune: fortune.h fortune.o cc fortune.o -o fortune -DFORTUNEFILE=${FORTUNES} makefortunes: fortune.h makefortunes.o cc makefortunes.o -o makefortunes install: all mv fortune ${DEST} mv makefortunes ${LIB} mv fortune.6 ${MAN} ${LIB}/makefortunes ${FORTUNES} fortunes clean: -rm *.o //E*O*F Makefile// echo x - READ_ME cat > "READ_ME" << '//E*O*F READ_ME//' This is a version of the UNIX(tm) `fortune' program. It dispenses small snippets of wisdom every time it is called. I have set it up so that it uses and indexed file to speed things up and allow multi-line fortunes. To set up an indexed file of fortunes, say `makefortune fortunes.dat fortunes'. It will take the fortunes in `fortunes', index them, and put them in `fortunes.dat'. If you wish to use your own file in place of `fortunes', simply type in the fortunes and seperate them with a line that has only a period (`.') on it. You may use blank lines, and the like, but do not use the fortune seperation character (normally '\001' or Control-A). Then just install it and run. You may use a private fortune file by giving fortune the filename as an argument. Send bugs, fixes, questions, etc. to the address below. That's about it. Have fun! Curt J. Sampson ihnp4!alberta!jeff //E*O*F READ_ME// echo x - fortune.6 cat > "fortune.6" << '//E*O*F fortune.6//' .TH FORTUNE 6 "1 February 1985" .SH NAME fortune \- print a random, hopefully interesting, adage .SH SYNOPSIS .B /usr/games/fortune [ file ] .SH DESCRIPTION .I Fortune with no arguments prints out a random adage. The argument `file' uses an alternate list of fortunes supplied by the user. .SH FILES /usr/games/lib/fortunes.dat default fortunes file .SH AUTHOR Curt J. Sampson .br ihnp4!alberta!jeff .SH SEE\ ALSO makefortunes(6) //E*O*F fortune.6// echo x - fortune.c cat > "fortune.c" << '//E*O*F fortune.c//' /* * fortune.c * * by Curt Sampson * v0.1 1 Feb. 1984 * * Usage: * fortune [file] * * This will pick a random fortune out of a fortunes file or <file> if * specified and print it. The fortunes file must be indexed by * `makefortunes'. * */ #include "fortune.h" main(argc, argv) int argc; char *argv[]; { FILE *fortunefile; /* file of fortunes */ int fortune; /* fortune selected */ long offset, /* offset of fortune into file */ numfortunes; /* number of fortunes */ char c; /* for the fortune itself */ if ( argc > 2 ) { puts("Usage: fortune [ file ]"); exit(1); } /* open file */ if ( argc == 2 ) { /* use argument as file */ if ( (fortunefile = fopen(argv[1], "r")) == NULL ) { fprintf(stderr, "fortune: can't open %s\n", argv[1]); exit(1); } } else { /* use default file */ if ( (fortunefile = fopen(FORTUNEFILE, "r")) == NULL ) { fputs("fortune: can't open fortunes file", stderr); exit(1); } } /* find out how many fortunes there are */ if ( fread(&numfortunes, sizeof(numfortunes), 1, fortunefile) == 0 ) { fputs("fortune: can't read fortunes", stderr); exit(1); } /* seed random number generator and get random fortune number */ (void) srand((int) time()); fortune = rand() % numfortunes; /* find offset into fortune file */ if ( fseek(fortunefile, (long)(fortune * sizeof(offset)), 1) == -1 ) { fputs("fortune: offset seek failed", stderr); exit(1); } if ( fread(&offset, sizeof(offset), 1, fortunefile) == NULL ) { fputs("fortune: offset read failed", stderr); exit(1); } /* get to the end of the offset info */ if ( fseek(fortunefile, (long)(((numfortunes - 1) - fortune) * sizeof(offset)), 1) == -1 ) { fputs("fortune: offset reseek failed", stderr); exit(1); } /* find the fortune */ if ( fseek(fortunefile, (long) offset, 1) == -1 ) { fputs("fortune: fortune seek failed", stderr); exit(1); } /* print the fortune */ while ( (c = getc(fortunefile)) != ENDOFFORTUNE ) putchar(c); (void) fclose(fortunefile); (void) exit(0); } //E*O*F fortune.c// echo x - fortune.h cat > "fortune.h" << '//E*O*F fortune.h//' #include <stdio.h> #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define ENDOFFORTUNE '\001' #define TXTENDOFFORTUNE ".\n" #define LINELEN 1024 #ifndef FORTUNEFILE #define FORTUNEFILE "/usr/games/lib/fortunes.dat" #endif //E*O*F fortune.h// echo x - fortunes cat > "fortunes" << '//E*O*F fortunes//' Q: What's the difference between a Mac and an Etch-a-Sketch? A: You don't have to shake the Mac to clear the screen. . Reactor error - core dumped! . Help! I'm trapped inside a DEC PDP-11! . !11-PDP CED a edisni deppart m`I !pleH . This is a fill in the blank fortune: ________________________________________. . Don't burn your chickens before you cross the road. . If at first you don't succeed, redefine success. . Arithmetic is being able to count up to twenty without taking off your shoes. -- Mickey Mouse . The human animal differs from the lesser primates in his passion for lists of "Ten Best". -- H. Allen Smith . Parkinson's Fifth Law: If there is a way to delay in important decision, the good bureaucracy, public or private, will find it. . Two Observations on English Grammer: 1) People tend to carelessly split infinitives. 2) A preposition is a bad thing to end a sentence with. . Hofstadter's Law: It always takes longer than you expect, even if you take Hofstadter's Law into account. . Jones' First Law: Anyone who makes a significant contribution to any field of endeavor, and stays in that field long enough, becomes an obstruction to its progress -- in direct proportion to the importance of their original contribution. . If the odds are a million to one against something occurring, chances are 50-50 it will. . If you think the pen is mightier than the sword, the next time someone pulls out a sword I'd like to see you get up there with your Bic... . What this country needs is a good five-cent nickel. . What this country needs is a good five-cent anything! . "It looked like something resembling white marble, which was probably what is was: something resembling white marble." -- Douglas Adams, "The Hitchhikers Guide to the Galaxy" . "Only great masters of style can succeed in being obtuse." -- Oscar Wilde "Most UNIX programmers are great masters of style." -- Unnamed Usenetter . "Nothing lasts forever." "Where do I find nothing?" . I'm sorry, but my kharma just ran over your dogma. . May you live in interesting times. -- Ancient Chinese Curse . We'll be recording at the Paradise Friday night. Live, on the Death label. . This is fortune pledge week. If you read this fortunes, why don't you mail in a contribution to `fortune'. Just to show you some of the really good fortunes we have coming up... . ROMEO: Courage, man; the hurt cannot be much. MERCUTIO: No, 'tis not so deep as a well, nor so wide as a church- door; but 'tis enough, 'twill serve. . Bus error -- please leave by the rear door. . //E*O*F fortunes// echo x - makefortunes.6 cat > "makefortunes.6" << '//E*O*F makefortunes.6//' .TH MAKEFORTUNES 6 .SH NAME makefortunes \- create an indexed file for fortune(6) .SH SYNOPSIS .B /usr/games/lib/makefortunes output input .SH DESCRIPTION .I makefortunes creates an indexed file that can be used by fortune(6). .I output will be the indexed file. .I input should consist of fortunes seperated by lines with only a period ('.'). Special characters and blank lines may be used freely with the execption of the end-of-fortune character, which is normally '\\001' or control-A. .SH AUTHOR Curt J. Sampson .br ihnp4!alberta!jeff .SH SEE\ ALSO fortune(6) //E*O*F makefortunes.6// echo x - makefortunes.c cat > "makefortunes.c" << '//E*O*F makefortunes.c//' /* * makefortunes.c * * by Curt Sampson * v0.1 1 Feb. 1985 * * Usage: * makefortunes <output> <fortunes> * * This program will take the contents of the file <fortunes> and * build a new file <output> that has an index and the fortunes in * it so that a fast lookup can be made by `fortune'. The <fortunes> * file should have the individaul fortunes seperated by a line with * only a period on it. * */ #include "fortune.h" main(argc, argv) int argc; char *argv[]; { char *mktemp(); /* declare library functions */ char inputfilname[25], /* input and output file names */ outputfilname[25], tmptxtfilname[25], /* tempory files for fortunes */ tmpindxfilname[25]; /* and index */ FILE *inputfil, /* pointers to files for fread() */ *outputfil, *tmptxt, *tmpindx; long offset, /* count of offset of fortunes */ numfortunes; /* number of fortunes */ int fortlen; /* length of current fortune */ if ( argc != 3 ) { fputs("Usage: makefortunes <output> <fortunes>\n", stderr); exit(1); } /* construct file names */ (void) strcpy(outputfilname, argv[1]); (void) strcpy(inputfilname, argv[2]); (void) strcpy(tmptxtfilname, (void) mktemp("/tmp/forfXXXXXX")); (void) strcpy(tmpindxfilname, (void) mktemp("/tmp/foriXXXXXX")); /* open files needed */ if ( (inputfil = fopen(inputfilname, "r")) == NULL ) { fprintf(stderr, "makefortunes: can't open %s\n", inputfilname); exit(1); } (void) unlink(tmptxtfilname); if ( (tmptxt = fopen(tmptxtfilname, "a")) == NULL ) { puts("makefortunes: can't create temporary text file", stderr); exit(1); } (void) unlink(tmpindxfilname); if ( (tmpindx = fopen(tmpindxfilname, "a")) == NULL ) { puts("makefortunes: can't create temporary index file", stderr); exit(1); } /* copy the fortunes and determine the offsets */ offset = 0; numfortunes = 0; while ( (fortlen = getnextfortune(inputfil, tmptxt)) != 0 ) { /* write offset */ fwrite(&offset, sizeof(offset), 1, tmpindx); offset += fortlen; ++numfortunes; } /* close files and reopen for reading */ if ( (fclose(inputfil)) == EOF ) { fprintf(stderr, "makefortunes: can't close %s\n", inputfilname); exit(1); } if ( (fclose(tmptxt)) == EOF ) { fputs("makefortunes: can't close temporary text file", stderr); exit(1); } if ( (fclose(tmpindx)) == EOF ) { fputs("makefortunes: can't close temporary index file", stderr); exit(1); } if ( (tmptxt = fopen(tmptxtfilname, "r")) == NULL ) { puts("makefortunes: can't open temporary text file", stderr); exit(1); } if ( (tmpindx = fopen(tmpindxfilname, "r")) == NULL ) { puts("makefortunes: can't open temporary index file", stderr); exit(1); } /* now write main fortunes file */ (void) unlink(outputfilname); if ( (outputfil = fopen(outputfilname, "a")) == NULL ) { /* create */ fprintf(stderr, "makefortunes: can't create %s\n", outputfilname); exit(1); } if ( fwrite(&numfortunes, sizeof(numfortunes), 1, outputfil) == 0 ) { fputs("makefortunes: can't write number of fortunes", stderr); exit(1); } if ( (fclose(outputfil)) == EOF ) { fprintf(stderr, "makefortunes: can't close %s\n",outputfilname); exit(1); } if ( (append(outputfilname, tmpindxfilname)) == 1 ) { fprintf(stderr, "makefortunes: can't append temporary\ index file to %s", outputfilname); exit(1); } if ( (append(outputfilname, tmptxtfilname)) == 1 ) { fprintf(stderr, "makefortunes: can't append temporary\ text file to %s", outputfilname); exit(1); } /* all done! */ exit(0); } /* * getnextfortune(infile, out) * * gets next fortune from <infile>, writes it to <outfile> with a ENDOFFORTUNE * after it, and returns the length of the fortune including the ENDOFFORTUNE. * It returns 0 if no more fortunes are left. * Fortune in <infile> has TXTENDOFFORTUNE on a line alone to signify its end. */ int getnextfortune(inputfile, outputfile) FILE *inputfile, *outputfile; { int len, /* length of fortune */ done; char inputline[LINELEN]; /* input line */ len = 0; if ( (fgets(inputline, LINELEN, inputfile)) == NULL ) return(0); done = FALSE; while ( ! done ) { if (strcmp(inputline, TXTENDOFFORTUNE) == 0) { done = TRUE; continue; } len += strlen(inputline); fputs(inputline, outputfile); if ( (fgets(inputline, LINELEN, inputfile)) == NULL ) { done = TRUE; continue; } } putc(ENDOFFORTUNE, outputfile); len += 1; return(len); } /* * append(to, from) * * appends the file <from> to the file <to> * returns 0 if successful, 1 if an error occurs */ int append(toname, fromname) char *toname, *fromname; { char cmd[128]; /* command to execute via system() */ sprintf(cmd, "cat %s >>%s", fromname, toname); if ( (system(cmd)) == 127 ) return(1); return(0); } //E*O*F makefortunes.c// exit 0
keith@seismo.UUCP (Keith Bostic) (03/03/85)
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 <stdio.h> X#include <sys/param.h> X#include <strfile.h> 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 <stdio.h> 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 <stdio.h> X#include <sys/file.h> X#include <strfile.h> 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 <stdio.h> X#include <strfile.h> 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