1 # 2 /* Re-coding of advent in C: file i/o and user i/o */ 3 4 static char sccsid[] = " io.c 4.2 88/09/22 "; 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 } 497 498