Commit | Line | Data |
---|---|---|
701570d7 RS |
1 | /* |
2 | * yow.c | |
bc851190 RS |
3 | * |
4 | * Print a quotation from Zippy the Pinhead. | |
5 | * Qux <Kaufman-David@Yale> March 6, 1986 | |
6 | * | |
701570d7 | 7 | * With dynamic memory allocation. |
bc851190 RS |
8 | */ |
9 | ||
701570d7 RS |
10 | #include <stdio.h> |
11 | #include <ctype.h> | |
21af68b6 | 12 | #include <../src/paths.h> /* For PATH_DATA. */ |
701570d7 RS |
13 | |
14 | #define BUFSIZE 80 | |
bc851190 | 15 | #define SEP '\0' |
701570d7 RS |
16 | |
17 | #ifndef YOW_FILE | |
bc851190 | 18 | #define YOW_FILE "yow.lines" |
701570d7 | 19 | #endif |
bc851190 RS |
20 | |
21 | main (argc, argv) | |
22 | int argc; | |
23 | char *argv[]; | |
24 | { | |
25 | FILE *fp; | |
26 | char file[BUFSIZ]; | |
701570d7 | 27 | void yow(), setup_yow(); |
bc851190 RS |
28 | |
29 | if (argc > 2 && !strcmp (argv[1], "-f")) | |
30 | strcpy (file, argv[2]); | |
31 | else | |
32 | #ifdef vms | |
4bcffd8e | 33 | sprintf (file, "%s%s", PATH_DATA, YOW_FILE); |
bc851190 | 34 | #else |
4bcffd8e | 35 | sprintf (file, "%s/%s", PATH_DATA, YOW_FILE); |
bc851190 RS |
36 | #endif |
37 | ||
38 | if ((fp = fopen(file, "r")) == NULL) { | |
39 | perror(file); | |
40 | exit(1); | |
41 | } | |
42 | ||
43 | /* initialize random seed */ | |
44 | srand((int) (getpid() + time((long *) 0))); | |
45 | ||
701570d7 | 46 | setup_yow(fp); |
bc851190 RS |
47 | yow(fp); |
48 | fclose(fp); | |
49 | exit(0); | |
50 | } | |
51 | ||
701570d7 RS |
52 | static long len = -1; |
53 | static long header_len; | |
54 | ||
55 | #define AVG_LEN 40 /* average length of a quotation */ | |
56 | ||
57 | /* Sets len and header_len */ | |
58 | void | |
59 | setup_yow(fp) | |
60 | FILE *fp; | |
61 | { | |
62 | int c; | |
63 | ||
64 | /* Get length of file */ | |
65 | /* Because the header (stuff before the first SEP) can be very long, | |
66 | * thus biasing our search in favor of the first quotation in the file, | |
67 | * we explicitly skip that. */ | |
68 | while ((c = getc(fp)) != SEP) { | |
69 | if (c == EOF) { | |
70 | fprintf(stderr, "File contains no separators.\n"); | |
71 | exit(2); | |
72 | } | |
73 | } | |
74 | header_len = ftell(fp); | |
75 | if (header_len > AVG_LEN) | |
76 | header_len -= AVG_LEN; /* allow the first quotation to appear */ | |
77 | ||
78 | if (fseek(fp, 0L, 2) == -1) { | |
79 | perror("fseek 1"); | |
80 | exit(1); | |
81 | } | |
82 | len = ftell(fp) - header_len; | |
83 | } | |
84 | ||
85 | ||
86 | /* go to a random place in the file and print the quotation there */ | |
bc851190 RS |
87 | void |
88 | yow (fp) | |
89 | FILE *fp; | |
90 | { | |
bc851190 RS |
91 | long offset; |
92 | int c, i = 0; | |
701570d7 RS |
93 | char *buf; |
94 | unsigned int bufsize; | |
95 | char *malloc(), *realloc(); | |
bc851190 | 96 | |
701570d7 | 97 | offset = rand() % len + header_len; |
bc851190 RS |
98 | if (fseek(fp, offset, 0) == -1) { |
99 | perror("fseek 2"); | |
100 | exit(1); | |
101 | } | |
102 | ||
103 | /* Read until SEP, read next line, print it. | |
eb8c3be9 | 104 | (Note that we will never print anything before the first separator.) |
bc851190 RS |
105 | If we hit EOF looking for the first SEP, just recurse. */ |
106 | while ((c = getc(fp)) != SEP) | |
107 | if (c == EOF) { | |
108 | yow(fp); | |
109 | return; | |
110 | } | |
111 | ||
112 | /* Skip leading whitespace, then read in a quotation. | |
113 | If we hit EOF before we find a non-whitespace char, recurse. */ | |
114 | while (isspace(c = getc(fp))) | |
115 | ; | |
116 | if (c == EOF) { | |
117 | yow(fp); | |
118 | return; | |
119 | } | |
701570d7 RS |
120 | |
121 | bufsize = BUFSIZE; | |
122 | buf = malloc(bufsize); | |
123 | if (buf == (char *)0) { | |
124 | fprintf(stderr, "can't allocate any memory\n"); | |
125 | exit (3); | |
126 | } | |
127 | ||
bc851190 RS |
128 | buf[i++] = c; |
129 | while ((c = getc(fp)) != SEP && c != EOF) { | |
130 | buf[i++] = c; | |
701570d7 RS |
131 | |
132 | if (i == bufsize-1) { | |
bc851190 | 133 | /* Yow! Is this quotation too long yet? */ |
701570d7 RS |
134 | bufsize *= 2; |
135 | buf = realloc(buf, bufsize); | |
136 | if (buf == (char *)0) { | |
137 | fprintf(stderr, "can't allocate more memory\n"); | |
138 | exit (3); | |
139 | } | |
140 | } | |
bc851190 RS |
141 | } |
142 | buf[i++] = 0; | |
143 | printf("%s\n", buf); | |
144 | } | |
145 |