1: /* $Header: fortune.c,v 1.10 85/11/01 15:19:49 arnold Exp $ */ 2: 3: # include <sys/types.h> 4: # include <stdio.h> 5: # include <sys/file.h> 6: # include "strfile.h" 7: 8: # define TRUE 1 9: # define FALSE 0 10: # define bool short 11: 12: # define MINW 6 /* minimum wait if desired */ 13: # define CPERS 20 /* # of chars for each sec */ 14: # define SLEN 160 /* # of chars in short fortune */ 15: 16: # define FORTFILE "/usr/games/lib/fortunes.dat" 17: 18: bool Wflag = FALSE, /* wait desired after fortune */ 19: Sflag = FALSE, /* short fortune desired */ 20: Lflag = FALSE, /* long fortune desired */ 21: Oflag = FALSE, /* offensive fortunes only */ 22: Aflag = FALSE; /* any fortune allowed */ 23: 24: char *Fortfile = FORTFILE, /* fortune database */ 25: *Usage[] = { 26: "usage: fortune [ - ] [ -wsloa ] [ file ]", 27: " - - give this summary of usage", 28: " w - have program wait after printing message in order", 29: " to give time to read", 30: " s - short fortune only", 31: " l - long fortune only", 32: " o - offensive fortunes only", 33: " a - any fortune", 34: " Mail suggested fortunes to \"fortune\"", 35: NULL 36: }; 37: 38: long Seekpts[2]; /* seek pointers to fortunes */ 39: 40: FILE *Inf; /* input file */ 41: 42: STRFILE Tbl; /* input table */ 43: 44: time_t time(); 45: 46: main(ac, av) 47: int ac; 48: char *av[]; 49: { 50: register char c; 51: register int nchar = 0; 52: register int i; 53: 54: getargs(ac, av); 55: if ((Inf = fopen(Fortfile, "r+")) == NULL) { 56: perror(Fortfile); 57: exit(-1); 58: } 59: fread((char *) &Tbl, sizeof Tbl, 1, Inf); /* NOSTRICT */ 60: if (Tbl.str_longlen <= SLEN && Lflag) { 61: puts("Sorry, no long strings in this file"); 62: exit(0); 63: } 64: if (Tbl.str_shortlen > SLEN && Sflag) { 65: puts("Sorry, no short strings in this file"); 66: exit(0); 67: } 68: 69: /* 70: * initialize the pointer to the first -o fortune if need be. 71: */ 72: if (Tbl.str_delims[2] == 0) 73: Tbl.str_delims[2] = Tbl.str_delims[0]; 74: 75: do { 76: getfort(); 77: } while ((Sflag && !is_short()) || (Lflag && !is_long())); 78: 79: fseek(Inf, Seekpts[0], 0); 80: while (c = getc(Inf)) { 81: nchar++; 82: putchar(c); 83: } 84: fflush(stdout); 85: fseek(Inf, 0L, 0); 86: #ifdef LOCK_EX 87: /* 88: * if we can, we exclusive lock, but since it isn't very 89: * important, we just punt if we don't have easy locking 90: * available. 91: */ 92: flock(fileno(Inf), LOCK_EX); 93: #endif LOCK_EX 94: fwrite(&Tbl, 1, sizeof Tbl, Inf); 95: #ifdef LOCK_EX 96: flock(fileno(Inf), LOCK_UN); 97: #endif LOCK_EX 98: if (Wflag) 99: sleep(max((int) nchar / CPERS, MINW)); 100: exit(0); 101: } 102: 103: /* 104: * is_short: 105: * Return TRUE if fortune is "short". 106: */ 107: is_short() 108: { 109: register int nchar; 110: 111: if (!(Tbl.str_flags & (STR_RANDOM | STR_ORDERED))) 112: return (Seekpts[1] - Seekpts[0] <= SLEN); 113: fseek(Inf, Seekpts[0], 0); 114: nchar = 0; 115: while (getc(Inf)) 116: nchar++; 117: return (nchar <= SLEN); 118: } 119: 120: /* 121: * is_long: 122: * Return TRUE if fortune is "long". 123: */ 124: is_long() 125: { 126: register int nchar; 127: 128: if (!(Tbl.str_flags & (STR_RANDOM | STR_ORDERED))) 129: return (Seekpts[1] - Seekpts[0] > SLEN); 130: fseek(Inf, Seekpts[0], 0); 131: nchar = 0; 132: while (getc(Inf)) 133: nchar++; 134: return (nchar > SLEN); 135: } 136: 137: /* 138: * This routine evaluates the arguments on the command line 139: */ 140: getargs(ac, av) 141: register int ac; 142: register char *av[]; 143: { 144: register int i; 145: register char *sp; 146: register int j; 147: register short bad = 0; 148: 149: for (i = 1; i < ac; i++) { 150: if (av[i][0] != '-') { 151: setuid(getuid()); 152: setgid(getgid()); 153: Fortfile = av[i]; 154: } 155: else if (av[i][1] == '\0') { 156: j = 0; 157: while (Usage[j] != NULL) 158: puts(Usage[j++]); 159: exit(0); 160: /* NOTREACHED */ 161: } 162: else 163: for (sp = &av[i][1]; *sp != '\0'; sp++) 164: switch (*sp) { 165: case 'w': /* give time to read */ 166: Wflag++; 167: break; 168: case 's': /* short ones only */ 169: Sflag++; 170: break; 171: case 'l': /* long ones only */ 172: Lflag++; 173: break; 174: case 'o': /* offensive ones only */ 175: Oflag++; 176: break; 177: case 'a': /* any fortune */ 178: Aflag++; 179: /* 180: * initialize the random number 181: * generator; throw away the first 182: * few numbers to avoid any non- 183: * randomness in startup 184: */ 185: srnd(time(NULL) + getpid()); 186: for (j = 0; j < 20; j++) 187: (void) rnd(100); 188: break; 189: default: 190: printf("unknown flag: '%c'\n", *sp); 191: bad++; 192: break; 193: } 194: } 195: if (bad) { 196: printf("use \"%s -\" to get usage\n", av[0]); 197: exit(-1); 198: } 199: } 200: 201: /* 202: * getfort: 203: * Get the fortune data file's seek pointer for the next fortune. 204: */ 205: getfort() 206: { 207: register int fortune; 208: 209: /* 210: * Make sure all values are in range. 211: */ 212: 213: if (Tbl.str_delims[1] >= Tbl.str_delims[0]) 214: Tbl.str_delims[1] = 0; 215: if (Tbl.str_delims[2] >= Tbl.str_numstr) 216: Tbl.str_delims[2] = Tbl.str_delims[0]; 217: 218: if (Aflag) { 219: if (rnd(Tbl.str_numstr) < Tbl.str_delims[0]) 220: fortune = Tbl.str_delims[1]++; 221: else 222: fortune = Tbl.str_delims[2]++; 223: } 224: else if (Oflag) 225: fortune = Tbl.str_delims[2]++; 226: else 227: fortune = Tbl.str_delims[1]++; 228: 229: fseek(Inf, (long)(sizeof Seekpts[0]) * fortune + sizeof Tbl, 0); 230: fread((char *) Seekpts, (sizeof Seekpts[0]), 2, Inf); 231: } 232: 233: max(i, j) 234: register int i, j; 235: { 236: return (i >= j ? i : j); 237: }