Commit | Line | Data |
---|---|---|
f2b5c7ab RH |
1 | # |
2 | /* Re-coding of advent in C: file i/o and user i/o */ | |
3 | ||
01eb5674 | 4 | static char sccsid[] = " io.c 4.1 82/05/11 "; |
f2b5c7ab RH |
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 |