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