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