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