1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * The game adventure was original written Fortran by Will Crowther 6 * and Don Woods. It was later translated to C and enhanced by 7 * Jim Gillogly. 8 * 9 * %sccs.include.redist.c% 10 */ 11 12 #ifndef lint 13 static char sccsid[] = "@(#)io.c 5.1 (Berkeley) 04/08/91"; 14 #endif /* not lint */ 15 16 /* Re-coding of advent in C: file i/o and user i/o */ 17 18 #include "hdr.h" 19 #include <stdio.h> 20 21 22 getin(wrd1,wrd2) /* get command from user */ 23 char **wrd1,**wrd2; /* no prompt, usually */ 24 { register char *s; 25 static char wd1buf[MAXSTR],wd2buf[MAXSTR]; 26 int first, numch; 27 28 *wrd1=wd1buf; /* return ptr to internal string*/ 29 *wrd2=wd2buf; 30 wd2buf[0]=0; /* in case it isn't set here */ 31 for (s=wd1buf, first=1, numch=0;;) 32 { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a'); 33 /* convert to upper case */ 34 switch(*s) /* start reading from user */ 35 { case '\n': 36 *s=0; 37 return; 38 case ' ': 39 if (s==wd1buf||s==wd2buf) /* initial blank */ 40 continue; 41 *s=0; 42 if (first) /* finished 1st wd; start 2nd */ 43 { first=numch=0; 44 s=wd2buf; 45 break; 46 } 47 else /* finished 2nd word */ 48 { FLUSHLINE; 49 *s=0; 50 return; 51 } 52 default: 53 if (++numch>=MAXSTR) /* string too long */ 54 { printf("Give me a break!!\n"); 55 wd1buf[0]=wd2buf[0]=0; 56 FLUSHLINE; 57 return; 58 } 59 s++; 60 } 61 } 62 } 63 64 65 confirm(mesg) /* confirm irreversible action */ 66 char *mesg; 67 { register int result; 68 printf("%s",mesg); /* tell him what he did */ 69 if (getchar()=='y') /* was his first letter a 'y'? */ 70 result=1; 71 else result=0; 72 FLUSHLINE; 73 return(result); 74 } 75 76 yes(x,y,z) /* confirm with rspeak */ 77 int x,y,z; 78 { register int result; 79 register char ch; 80 for (;;) 81 { rspeak(x); /* tell him what we want*/ 82 if ((ch=getchar())=='y') 83 result=TRUE; 84 else if (ch=='n') result=FALSE; 85 FLUSHLINE; 86 if (ch=='y'|| ch=='n') break; 87 printf("Please answer the question.\n"); 88 } 89 if (result==TRUE) rspeak(y); 90 if (result==FALSE) rspeak(z); 91 return(result); 92 } 93 94 yesm(x,y,z) /* confirm with mspeak */ 95 int x,y,z; 96 { register int result; 97 register char ch; 98 for (;;) 99 { mspeak(x); /* tell him what we want*/ 100 if ((ch=getchar())=='y') 101 result=TRUE; 102 else if (ch=='n') result=FALSE; 103 FLUSHLINE; 104 if (ch=='y'|| ch=='n') break; 105 printf("Please answer the question.\n"); 106 } 107 if (result==TRUE) mspeak(y); 108 if (result==FALSE) mspeak(z); 109 return(result); 110 } 111 112 FILE *inbuf,*outbuf; 113 114 int adrptr; /* current seek adr ptr */ 115 int outsw = 0; /* putting stuff to data file? */ 116 117 char iotape[] = "Ax3F'tt$8hqer*hnGKrX:!l"; 118 char *tape = iotape; /* pointer to encryption tape */ 119 120 next() /* next char frm file, bump adr */ 121 { register char ch,t; 122 adrptr++; /* seek address in file */ 123 ch=getc(inbuf); 124 if (outsw) /* putting data in tmp file */ 125 { if (*tape==0) tape=iotape; /* rewind encryption tape */ 126 putc(ch ^ *tape++,outbuf); /* encrypt & output char */ 127 } 128 return(ch); 129 } 130 131 132 char breakch; /* tell which char ended rnum */ 133 134 135 rdata() /* read all data from orig file */ 136 { register int sect; 137 register char ch; 138 if ((inbuf=fopen(DATFILE,"r"))==NULL) /* all the data lives in here */ 139 { printf("Cannot open data file %s\n",DATFILE); 140 exit(0); 141 } 142 if ((outbuf=fopen(TMPFILE,"w"))==NULL) /* the text lines will go here */ 143 { printf("Cannot create output file %s\n",TMPFILE); 144 exit(0); 145 } 146 setup=clsses=1; 147 for (;;) /* read data sections */ 148 { sect=next()-'0'; /* 1st digit of section number */ 149 printf("Section %c",sect+'0'); 150 if ((ch=next())!=LF) /* is there a second digit? */ 151 { FLUSHLF; 152 putchar(ch); 153 sect=10*sect+ch-'0'; 154 } 155 putchar('\n'); 156 switch(sect) 157 { case 0: /* finished reading database */ 158 fclose(inbuf); 159 fclose(outbuf); 160 return; 161 case 1: /* long form descriptions */ 162 rdesc(1); 163 break; 164 case 2: /* short form descriptions */ 165 rdesc(2); 166 break; 167 case 3: /* travel table */ 168 rtrav(); break; 169 case 4: /* vocabulary */ 170 rvoc(); 171 break; 172 case 5: /* object descriptions */ 173 rdesc(5); 174 break; 175 case 6: /* arbitrary messages */ 176 rdesc(6); 177 break; 178 case 7: /* object locations */ 179 rlocs(); break; 180 case 8: /* action defaults */ 181 rdflt(); break; 182 case 9: /* liquid assets */ 183 rliq(); break; 184 case 10: /* class messages */ 185 rdesc(10); 186 break; 187 case 11: /* hints */ 188 rhints(); break; 189 case 12: /* magic messages */ 190 rdesc(12); 191 break; 192 default: 193 printf("Invalid data section number: %d\n",sect); 194 for (;;) putchar(next()); 195 } 196 if (breakch!=LF) /* routines return after "-1" */ 197 FLUSHLF; 198 } 199 } 200 201 char nbf[12]; 202 203 204 rnum() /* read initial location num */ 205 { register char *s; 206 tape = iotape; /* restart encryption tape */ 207 for (s=nbf,*s=0;; s++) 208 if ((*s=next())==TAB || *s=='\n' || *s==LF) 209 break; 210 breakch= *s; /* save char for rtrav() */ 211 *s=0; /* got the number as ascii */ 212 if (nbf[0]=='-') return(-1); /* end of data */ 213 return(atoi(nbf)); /* convert it to integer */ 214 } 215 216 int seekhere = 1; /* initial seek for output file */ 217 218 rdesc(sect) /* read description-format msgs */ 219 int sect; 220 { register char *s,*t; 221 register int locc; 222 int seekstart, maystart, adrstart; 223 char *entry; 224 outsw=1; /* these msgs go into tmp file */ 225 if (sect==1) putc('X',outbuf); /* so seekadr > 0 */ 226 adrptr=0; 227 for (oldloc= -1, seekstart=seekhere;;) 228 { maystart=adrptr; /* maybe starting new entry */ 229 if ((locc=rnum())!=oldloc && oldloc>=0 /* finished msg */ 230 && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/ 231 { switch(sect) /* now put it into right table */ 232 { case 1: /* long descriptions */ 233 ltext[oldloc].seekadr=seekhere; 234 ltext[oldloc].txtlen=maystart-seekstart; 235 break; 236 case 2: /* short descriptions */ 237 stext[oldloc].seekadr=seekhere; 238 stext[oldloc].txtlen=maystart-seekstart; 239 break; 240 case 5: /* object descriptions */ 241 ptext[oldloc].seekadr=seekhere; 242 ptext[oldloc].txtlen=maystart-seekstart; 243 break; 244 case 6: /* random messages */ 245 if (oldloc>RTXSIZ) 246 { printf("Too many random msgs\n"); 247 exit(0); 248 } 249 rtext[oldloc].seekadr=seekhere; 250 rtext[oldloc].txtlen=maystart-seekstart; 251 break; 252 case 10: /* class messages */ 253 ctext[clsses].seekadr=seekhere; 254 ctext[clsses].txtlen=maystart-seekstart; 255 cval[clsses++]=oldloc; 256 break; 257 case 12: /* magic messages */ 258 if (oldloc>MAGSIZ) 259 { printf("Too many magic msgs\n"); 260 exit(0); 261 } 262 mtext[oldloc].seekadr=seekhere; 263 mtext[oldloc].txtlen=maystart-seekstart; 264 break; 265 default: 266 printf("rdesc called with bad section\n"); 267 exit(0); 268 } 269 seekhere += maystart-seekstart; 270 } 271 if (locc<0) 272 { outsw=0; /* turn off output */ 273 seekhere += 3; /* -1<delimiter> */ 274 return; 275 } 276 if (sect!=5 || (locc>0 && locc<100)) 277 { if (oldloc!=locc)/* starting a new message */ 278 seekstart=maystart; 279 oldloc=locc; 280 } 281 FLUSHLF; /* scan the line */ 282 } 283 } 284 285 286 rtrav() /* read travel table */ 287 { register int locc; 288 register struct travlist *t; 289 register char *s; 290 char buf[12]; 291 int len,m,n,entries; 292 for (oldloc= -1;;) /* get another line */ 293 { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */ 294 { 295 t->next = 0; /* terminate the old entry */ 296 /* printf("%d:%d entries\n",oldloc,entries); */ 297 /* twrite(oldloc); */ 298 } 299 if (locc== -1) return; 300 if (locc!=oldloc) /* getting a new entry */ 301 { t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist)); 302 /* printf("New travel list for %d\n",locc); */ 303 entries=0; 304 oldloc=locc; 305 } 306 for (s=buf;; *s++) /* get the newloc number /ASCII */ 307 if ((*s=next())==TAB || *s==LF) break; 308 *s=0; 309 len=length(buf)-1; /* quad long number handling */ 310 /* printf("Newloc: %s (%d chars)\n",buf,len); */ 311 if (len<4) /* no "m" conditions */ 312 { m=0; 313 n=atoi(buf); /* newloc mod 1000 = newloc */ 314 } 315 else /* a long integer */ 316 { n=atoi(buf+len-3); 317 buf[len-3]=0; /* terminate newloc/1000 */ 318 m=atoi(buf); 319 } 320 while (breakch!=LF) /* only do one line at a time */ 321 { if (entries++) t=t->next=(struct travlist *) malloc(sizeof (struct travlist)); 322 t->tverb=rnum();/* get verb from the file */ 323 t->tloc=n; /* table entry mod 1000 */ 324 t->conditions=m;/* table entry / 1000 */ 325 /* printf("entry %d for %d\n",entries,locc); */ 326 } 327 } 328 } 329 330 331 twrite(loq) /* travel options from this loc */ 332 int loq; 333 { register struct travlist *t; 334 printf("If"); 335 speak(<ext[loq]); 336 printf("then\n"); 337 for (t=travel[loq]; t!=0; t=t->next) 338 { printf("verb %d takes you to ",t->tverb); 339 if (t->tloc<=300) 340 speak(<ext[t->tloc]); 341 else if (t->tloc<=500) 342 printf("special code %d\n",t->tloc-300); 343 else 344 rspeak(t->tloc-500); 345 printf("under conditions %d\n",t->conditions); 346 } 347 } 348 349 350 351 rvoc() 352 { register char *s; /* read the vocabulary */ 353 register int index; 354 char buf[6]; 355 for (;;) 356 { index=rnum(); 357 if (index<0) break; 358 for (s=buf,*s=0;; s++) /* get the word */ 359 if ((*s=next())==TAB || *s=='\n' || *s==LF 360 || *s==' ') break; 361 /* terminate word with newline, LF, tab, blank */ 362 if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */ 363 *s=0; 364 /* printf("\"%s\"=%d\n",buf,index);*/ 365 vocab(buf,-2,index); 366 } 367 /* prht(); */ 368 } 369 370 371 rlocs() /* initial object locations */ 372 { for (;;) 373 { if ((obj=rnum())<0) break; 374 plac[obj]=rnum(); /* initial loc for this obj */ 375 if (breakch==TAB) /* there's another entry */ 376 fixd[obj]=rnum(); 377 else fixd[obj]=0; 378 } 379 } 380 381 rdflt() /* default verb messages */ 382 { for (;;) 383 { if ((verb=rnum())<0) break; 384 actspk[verb]=rnum(); 385 } 386 } 387 388 rliq() /* liquid assets &c: cond bits */ 389 { register int bitnum; 390 for (;;) /* read new bit list */ 391 { if ((bitnum=rnum())<0) break; 392 for (;;) /* read locs for bits */ 393 { cond[rnum()] |= setbit[bitnum]; 394 if (breakch==LF) break; 395 } 396 } 397 } 398 399 rhints() 400 { register int hintnum,i; 401 hntmax=0; 402 for (;;) 403 { if ((hintnum=rnum())<0) break; 404 for (i=1; i<5; i++) 405 hints[hintnum][i]=rnum(); 406 if (hintnum>hntmax) hntmax=hintnum; 407 } 408 } 409 410 411 rspeak(msg) 412 int msg; 413 { if (msg!=0) speak(&rtext[msg]); 414 } 415 416 417 mspeak(msg) 418 int msg; 419 { if (msg!=0) speak(&mtext[msg]); 420 } 421 422 423 doseek(offset) /* do 2 seeks to get to right place in the file */ 424 unsigned offset; 425 { 426 extern unsigned filesize; 427 lseek(datfd,(long)offset+(long)filesize, 0); 428 #ifdef notdef 429 blockadr=chadr=0; 430 if (offset<0) /* right place is offset+filesize*/ 431 { blockadr += 64; /* take off 32768 bytes */ 432 chadr += offset+32768; /* & make them into 64 blocks */ 433 } 434 else chadr += offset; 435 if (filesize<0) /* data starts after file */ 436 { blockadr += 64; /* which may also be large */ 437 chadr += filesize+32768; 438 } 439 else chadr += filesize; 440 if (chadr<0) /* and the leftovers may be lge */ 441 { blockadr += 64; 442 chadr += 32768; 443 } 444 seek(datfd,blockadr,3); /* get within 32767 */ 445 seek(datfd,chadr,1); /* then the rest of the way */ 446 #endif 447 } 448 449 450 speak(msg) /* read, decrypt, and print a message (not ptext) */ 451 struct text *msg;/* msg is a pointer to seek address and length of mess */ 452 { register char *s,nonfirst; 453 register char *tbuf; 454 doseek(msg->seekadr); 455 if ((tbuf=(char *) malloc(msg->txtlen+1)) == 0) bug(109); 456 read(datfd,tbuf,msg->txtlen); 457 s=tbuf; 458 nonfirst=0; 459 while (s-tbuf<msg->txtlen) /* read a line at a time */ 460 { tape=iotape; /* restart decryption tape */ 461 while ((*s++^*tape++)!=TAB); /* read past loc num */ 462 /* assume tape is longer than location number */ 463 /* plus the lookahead put together */ 464 if ((*s^*tape)=='>' && 465 (*(s+1)^*(tape+1))=='$' && 466 (*(s+2)^*(tape+2))=='<') break; 467 if (blklin&&!nonfirst++) putchar('\n'); 468 do 469 { if (*tape==0) tape=iotape;/* rewind decryp tape */ 470 putchar(*s^*tape); 471 } while ((*s++^*tape++)!=LF); /* better end with LF */ 472 } 473 free(tbuf); 474 } 475 476 477 pspeak(msg,skip) /* read, decrypt an print a ptext message */ 478 int msg; /* msg is the number of all the p msgs for this place */ 479 int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/ 480 { register char *s,nonfirst; 481 register char *tbuf; 482 char *numst; 483 int lstr; 484 doseek(ptext[msg].seekadr); 485 if ((tbuf=(char *) malloc((lstr=ptext[msg].txtlen)+1)) == 0) bug(108); 486 read(datfd,tbuf,lstr); 487 s=tbuf; 488 nonfirst=0; 489 while (s-tbuf<lstr) /* read a line at a time */ 490 { tape=iotape; /* restart decryption tape */ 491 for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number */ 492 *s++=0; /* decrypting number within the string */ 493 if (atoi(numst)!=100*skip && skip>=0) 494 { while ((*s++^*tape++)!=LF) /* flush the line */ 495 if (*tape==0) tape=iotape; 496 continue; 497 } 498 if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' && 499 (*(s+2)^*(tape+2))=='<') break; 500 if (blklin && ! nonfirst++) putchar('\n'); 501 do 502 { if (*tape==0) tape=iotape; 503 putchar(*s^*tape); 504 } while ((*s++^*tape++)!=LF); /* better end with LF */ 505 if (skip<0) break; 506 } 507 free(tbuf); 508 } 509 510