1*47851Sbostic /*- 2*47851Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47851Sbostic * All rights reserved. 4*47851Sbostic * 5*47851Sbostic * The game adventure was original written Fortran by Will Crowther 6*47851Sbostic * and Don Woods. It was later translated to C and enhanced by 7*47851Sbostic * Jim Gillogly. 8*47851Sbostic * 9*47851Sbostic * %sccs.include.redist.c% 10*47851Sbostic */ 11*47851Sbostic 12*47851Sbostic #ifndef lint 13*47851Sbostic static char sccsid[] = "@(#)io.c 5.1 (Berkeley) 04/08/91"; 14*47851Sbostic #endif /* not lint */ 15*47851Sbostic 166736Srrh /* Re-coding of advent in C: file i/o and user i/o */ 176736Srrh 186736Srrh #include "hdr.h" 196736Srrh #include <stdio.h> 206736Srrh 216736Srrh 226736Srrh getin(wrd1,wrd2) /* get command from user */ 236736Srrh char **wrd1,**wrd2; /* no prompt, usually */ 246736Srrh { register char *s; 256736Srrh static char wd1buf[MAXSTR],wd2buf[MAXSTR]; 266736Srrh int first, numch; 276736Srrh 286736Srrh *wrd1=wd1buf; /* return ptr to internal string*/ 296736Srrh *wrd2=wd2buf; 306736Srrh wd2buf[0]=0; /* in case it isn't set here */ 316736Srrh for (s=wd1buf, first=1, numch=0;;) 326736Srrh { if ((*s=getchar())>='A' && *s <='Z') *s = *s - ('A' -'a'); 336736Srrh /* convert to upper case */ 346736Srrh switch(*s) /* start reading from user */ 356736Srrh { case '\n': 366736Srrh *s=0; 376736Srrh return; 386736Srrh case ' ': 396736Srrh if (s==wd1buf||s==wd2buf) /* initial blank */ 406736Srrh continue; 416736Srrh *s=0; 426736Srrh if (first) /* finished 1st wd; start 2nd */ 436736Srrh { first=numch=0; 446736Srrh s=wd2buf; 456736Srrh break; 466736Srrh } 476736Srrh else /* finished 2nd word */ 486736Srrh { FLUSHLINE; 496736Srrh *s=0; 506736Srrh return; 516736Srrh } 526736Srrh default: 536736Srrh if (++numch>=MAXSTR) /* string too long */ 546736Srrh { printf("Give me a break!!\n"); 556736Srrh wd1buf[0]=wd2buf[0]=0; 566736Srrh FLUSHLINE; 576736Srrh return; 586736Srrh } 596736Srrh s++; 606736Srrh } 616736Srrh } 626736Srrh } 636736Srrh 646736Srrh 656736Srrh confirm(mesg) /* confirm irreversible action */ 666736Srrh char *mesg; 676736Srrh { register int result; 686736Srrh printf("%s",mesg); /* tell him what he did */ 696736Srrh if (getchar()=='y') /* was his first letter a 'y'? */ 706736Srrh result=1; 716736Srrh else result=0; 726736Srrh FLUSHLINE; 736736Srrh return(result); 746736Srrh } 756736Srrh 766736Srrh yes(x,y,z) /* confirm with rspeak */ 776736Srrh int x,y,z; 786736Srrh { register int result; 796736Srrh register char ch; 806736Srrh for (;;) 816736Srrh { rspeak(x); /* tell him what we want*/ 826736Srrh if ((ch=getchar())=='y') 836736Srrh result=TRUE; 846736Srrh else if (ch=='n') result=FALSE; 856736Srrh FLUSHLINE; 866736Srrh if (ch=='y'|| ch=='n') break; 876736Srrh printf("Please answer the question.\n"); 886736Srrh } 896736Srrh if (result==TRUE) rspeak(y); 906736Srrh if (result==FALSE) rspeak(z); 916736Srrh return(result); 926736Srrh } 936736Srrh 946736Srrh yesm(x,y,z) /* confirm with mspeak */ 956736Srrh int x,y,z; 966736Srrh { register int result; 976736Srrh register char ch; 986736Srrh for (;;) 996736Srrh { mspeak(x); /* tell him what we want*/ 1006736Srrh if ((ch=getchar())=='y') 1016736Srrh result=TRUE; 1026736Srrh else if (ch=='n') result=FALSE; 1036736Srrh FLUSHLINE; 1046736Srrh if (ch=='y'|| ch=='n') break; 1056736Srrh printf("Please answer the question.\n"); 1066736Srrh } 1076736Srrh if (result==TRUE) mspeak(y); 1086736Srrh if (result==FALSE) mspeak(z); 1096736Srrh return(result); 1106736Srrh } 1116736Srrh 1126736Srrh FILE *inbuf,*outbuf; 1136736Srrh 1146736Srrh int adrptr; /* current seek adr ptr */ 1156736Srrh int outsw = 0; /* putting stuff to data file? */ 1166736Srrh 1176736Srrh char iotape[] = "Ax3F'tt$8hqer*hnGKrX:!l"; 1186736Srrh char *tape = iotape; /* pointer to encryption tape */ 1196736Srrh 1206736Srrh next() /* next char frm file, bump adr */ 1216736Srrh { register char ch,t; 1226736Srrh adrptr++; /* seek address in file */ 1236736Srrh ch=getc(inbuf); 1246736Srrh if (outsw) /* putting data in tmp file */ 1256736Srrh { if (*tape==0) tape=iotape; /* rewind encryption tape */ 1266736Srrh putc(ch ^ *tape++,outbuf); /* encrypt & output char */ 1276736Srrh } 1286736Srrh return(ch); 1296736Srrh } 1306736Srrh 1316736Srrh 1326736Srrh char breakch; /* tell which char ended rnum */ 1336736Srrh 1346736Srrh 1356736Srrh rdata() /* read all data from orig file */ 1366736Srrh { register int sect; 1376736Srrh register char ch; 1386736Srrh if ((inbuf=fopen(DATFILE,"r"))==NULL) /* all the data lives in here */ 1396736Srrh { printf("Cannot open data file %s\n",DATFILE); 1406736Srrh exit(0); 1416736Srrh } 1426736Srrh if ((outbuf=fopen(TMPFILE,"w"))==NULL) /* the text lines will go here */ 1436736Srrh { printf("Cannot create output file %s\n",TMPFILE); 1446736Srrh exit(0); 1456736Srrh } 1466736Srrh setup=clsses=1; 1476736Srrh for (;;) /* read data sections */ 1486736Srrh { sect=next()-'0'; /* 1st digit of section number */ 1496736Srrh printf("Section %c",sect+'0'); 1506736Srrh if ((ch=next())!=LF) /* is there a second digit? */ 1516736Srrh { FLUSHLF; 1526736Srrh putchar(ch); 1536736Srrh sect=10*sect+ch-'0'; 1546736Srrh } 1556736Srrh putchar('\n'); 1566736Srrh switch(sect) 1576736Srrh { case 0: /* finished reading database */ 1586736Srrh fclose(inbuf); 1596736Srrh fclose(outbuf); 1606736Srrh return; 1616736Srrh case 1: /* long form descriptions */ 1626736Srrh rdesc(1); 1636736Srrh break; 1646736Srrh case 2: /* short form descriptions */ 1656736Srrh rdesc(2); 1666736Srrh break; 1676736Srrh case 3: /* travel table */ 1686736Srrh rtrav(); break; 1696736Srrh case 4: /* vocabulary */ 1706736Srrh rvoc(); 1716736Srrh break; 1726736Srrh case 5: /* object descriptions */ 1736736Srrh rdesc(5); 1746736Srrh break; 1756736Srrh case 6: /* arbitrary messages */ 1766736Srrh rdesc(6); 1776736Srrh break; 1786736Srrh case 7: /* object locations */ 1796736Srrh rlocs(); break; 1806736Srrh case 8: /* action defaults */ 1816736Srrh rdflt(); break; 1826736Srrh case 9: /* liquid assets */ 1836736Srrh rliq(); break; 1846736Srrh case 10: /* class messages */ 1856736Srrh rdesc(10); 1866736Srrh break; 1876736Srrh case 11: /* hints */ 1886736Srrh rhints(); break; 1896736Srrh case 12: /* magic messages */ 1906736Srrh rdesc(12); 1916736Srrh break; 1926736Srrh default: 1936736Srrh printf("Invalid data section number: %d\n",sect); 1946736Srrh for (;;) putchar(next()); 1956736Srrh } 1966736Srrh if (breakch!=LF) /* routines return after "-1" */ 1976736Srrh FLUSHLF; 1986736Srrh } 1996736Srrh } 2006736Srrh 2016736Srrh char nbf[12]; 2026736Srrh 2036736Srrh 2046736Srrh rnum() /* read initial location num */ 2056736Srrh { register char *s; 2066736Srrh tape = iotape; /* restart encryption tape */ 2076736Srrh for (s=nbf,*s=0;; s++) 2086736Srrh if ((*s=next())==TAB || *s=='\n' || *s==LF) 2096736Srrh break; 2106736Srrh breakch= *s; /* save char for rtrav() */ 2116736Srrh *s=0; /* got the number as ascii */ 2126736Srrh if (nbf[0]=='-') return(-1); /* end of data */ 2136736Srrh return(atoi(nbf)); /* convert it to integer */ 2146736Srrh } 2156736Srrh 2166736Srrh int seekhere = 1; /* initial seek for output file */ 2176736Srrh 2186736Srrh rdesc(sect) /* read description-format msgs */ 2196736Srrh int sect; 2206736Srrh { register char *s,*t; 2216736Srrh register int locc; 2226736Srrh int seekstart, maystart, adrstart; 2236736Srrh char *entry; 2246736Srrh outsw=1; /* these msgs go into tmp file */ 2256736Srrh if (sect==1) putc('X',outbuf); /* so seekadr > 0 */ 2266736Srrh adrptr=0; 2276736Srrh for (oldloc= -1, seekstart=seekhere;;) 2286736Srrh { maystart=adrptr; /* maybe starting new entry */ 2296736Srrh if ((locc=rnum())!=oldloc && oldloc>=0 /* finished msg */ 2306736Srrh && ! (sect==5 && (locc==0 || locc>=100)))/* unless sect 5*/ 2316736Srrh { switch(sect) /* now put it into right table */ 2326736Srrh { case 1: /* long descriptions */ 2336736Srrh ltext[oldloc].seekadr=seekhere; 2346736Srrh ltext[oldloc].txtlen=maystart-seekstart; 2356736Srrh break; 2366736Srrh case 2: /* short descriptions */ 2376736Srrh stext[oldloc].seekadr=seekhere; 2386736Srrh stext[oldloc].txtlen=maystart-seekstart; 2396736Srrh break; 2406736Srrh case 5: /* object descriptions */ 2416736Srrh ptext[oldloc].seekadr=seekhere; 2426736Srrh ptext[oldloc].txtlen=maystart-seekstart; 2436736Srrh break; 2446736Srrh case 6: /* random messages */ 2456736Srrh if (oldloc>RTXSIZ) 2466736Srrh { printf("Too many random msgs\n"); 2476736Srrh exit(0); 2486736Srrh } 2496736Srrh rtext[oldloc].seekadr=seekhere; 2506736Srrh rtext[oldloc].txtlen=maystart-seekstart; 2516736Srrh break; 2526736Srrh case 10: /* class messages */ 2536736Srrh ctext[clsses].seekadr=seekhere; 2546736Srrh ctext[clsses].txtlen=maystart-seekstart; 2556736Srrh cval[clsses++]=oldloc; 2566736Srrh break; 2576736Srrh case 12: /* magic messages */ 2586736Srrh if (oldloc>MAGSIZ) 2596736Srrh { printf("Too many magic msgs\n"); 2606736Srrh exit(0); 2616736Srrh } 2626736Srrh mtext[oldloc].seekadr=seekhere; 2636736Srrh mtext[oldloc].txtlen=maystart-seekstart; 2646736Srrh break; 2656736Srrh default: 2666736Srrh printf("rdesc called with bad section\n"); 2676736Srrh exit(0); 2686736Srrh } 2696736Srrh seekhere += maystart-seekstart; 2706736Srrh } 2716736Srrh if (locc<0) 2726736Srrh { outsw=0; /* turn off output */ 2736736Srrh seekhere += 3; /* -1<delimiter> */ 2746736Srrh return; 2756736Srrh } 2766736Srrh if (sect!=5 || (locc>0 && locc<100)) 2776736Srrh { if (oldloc!=locc)/* starting a new message */ 2786736Srrh seekstart=maystart; 2796736Srrh oldloc=locc; 2806736Srrh } 2816736Srrh FLUSHLF; /* scan the line */ 2826736Srrh } 2836736Srrh } 2846736Srrh 2856736Srrh 2866736Srrh rtrav() /* read travel table */ 2876736Srrh { register int locc; 2886736Srrh register struct travlist *t; 2896736Srrh register char *s; 2906736Srrh char buf[12]; 2916736Srrh int len,m,n,entries; 2926736Srrh for (oldloc= -1;;) /* get another line */ 2936736Srrh { if ((locc=rnum())!=oldloc && oldloc>=0) /* end of entry */ 2946736Srrh { 2956736Srrh t->next = 0; /* terminate the old entry */ 2966736Srrh /* printf("%d:%d entries\n",oldloc,entries); */ 2976736Srrh /* twrite(oldloc); */ 2986736Srrh } 2996736Srrh if (locc== -1) return; 3006736Srrh if (locc!=oldloc) /* getting a new entry */ 3016736Srrh { t=travel[locc]=(struct travlist *) malloc(sizeof (struct travlist)); 3026736Srrh /* printf("New travel list for %d\n",locc); */ 3036736Srrh entries=0; 3046736Srrh oldloc=locc; 3056736Srrh } 3066736Srrh for (s=buf;; *s++) /* get the newloc number /ASCII */ 3076736Srrh if ((*s=next())==TAB || *s==LF) break; 3086736Srrh *s=0; 3096736Srrh len=length(buf)-1; /* quad long number handling */ 3106736Srrh /* printf("Newloc: %s (%d chars)\n",buf,len); */ 3116736Srrh if (len<4) /* no "m" conditions */ 3126736Srrh { m=0; 3136736Srrh n=atoi(buf); /* newloc mod 1000 = newloc */ 3146736Srrh } 3156736Srrh else /* a long integer */ 3166736Srrh { n=atoi(buf+len-3); 3176736Srrh buf[len-3]=0; /* terminate newloc/1000 */ 3186736Srrh m=atoi(buf); 3196736Srrh } 3206736Srrh while (breakch!=LF) /* only do one line at a time */ 3216736Srrh { if (entries++) t=t->next=(struct travlist *) malloc(sizeof (struct travlist)); 3226736Srrh t->tverb=rnum();/* get verb from the file */ 3236736Srrh t->tloc=n; /* table entry mod 1000 */ 3246736Srrh t->conditions=m;/* table entry / 1000 */ 3256736Srrh /* printf("entry %d for %d\n",entries,locc); */ 3266736Srrh } 3276736Srrh } 3286736Srrh } 3296736Srrh 3306736Srrh 3316736Srrh twrite(loq) /* travel options from this loc */ 3326736Srrh int loq; 3336736Srrh { register struct travlist *t; 3346736Srrh printf("If"); 3356736Srrh speak(<ext[loq]); 3366736Srrh printf("then\n"); 3376736Srrh for (t=travel[loq]; t!=0; t=t->next) 3386736Srrh { printf("verb %d takes you to ",t->tverb); 3396736Srrh if (t->tloc<=300) 3406736Srrh speak(<ext[t->tloc]); 3416736Srrh else if (t->tloc<=500) 3426736Srrh printf("special code %d\n",t->tloc-300); 3436736Srrh else 3446736Srrh rspeak(t->tloc-500); 3456736Srrh printf("under conditions %d\n",t->conditions); 3466736Srrh } 3476736Srrh } 3486736Srrh 3496736Srrh 3506736Srrh 3516736Srrh rvoc() 3526736Srrh { register char *s; /* read the vocabulary */ 3536736Srrh register int index; 3546736Srrh char buf[6]; 3556736Srrh for (;;) 3566736Srrh { index=rnum(); 3576736Srrh if (index<0) break; 3586736Srrh for (s=buf,*s=0;; s++) /* get the word */ 3596736Srrh if ((*s=next())==TAB || *s=='\n' || *s==LF 3606736Srrh || *s==' ') break; 3616736Srrh /* terminate word with newline, LF, tab, blank */ 3626736Srrh if (*s!='\n' && *s!=LF) FLUSHLF; /* can be comments */ 3636736Srrh *s=0; 3646736Srrh /* printf("\"%s\"=%d\n",buf,index);*/ 3656736Srrh vocab(buf,-2,index); 3666736Srrh } 3676736Srrh /* prht(); */ 3686736Srrh } 3696736Srrh 3706736Srrh 3716736Srrh rlocs() /* initial object locations */ 3726736Srrh { for (;;) 3736736Srrh { if ((obj=rnum())<0) break; 3746736Srrh plac[obj]=rnum(); /* initial loc for this obj */ 3756736Srrh if (breakch==TAB) /* there's another entry */ 3766736Srrh fixd[obj]=rnum(); 3776736Srrh else fixd[obj]=0; 3786736Srrh } 3796736Srrh } 3806736Srrh 3816736Srrh rdflt() /* default verb messages */ 3826736Srrh { for (;;) 3836736Srrh { if ((verb=rnum())<0) break; 3846736Srrh actspk[verb]=rnum(); 3856736Srrh } 3866736Srrh } 3876736Srrh 3886736Srrh rliq() /* liquid assets &c: cond bits */ 3896736Srrh { register int bitnum; 3906736Srrh for (;;) /* read new bit list */ 3916736Srrh { if ((bitnum=rnum())<0) break; 3926736Srrh for (;;) /* read locs for bits */ 3936736Srrh { cond[rnum()] |= setbit[bitnum]; 3946736Srrh if (breakch==LF) break; 3956736Srrh } 3966736Srrh } 3976736Srrh } 3986736Srrh 3996736Srrh rhints() 4006736Srrh { register int hintnum,i; 4016736Srrh hntmax=0; 4026736Srrh for (;;) 4036736Srrh { if ((hintnum=rnum())<0) break; 4046736Srrh for (i=1; i<5; i++) 4056736Srrh hints[hintnum][i]=rnum(); 4066736Srrh if (hintnum>hntmax) hntmax=hintnum; 4076736Srrh } 4086736Srrh } 4096736Srrh 4106736Srrh 4116736Srrh rspeak(msg) 4126736Srrh int msg; 4136736Srrh { if (msg!=0) speak(&rtext[msg]); 4146736Srrh } 4156736Srrh 4166736Srrh 4176736Srrh mspeak(msg) 4186736Srrh int msg; 4196736Srrh { if (msg!=0) speak(&mtext[msg]); 4206736Srrh } 4216736Srrh 4226736Srrh 4236736Srrh doseek(offset) /* do 2 seeks to get to right place in the file */ 4246736Srrh unsigned offset; 4256736Srrh { 4266736Srrh extern unsigned filesize; 4276736Srrh lseek(datfd,(long)offset+(long)filesize, 0); 4286736Srrh #ifdef notdef 4296736Srrh blockadr=chadr=0; 4306736Srrh if (offset<0) /* right place is offset+filesize*/ 4316736Srrh { blockadr += 64; /* take off 32768 bytes */ 4326736Srrh chadr += offset+32768; /* & make them into 64 blocks */ 4336736Srrh } 4346736Srrh else chadr += offset; 4356736Srrh if (filesize<0) /* data starts after file */ 4366736Srrh { blockadr += 64; /* which may also be large */ 4376736Srrh chadr += filesize+32768; 4386736Srrh } 4396736Srrh else chadr += filesize; 4406736Srrh if (chadr<0) /* and the leftovers may be lge */ 4416736Srrh { blockadr += 64; 4426736Srrh chadr += 32768; 4436736Srrh } 4446736Srrh seek(datfd,blockadr,3); /* get within 32767 */ 4456736Srrh seek(datfd,chadr,1); /* then the rest of the way */ 4466736Srrh #endif 4476736Srrh } 4486736Srrh 4496736Srrh 4506736Srrh speak(msg) /* read, decrypt, and print a message (not ptext) */ 4516736Srrh struct text *msg;/* msg is a pointer to seek address and length of mess */ 4526736Srrh { register char *s,nonfirst; 4536736Srrh register char *tbuf; 4546736Srrh doseek(msg->seekadr); 45535697Sbostic if ((tbuf=(char *) malloc(msg->txtlen+1)) == 0) bug(109); 4566736Srrh read(datfd,tbuf,msg->txtlen); 4576736Srrh s=tbuf; 4586736Srrh nonfirst=0; 4596736Srrh while (s-tbuf<msg->txtlen) /* read a line at a time */ 4606736Srrh { tape=iotape; /* restart decryption tape */ 4616736Srrh while ((*s++^*tape++)!=TAB); /* read past loc num */ 4626736Srrh /* assume tape is longer than location number */ 4636736Srrh /* plus the lookahead put together */ 4646736Srrh if ((*s^*tape)=='>' && 4656736Srrh (*(s+1)^*(tape+1))=='$' && 4666736Srrh (*(s+2)^*(tape+2))=='<') break; 4676736Srrh if (blklin&&!nonfirst++) putchar('\n'); 4686736Srrh do 4696736Srrh { if (*tape==0) tape=iotape;/* rewind decryp tape */ 4706736Srrh putchar(*s^*tape); 4716736Srrh } while ((*s++^*tape++)!=LF); /* better end with LF */ 4726736Srrh } 4736736Srrh free(tbuf); 4746736Srrh } 4756736Srrh 4766736Srrh 4776736Srrh pspeak(msg,skip) /* read, decrypt an print a ptext message */ 4786736Srrh int msg; /* msg is the number of all the p msgs for this place */ 4796736Srrh int skip; /* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c*/ 4806736Srrh { register char *s,nonfirst; 4816736Srrh register char *tbuf; 4826736Srrh char *numst; 4836736Srrh int lstr; 4846736Srrh doseek(ptext[msg].seekadr); 48535697Sbostic if ((tbuf=(char *) malloc((lstr=ptext[msg].txtlen)+1)) == 0) bug(108); 4866736Srrh read(datfd,tbuf,lstr); 4876736Srrh s=tbuf; 4886736Srrh nonfirst=0; 4896736Srrh while (s-tbuf<lstr) /* read a line at a time */ 4906736Srrh { tape=iotape; /* restart decryption tape */ 4916736Srrh for (numst=s; (*s^= *tape++)!=TAB; s++); /* get number */ 4926736Srrh *s++=0; /* decrypting number within the string */ 4936736Srrh if (atoi(numst)!=100*skip && skip>=0) 4946736Srrh { while ((*s++^*tape++)!=LF) /* flush the line */ 4956736Srrh if (*tape==0) tape=iotape; 4966736Srrh continue; 4976736Srrh } 4986736Srrh if ((*s^*tape)=='>' && (*(s+1)^*(tape+1))=='$' && 4996736Srrh (*(s+2)^*(tape+2))=='<') break; 5006736Srrh if (blklin && ! nonfirst++) putchar('\n'); 5016736Srrh do 5026736Srrh { if (*tape==0) tape=iotape; 5036736Srrh putchar(*s^*tape); 5046736Srrh } while ((*s++^*tape++)!=LF); /* better end with LF */ 5056736Srrh if (skip<0) break; 5066736Srrh } 5076736Srrh free(tbuf); 5086736Srrh } 5096736Srrh 510