]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - adventure/io.c
Coverity CID 1195: Check for possible negative index.
[bsdgames-darwin.git] / adventure / io.c
1 /* $NetBSD: io.c,v 1.18 2006/03/18 23:33:38 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * The game adventure was originally written in Fortran by Will Crowther
8 * and Don Woods. It was later translated to C and enhanced by Jim
9 * Gillogly. This code is derived from software contributed to Berkeley
10 * by Jim Gillogly at The Rand Corporation.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 5/31/93";
41 #else
42 __RCSID("$NetBSD: io.c,v 1.18 2006/03/18 23:33:38 christos Exp $");
43 #endif
44 #endif /* not lint */
45
46 /* Re-coding of advent in C: file i/o and user i/o */
47
48 #include <err.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include "hdr.h"
53 #include "extern.h"
54
55
56 /* get command from user */
57 /* no prompt, usually */
58 void
59 getin(char **wrd1, char **wrd2)
60 {
61 char *s;
62 static char wd1buf[MAXSTR], wd2buf[MAXSTR];
63 int first, numch;
64
65 *wrd1 = wd1buf; /* return ptr to internal str */
66 *wrd2 = wd2buf;
67 wd2buf[0] = 0; /* in case it isn't set here */
68 for (s = wd1buf, first = 1, numch = 0;;) {
69 if ((*s = getchar()) >= 'A' && *s <= 'Z')
70 *s = *s - ('A' - 'a');
71 /* convert to upper case */
72 switch (*s) { /* start reading from user */
73 case '\n':
74 *s = 0;
75 return;
76 case ' ':
77 if (s == wd1buf || s == wd2buf) /* initial blank */
78 continue;
79 *s = 0;
80 if (first) { /* finished 1st wd; start 2nd */
81 first = numch = 0;
82 s = wd2buf;
83 break;
84 } else { /* finished 2nd word */
85 FLUSHLINE;
86 *s = 0;
87 return;
88 }
89 case EOF:
90 printf("user closed input stream, quitting...\n");
91 exit(0);
92 default:
93 if (++numch >= MAXSTR) { /* string too long */
94 printf("Give me a break!!\n");
95 wd1buf[0] = wd2buf[0] = 0;
96 FLUSHLINE;
97 return;
98 }
99 s++;
100 }
101 }
102 }
103
104 /* confirm with rspeak */
105 int
106 yes(int x, int y, int z)
107 {
108 int result = TRUE; /* pacify gcc */
109 int ch;
110 for (;;) {
111 rspeak(x); /* tell him what we want */
112 if ((ch = getchar()) == 'y')
113 result = TRUE;
114 else if (ch == 'n')
115 result = FALSE;
116 else if (ch == EOF) {
117 printf("user closed input stream, quitting...\n");
118 exit(0);
119 }
120 FLUSHLINE;
121 if (ch == 'y' || ch == 'n')
122 break;
123 printf("Please answer the question.\n");
124 }
125 if (result == TRUE)
126 rspeak(y);
127 if (result == FALSE)
128 rspeak(z);
129 return (result);
130 }
131
132 /* confirm with mspeak */
133 int
134 yesm(int x, int y, int z)
135 {
136 int result = TRUE; /* pacify gcc */
137 int ch;
138 for (;;) {
139 mspeak(x); /* tell him what we want */
140 if ((ch = getchar()) == 'y')
141 result = TRUE;
142 else if (ch == 'n')
143 result = FALSE;
144 else if (ch == EOF) {
145 printf("user closed input stream, quitting...\n");
146 exit(0);
147 }
148 FLUSHLINE;
149 if (ch == 'y' || ch == 'n')
150 break;
151 printf("Please answer the question.\n");
152 }
153 if (result == TRUE)
154 mspeak(y);
155 if (result == FALSE)
156 mspeak(z);
157 return (result);
158 }
159 /* FILE *inbuf,*outbuf; */
160
161 char *inptr; /* Pointer into virtual disk */
162
163 int outsw = 0; /* putting stuff to data file? */
164
165 const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
166 const char *tape = iotape; /* pointer to encryption tape */
167
168 /* next virtual char, bump adr */
169 int
170 next(void)
171 {
172 int ch;
173
174 ch = (*inptr ^ random()) & 0xFF; /* Decrypt input data */
175 if (outsw) { /* putting data in tmp file */
176 if (*tape == 0)
177 tape = iotape; /* rewind encryption tape */
178 *inptr = ch ^ *tape++; /* re-encrypt and replace value */
179 }
180 inptr++;
181 return (ch);
182 }
183
184 char breakch; /* tell which char ended rnum */
185
186 /* "read" data from virtual file */
187 void
188 rdata(void)
189 {
190 int sect;
191 char ch;
192
193 inptr = data_file; /* Pointer to virtual data file */
194 srandom(SEED); /* which is lightly encrypted. */
195
196 clsses = 1;
197 for (;;) { /* read data sections */
198 sect = next() - '0'; /* 1st digit of section number */
199 #ifdef VERBOSE
200 printf("Section %c", sect + '0');
201 #endif
202 if ((ch = next()) != LF) { /* is there a second digit? */
203 FLUSHLF;
204 #ifdef VERBOSE
205 putchar(ch);
206 #endif
207 sect = 10 * sect + ch - '0';
208 }
209 #ifdef VERBOSE
210 putchar('\n');
211 #endif
212 switch (sect) {
213 case 0: /* finished reading database */
214 return;
215 case 1: /* long form descriptions */
216 rdesc(1);
217 break;
218 case 2: /* short form descriptions */
219 rdesc(2);
220 break;
221 case 3: /* travel table */
222 rtrav();
223 break;
224 case 4: /* vocabulary */
225 rvoc();
226 break;
227 case 5: /* object descriptions */
228 rdesc(5);
229 break;
230 case 6: /* arbitrary messages */
231 rdesc(6);
232 break;
233 case 7: /* object locations */
234 rlocs();
235 break;
236 case 8: /* action defaults */
237 rdflt();
238 break;
239 case 9: /* liquid assets */
240 rliq();
241 break;
242 case 10: /* class messages */
243 rdesc(10);
244 break;
245 case 11: /* hints */
246 rhints();
247 break;
248 case 12: /* magic messages */
249 rdesc(12);
250 break;
251 default:
252 printf("Invalid data section number: %d\n", sect);
253 for (;;)
254 putchar(next());
255 }
256 if (breakch != LF) /* routines return after "-1" */
257 FLUSHLF;
258 }
259 }
260
261 char nbf[12];
262
263 /* read initial location num */
264 int
265 rnum(void)
266 {
267 char *s;
268 tape = iotape; /* restart encryption tape */
269 for (s = nbf, *s = 0;; s++)
270 if ((*s = next()) == TAB || *s == '\n' || *s == LF)
271 break;
272 breakch = *s; /* save char for rtrav() */
273 *s = 0; /* got the number as ascii */
274 if (nbf[0] == '-')
275 return (-1); /* end of data */
276 return (atoi(nbf)); /* convert it to integer */
277 }
278
279 char *seekhere;
280
281 /* read description-format msgs */
282 void
283 rdesc(int sect)
284 {
285 int locc;
286 char *seekstart, *maystart;
287
288 seekhere = inptr; /* Where are we in virtual file? */
289 outsw = 1; /* these msgs go into tmp file */
290 for (oldloc = -1, seekstart = seekhere;;) {
291 maystart = inptr; /* maybe starting new entry */
292 if ((locc = rnum()) != oldloc && oldloc >= 0 /* finished msg */
293 /* unless sect 5 */
294 && !(sect == 5 && (locc == 0 || locc >= 100))) {
295 switch (sect) { /* now put it into right table */
296 case 1:/* long descriptions */
297 ltext[oldloc].seekadr = seekhere;
298 ltext[oldloc].txtlen = maystart - seekstart;
299 break;
300 case 2:/* short descriptions */
301 stext[oldloc].seekadr = seekhere;
302 stext[oldloc].txtlen = maystart - seekstart;
303 break;
304 case 5:/* object descriptions */
305 ptext[oldloc].seekadr = seekhere;
306 ptext[oldloc].txtlen = maystart - seekstart;
307 break;
308 case 6:/* random messages */
309 if (oldloc >= RTXSIZ)
310 errx(1,"Too many random msgs");
311 rtext[oldloc].seekadr = seekhere;
312 rtext[oldloc].txtlen = maystart - seekstart;
313 break;
314 case 10: /* class messages */
315 ctext[clsses].seekadr = seekhere;
316 ctext[clsses].txtlen = maystart - seekstart;
317 cval[clsses++] = oldloc;
318 break;
319 case 12: /* magic messages */
320 if (oldloc >= MAGSIZ)
321 errx(1,"Too many magic msgs");
322 mtext[oldloc].seekadr = seekhere;
323 mtext[oldloc].txtlen = maystart - seekstart;
324 break;
325 default:
326 errx(1,"rdesc called with bad section");
327 }
328 seekhere += maystart - seekstart;
329 }
330 if (locc < 0) {
331 outsw = 0; /* turn off output */
332 seekhere += 3; /* -1<delimiter> */
333 return;
334 }
335 if (sect != 5 || (locc > 0 && locc < 100)) {
336 if (oldloc != locc) /* starting a new message */
337 seekstart = maystart;
338 oldloc = locc;
339 }
340 FLUSHLF; /* scan the line */
341 }
342 }
343
344 /* read travel table */
345 void
346 rtrav(void)
347 {
348 int locc;
349 struct travlist *t = NULL;
350 char *s;
351 char buf[12];
352 int len, m, n, entries = 0;
353
354 for (oldloc = -1;;) { /* get another line */
355 /* end of entry */
356 if ((locc = rnum()) != oldloc && oldloc >= 0 && t) {
357 t->next = 0; /* terminate the old entry */
358 /* printf("%d:%d entries\n",oldloc,entries); */
359 /* twrite(oldloc); */
360 }
361 if (locc == -1)
362 return;
363 if (locc != oldloc) { /* getting a new entry */
364 t = travel[locc] = (struct travlist *)
365 malloc(sizeof(struct travlist));
366 if ( t == NULL)
367 err(1, NULL);
368 /* printf("New travel list for %d\n",locc); */
369 entries = 0;
370 oldloc = locc;
371 }
372 for (s = buf;; s++) /* get the newloc number /ASCII */
373 if ((*s = next()) == TAB || *s == LF)
374 break;
375 *s = 0;
376 len = length(buf) - 1; /* quad long number handling */
377 /* printf("Newloc: %s (%d chars)\n",buf,len); */
378 if (len < 4) { /* no "m" conditions */
379 m = 0;
380 n = atoi(buf); /* newloc mod 1000 = newloc */
381 } else { /* a long integer */
382 n = atoi(buf + len - 3);
383 buf[len - 3] = 0; /* terminate newloc/1000 */
384 m = atoi(buf);
385 }
386 while (breakch != LF) { /* only do one line at a time */
387 if (t && entries++) {
388 t->next = malloc(sizeof(struct travlist));
389 if (t->next == NULL)
390 err(1, NULL);
391 t = t->next;
392 }
393 t->tverb = rnum(); /* get verb from the file */
394 t->tloc = n; /* table entry mod 1000 */
395 t->conditions = m; /* table entry / 1000 */
396 /* printf("entry %d for %d\n",entries,locc); */
397 }
398 }
399 }
400 #ifdef DEBUG
401
402 /* travel options from this loc */
403 void
404 twrite(int loq)
405 {
406 struct travlist *t;
407 printf("If");
408 speak(&ltext[loq]);
409 printf("then\n");
410 for (t = travel[loq]; t != 0; t = t->next) {
411 printf("verb %d takes you to ", t->tverb);
412 if (t->tloc <= 300)
413 speak(&ltext[t->tloc]);
414 else
415 if (t->tloc <= 500)
416 printf("special code %d\n", t->tloc - 300);
417 else
418 rspeak(t->tloc - 500);
419 printf("under conditions %d\n", t->conditions);
420 }
421 }
422 #endif /* DEBUG */
423
424 /* read the vocabulary */
425 void
426 rvoc(void)
427 {
428 char *s;
429 int idx;
430 char buf[6];
431 for (;;) {
432 idx = rnum();
433 if (idx < 0)
434 break;
435 for (s = buf, *s = 0;; s++) /* get the word */
436 if ((*s = next()) == TAB || *s == '\n' || *s == LF
437 || *s == ' ')
438 break;
439 /* terminate word with newline, LF, tab, blank */
440 if (*s != '\n' && *s != LF)
441 FLUSHLF;/* can be comments */
442 *s = 0;
443 /* printf("\"%s\"=%d\n",buf,idx); */
444 vocab(buf, -2, idx);
445 }
446 /* prht(); */
447 }
448
449 /* initial object locations */
450 void
451 rlocs(void)
452 {
453 for (;;) {
454 if ((obj = rnum()) < 0)
455 break;
456 plac[obj] = rnum(); /* initial loc for this obj */
457 if (breakch == TAB) /* there's another entry */
458 fixd[obj] = rnum();
459 else
460 fixd[obj] = 0;
461 }
462 }
463
464 /* default verb messages */
465 void
466 rdflt(void)
467 {
468 for (;;) {
469 if ((verb = rnum()) < 0)
470 break;
471 actspk[verb] = rnum();
472 }
473 }
474
475 /* liquid assets &c: cond bits */
476 void
477 rliq(void)
478 {
479 int bitnum;
480 for (;;) { /* read new bit list */
481 if ((bitnum = rnum()) < 0)
482 break;
483 for (;;) { /* read locs for bits */
484 int n = rnum();
485 if (n < 0)
486 break;
487 cond[n] |= setbit[bitnum];
488 if (breakch == LF)
489 break;
490 }
491 }
492 }
493
494 void
495 rhints(void)
496 {
497 int hintnum, i;
498 hntmax = 0;
499 for (;;) {
500 if ((hintnum = rnum()) < 0)
501 break;
502 for (i = 1; i < 5; i++)
503 hints[hintnum][i] = rnum();
504 if (hintnum > hntmax)
505 hntmax = hintnum;
506 }
507 }
508
509
510 void
511 rspeak(int msg)
512 {
513 if (msg != 0)
514 speak(&rtext[msg]);
515 }
516
517
518 void
519 mspeak(int msg)
520 {
521 if (msg != 0)
522 speak(&mtext[msg]);
523 }
524
525
526 /* read, decrypt, and print a message (not ptext) */
527 /* msg is a pointer to seek address and length of mess */
528 void
529 speak(const struct text *msg)
530 {
531 char *s, nonfirst;
532
533 s = msg->seekadr;
534 nonfirst = 0;
535 while (s - msg->seekadr < msg->txtlen) { /* read a line at a time */
536 tape = iotape; /* restart decryption tape */
537 while ((*s++ ^ *tape++) != TAB); /* read past loc num */
538 /* assume tape is longer than location number */
539 /* plus the lookahead put together */
540 if ((*s ^ *tape) == '>' &&
541 (*(s + 1) ^ *(tape + 1)) == '$' &&
542 (*(s + 2) ^ *(tape + 2)) == '<')
543 break;
544 if (blklin && !nonfirst++)
545 putchar('\n');
546 do {
547 if (*tape == 0)
548 tape = iotape; /* rewind decryp tape */
549 putchar(*s ^ *tape);
550 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
551 }
552 }
553
554 /* read, decrypt and print a ptext message */
555 /* msg is the number of all the p msgs for this place */
556 /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c */
557 void
558 pspeak(int m, int skip)
559 {
560 char *s, nonfirst;
561 char *numst;
562 struct text *msg;
563 char *tbuf;
564
565 msg = &ptext[m];
566 if ((tbuf = (char *) malloc(msg->txtlen + 1)) == NULL)
567 err(1, NULL);
568 memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
569 s = tbuf;
570
571 nonfirst = 0;
572 while (s - tbuf < msg->txtlen) { /* read line at a time */
573 tape = iotape; /* restart decryption tape */
574 for (numst = s; (*s ^= *tape++) != TAB; s++); /* get number */
575
576 /* Temporarily trash the string (cringe) */
577 *s++ = 0; /* decrypting number within the string */
578
579 if (atoi(numst) != 100 * skip && skip >= 0) {
580 while ((*s++ ^ *tape++) != LF) /* flush the line */
581 if (*tape == 0)
582 tape = iotape;
583 continue;
584 }
585 if ((*s ^ *tape) == '>' && (*(s + 1) ^ *(tape + 1)) == '$' &&
586 (*(s + 2) ^ *(tape + 2)) == '<')
587 break;
588 if (blklin && !nonfirst++)
589 putchar('\n');
590 do {
591 if (*tape == 0)
592 tape = iotape;
593 putchar(*s ^ *tape);
594 } while ((*s++ ^ *tape++) != LF); /* better end with LF */
595 if (skip < 0)
596 break;
597 }
598 free(tbuf);
599 }