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