/* C O O K I E * * Print a random cookie. * */ /*)BUILD */ #ifdef DOCUMENTATION title cookie Print a Random Message index Print a Random Message synopsis cookie [options] description Cookie prints a fortune cookie. The options are: .lm +8 .s.i- 8;-N Output N cookies. .s.i- 8;N Output the Nth cookie. .s.i- 8;-a Output all cookies in entry order. cookie -a -a appends %% to each cookie (so that the output file may be fed back to coobld). .s.i -8;-f file Read cookies from this file. (Ignore search list.) .s.i- 8;-h Eliminate Heinlien and Lazarus Long cookies .s.i- 8;-v Video mode -- Format for a VT52 or VT100 (VT100 assumed). .s.i- 8;-vt52 Explicitly format for a VT52 or VT100 in VT52 mode .s.i- 8;-vt100 Explicitly format for a VT100 in ANSI mode .s.i- 8;-c Continuous -- give lots of random cookies .s.i- 8;-s N Continuous with specified sleep interval. This may also be specified "-sN". If no number is given, "-s 60" will be assumed. .s.i- 8;/HEINLIEN=NO##Same as -h, but for VMS systems .s.lm -8 To enable elimination of cookies by Robert A. Heinlien and his alter ego Lazarus Long, define "NOHEINLIEN". If eliminated, a suitable anticookie will be presented. .s Cookie uses the following search list to locate the cookie file: .s.nf []cookie.fil sys_cookie:cookie.fil public:cookie.fil pub:cookie.fil sys$public:cookie.fil games:cookie.fil sys$games:cookie.fil _dbb1:[game]cookie.fil .s.f author Martin Minow bugs #endif #define NOHEINLIEN 1 #include #define EOS 0 #define TRUE 1 #define FALSE 0 #ifdef rsx #define R_MODE "run" #else #ifdef rt11 #define R_MODE "rn" #else #define R_MODE "r" #endif #endif int $$narg = 1; /* No argv> prompt */ extern int $$rsts; extern long rand(); extern long seed; extern long time(); #define EOS 0 int doall = 0; int video = 0; int isvt52 = 0; int notLong = 0; /* nor Heinlien */ int continuous = 0; int long_sleep = 0; int cur_line = 0; int linecount = 0; char *old_buff = NULL; char sc_buff[121]; char temp_text[81]; FILE *cookfd = NULL; char *cookfile[] = { /* Cookie search list */ "cookie.fil", /* Current directory first */ "sys_cookie:cookie.fil", /* Default cookie directory */ "public:cookie.fil", /* Various */ "pub:cookie.fil", /* public */ "sys$public:cookie.fil", /* directories */ "games:cookie.fil", /* Some */ "game:cookie.fil", /* games */ "sys$games:cookie.fil", /* directories */ "_dbb1:[game]cookie.fil", /* PHENIX games directory */ NULL, }; struct header { long ncookie; /* Number of cookies */ int nindex; /* Dimension of index[] */ int subindex; /* Number of subindex entries */ int sindex; /* Sizeof index for alloc */ char date[28]; /* Date cookie file built */ } header; #define NCOOKIES (header.ncookie) #define TEXTSIZE 2048 #define INDEXMAX (TEXTSIZE / sizeof (long)) union { char text[TEXTSIZE]; /* Cookies stored here */ long index[INDEXMAX]; /* Cookie sub index entries */ } t; /* * If only one cookie is needed, topindex[] can be overlayed over t.index[] */ long topindex[INDEXMAX]; /* Top index entries */ main(argc, argv) int argc; char *argv[]; { register int howmany; /* How many to do */ register char *ap; register int outtime; long which; long atol(); which = 0; while (argc > 1) { ap = argv[1]; if (isdigit(*ap) || (*ap == '-' && isdigit(ap[1]))) which = atol(ap); else if (*ap != '-') { #ifdef NOHEINLIEN if (streq(ap, "/HEINLIEN=NO") || streq(ap, "/heinlien=no")) notLong++; else #endif fprintf(stderr, "?Unknown command \"%s\"\n", ap); } else for (ap++; *ap; ap++) { switch (tolower(*ap)) { case 'a': doall++; break; case 'c': continuous++; break; case 'f': if ((cookfd = fopen(argv[2], R_MODE)) == NULL) { perror(argv[2]); exit(IO_ERROR); } argv++; argc--; goto next_arg; #ifdef NOHEINLIEN case 'h': notLong++; /* No (Lazarus) Longs */ break; #endif case 's': /* Long sleep */ continuous++; if (isdigit(ap[1])) { long_sleep = atoi(&ap[1]); } else if (isdigit(argv[2][0])) { long_sleep = atoi(argv[2]); argv++; /* Skip next argument */ argc--; /* too. */ } else { long_sleep = 60; break; } goto next_arg; case 'v': video = 1; if (tolower(ap[1]) == 't') { video = atoi(&ap[2]); if (video == 52) isvt52 = 1; else if (video == 100) isvt52 = 0; else fprintf(stderr, "?Unknown video \"%s\"\n", ap); while (*ap) ap++; } break; default: fprintf(stderr, "?Unknown option '%c'\n", *ap); } } next_arg: argc--; argv++; } init(); /* Setup random number */ setup_cookie(); if (video) erpage(1, 1); if (doall) { for (which = 1; which <= NCOOKIES; which++) { docookie(which); } } if (continuous) which = -1; if (which > 0) { if (which > NCOOKIES) { sprintf(t.text, "Misfortune: there are only %ld cookies.\n", NCOOKIES); output(which, t.text); } else docookie(which); } else { if ((howmany = -which) == 0) howmany = 1; while (howmany-- > 0) { which = irand((int) NCOOKIES); docookie(which + 1); if (continuous) howmany = 1; if (howmany > 0) { sleep((long_sleep > 0) ? long_sleep : (linecount + 1) * 2); } } } } int irand(max) int max; /* * Rand mod max */ { long temp; temp = rand(); temp = temp ^ (temp >> 16); temp &= 32767; temp *= max; return ((int) (temp / 32768L)); } init() /* * Initialize random number generator */ { union { long lvec; /* For time of day */ int ivec[2]; } tbuf; register int i; register int j; time(&tbuf.lvec); /* Setup random number */ seed = tbuf.lvec; j = rand(0); i = rand(0); i = i ^ (~tbuf.ivec[0] ^ tbuf.ivec[1]); /* random number */ i = (j ^ i) & 15; /* generator */ do { /* call rand() 1 .. 16 */ rand(); /* times. */ } while (i-- > 0); } setup_cookie() /* * Initialize cookie file, finding it in the search list */ { register char **namep; register int temp; if (cookfd == NULL) { for (namep = cookfile; *namep != NULL; namep++) { if ((cookfd = fopen(*namep, R_MODE)) != NULL) break; } if (cookfd == NULL) error("Can't open cookie file\n"); } #ifdef rsx if ((temp = fget(&header, sizeof header, cookfd)) != sizeof header) rerror(sizeof header, temp, "Reading header file"); if ((temp = fget(&topindex, header.sindex, cookfd)) != header.sindex) rerror(header.sindex, temp, "Reading top-level index"); #else if ((temp = fread(&header, sizeof header, 1, cookfd)) != 1) rerror(sizeof header, temp, "Reading header file"); if ((temp = fread(&topindex, header.sindex, 1, cookfd)) != 1) rerror(header.sindex, temp, "Reading top-level index"); #endif } rerror(expected, got, why) int expected; /* Bytes in item */ int got; /* Unexpectedly isn't == 1 */ char *why; /* * Fatal read error */ { perror(why); #ifdef rsx fprintf(stderr, "expected %d bytes, read %d bytes\n", expected, got); #else fprintf(stderr, "expected 1 item of %d bytes, read %d items\n", expected, got); #endif /* error("Can't continue"); */ } docookie(which) long which; /* * Read and output the Nth cookie. Note: 1-origin addressing */ { long index; long temp; register int bytect; register int i; register char *tp; which--; temp = header.nindex; temp = which / temp; i = temp; if (i >= header.subindex) error("Bug: Gone too far, index = %d, max = %d\n", i, header.subindex); index = topindex[i]; if (fseek(cookfd, index, 0) != 0) error("Can't seek to top_index at %ld, error = %06o\n", index, $$ferr); $$ferr = 0; #ifdef rsx if ((bytect = fget(&t.index, header.sindex, cookfd)) != header.sindex) { #else if ((bytect = fread(&t.index, header.sindex, 1, cookfd)) != 1) { #endif fprintf(stderr, "seek to sub-index %d, %ld. %06o %06o\n", i, index, index); rerror(header.sindex, bytect, "Can't read sub_index"); } temp = header.nindex; temp = which % temp; i = temp; index = t.index[i]; if (fseek(cookfd, index, 0) != 0) { fprintf(stderr, "?Can't seek to cookie at %ld, code = %06o: ", index, $$ferr); perror("minor index seek"); error("?Requesting cookie %ld, max = %ld\n", which, header.ncookie); return; } tp = &t.text[0]; #ifdef rsx while (fget(tp, (sizeof t.text) - (tp - t.text), cookfd) > 0 #else while (fgets(tp, (sizeof t.text) - (tp - t.text), cookfd) != NULL #endif && !feof(cookfd) && tp[0] != '%' && tp[1] != '%') { tp += strlen(tp); } *tp = EOS; /* Remove trailing %% */ if (feof(cookfd)) { rerror(tp - t.text, tp - t.text, "Can't read cookie"); } if (notLong && isLong(t.text)) antiheinlien(which + 1); else output(which + 1, &t.text); } static char *anti1[] = { "A Heinlien Cookie you do distain,\n\ I'll say no more to soothe your brain.", "I'd rather drink a gallon of overage Rhine wine,\n\ Than read a quote by Robert A. Heinlien.", "I'd rather bite boils from an elephant's behind,\n\ Than read more quotes by Robert A. Heinlien.", "*I'd rather a tax audit found me wrong,", "*I'd rather be dribbled by old King Kong,", "*I'd rather find paraquat in my bong,", "*I'd rather Chuck Barris used me as the gong,", "*I'd rather do updates to Atari Pong,", "*I'd rather write a \"User's Guide to Pong\",", }; static char *anti2[] = { "Than read another quote by Lazarus Long.", "Than have to read more of Lazarus Long.", "Than be forced to consider more Lazarus Long.", }; isLong(text) register char *text; /* * Return TRUE if the text contains "Heinlien" or "Lazarus Long" */ { register char c; while ((c = *text++) != EOS) { switch (c) { case 'H': if (streq(text, "einlien")) return (TRUE); break; case 'L': if (streq(text, "azarus Long")) return (TRUE); break; } } return (FALSE); } static char antibuffer[257]; antiheinlien(which) long which; /* * Output a non-Heinlien cookie */ { register char *tp; tp = anti1[(rand() & 32767) % (sizeof anti1) / (sizeof (char *))]; if (*tp == '*') { strcpy(antibuffer, tp + 1); *tp++ = '\n'; strcat(tp, anti2[(rand() & 32767) % (sizeof anti2) / (sizeof (char *))]); } else { strcpy(antibuffer, tp); } output(which, antibuffer); } output(which, out_text) long which; char *out_text; /* * Output one cookie */ { register char *tp; startoutput(which); printf("%s%s\n", out_text, (doall > 1) ? "%%" : ""); linecount = 1; tp = out_text; if ((tp = strchr(tp, '\n')) != NULL) { linecount++; tp++; } endoutput(); } startout(which) long which; /* * Initialize output */ { register char *timebuf; int tvec[2]; if (video) { sprintf(temp_text, "%ld", which); time(&tvec); timebuf = ctime(&tvec); erpage(1, 1); if (isvt52) { /* * VT52 */ vtout(1, 27, timebuf); vtout(3, 36, temp_text); } else { /* * VT100 */ if ($$rsts) { vtout(1, 8, "\233#3"); /* Double high */ vtout(0, 0, timebuf); /* Top half */ vtout(2, 8, "\233#4"); /* Double high */ vtout(0, 0, timebuf); /* Bottom half */ vtout(3, 18, "\233#6"); /* Double wide */ vtout(0, 0, temp_text); } else { vtout(1, 8, "\033#3"); /* Double high */ vtout(0, 0, timebuf); /* Top half */ vtout(2, 8, "\033#4"); /* Double high */ vtout(0, 0, timebuf); /* Bottom half */ vtout(3, 18, "\033#6"); /* Double wide */ vtout(0, 0, temp_text); } } vtout(5, 1, ""); } } endoutput() /* * Clear the rest of the screen */ { if (video) { erpage(0, 0); fflush(stdout); } } vtcurse(row, col) int row, col; { if (row == 0) return; if (isvt52) { printf(($$rsts) ? "\233Y%c%c" : "\033Y%c%c", row + 040, col + 040); } else { printf(($$rsts) ? "\233[%d;%dH" : "\033[%d;%dH", row, col); } } erpage(row, col) int row, col; { vtcurse(row, col); if (isvt52) fputs(($$rsts) ? "\233J" : "\033J", stdout); else fputs(($$rsts) ? "\233[J" : "\033[J", stdout); } erline(row, col) int row, col; { vtcurse(row, col); if (isvt52) fputs(($$rsts) ? "\233K" : "\033K", stdout); else fputs(($$rsts) ? "\233[K" : "\033[K", stdout); } vtout(row, col, text) int row, col; char *text; { vtcurse(row, col); fputs(text, stdout); }