io.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /* $NetBSD: io.c,v 1.15 2003/09/19 10:01:53 itojun Exp $ */
  2. /*-
  3. * Copyright (c) 1991, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * The game adventure was originally written in Fortran by Will Crowther
  7. * and Don Woods. It was later translated to C and enhanced by Jim
  8. * Gillogly. This code is derived from software contributed to Berkeley
  9. * by Jim Gillogly at The Rand Corporation.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. Neither the name of the University nor the names of its contributors
  20. * may be used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. * SUCH DAMAGE.
  34. */
  35. #include <sys/cdefs.h>
  36. #ifndef lint
  37. #if 0
  38. static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 5/31/93";
  39. #else
  40. __RCSID("$NetBSD: io.c,v 1.15 2003/09/19 10:01:53 itojun Exp $");
  41. #endif
  42. #endif /* not lint */
  43. /* Re-coding of advent in C: file i/o and user i/o */
  44. #include <err.h>
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48. #include "hdr.h"
  49. #include "extern.h"
  50. void
  51. getin(wrd1, wrd2) /* get command from user */
  52. char **wrd1, **wrd2; /* no prompt, usually */
  53. {
  54. char *s;
  55. static char wd1buf[MAXSTR], wd2buf[MAXSTR];
  56. int first, numch;
  57. *wrd1 = wd1buf; /* return ptr to internal str */
  58. *wrd2 = wd2buf;
  59. wd2buf[0] = 0; /* in case it isn't set here */
  60. for (s = wd1buf, first = 1, numch = 0;;) {
  61. if ((*s = getchar()) >= 'A' && *s <= 'Z')
  62. *s = *s - ('A' - 'a');
  63. /* convert to upper case */
  64. switch (*s) { /* start reading from user */
  65. case '\n':
  66. *s = 0;
  67. return;
  68. case ' ':
  69. if (s == wd1buf || s == wd2buf) /* initial blank */
  70. continue;
  71. *s = 0;
  72. if (first) { /* finished 1st wd; start 2nd */
  73. first = numch = 0;
  74. s = wd2buf;
  75. break;
  76. } else { /* finished 2nd word */
  77. FLUSHLINE;
  78. *s = 0;
  79. return;
  80. }
  81. case EOF:
  82. printf("user closed input stream, quitting...\n");
  83. exit(0);
  84. default:
  85. if (++numch >= MAXSTR) { /* string too long */
  86. printf("Give me a break!!\n");
  87. wd1buf[0] = wd2buf[0] = 0;
  88. FLUSHLINE;
  89. return;
  90. }
  91. s++;
  92. }
  93. }
  94. }
  95. int
  96. yes(x, y, z) /* confirm with rspeak */
  97. int x, y, z;
  98. {
  99. int result = TRUE; /* pacify gcc */
  100. int ch;
  101. for (;;) {
  102. rspeak(x); /* tell him what we want */
  103. if ((ch = getchar()) == 'y')
  104. result = TRUE;
  105. else if (ch == 'n')
  106. result = FALSE;
  107. else if (ch == EOF) {
  108. printf("user closed input stream, quitting...\n");
  109. exit(0);
  110. }
  111. FLUSHLINE;
  112. if (ch == 'y' || ch == 'n')
  113. break;
  114. printf("Please answer the question.\n");
  115. }
  116. if (result == TRUE)
  117. rspeak(y);
  118. if (result == FALSE)
  119. rspeak(z);
  120. return (result);
  121. }
  122. int
  123. yesm(x, y, z) /* confirm with mspeak */
  124. int x, y, z;
  125. {
  126. int result = TRUE; /* pacify gcc */
  127. int ch;
  128. for (;;) {
  129. mspeak(x); /* tell him what we want */
  130. if ((ch = getchar()) == 'y')
  131. result = TRUE;
  132. else if (ch == 'n')
  133. result = FALSE;
  134. else if (ch == EOF) {
  135. printf("user closed input stream, quitting...\n");
  136. exit(0);
  137. }
  138. FLUSHLINE;
  139. if (ch == 'y' || ch == 'n')
  140. break;
  141. printf("Please answer the question.\n");
  142. }
  143. if (result == TRUE)
  144. mspeak(y);
  145. if (result == FALSE)
  146. mspeak(z);
  147. return (result);
  148. }
  149. /* FILE *inbuf,*outbuf; */
  150. char *inptr; /* Pointer into virtual disk */
  151. int outsw = 0; /* putting stuff to data file? */
  152. const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
  153. const char *tape = iotape; /* pointer to encryption tape */
  154. int
  155. next()
  156. { /* next virtual char, bump adr */
  157. int ch;
  158. ch = (*inptr ^ random()) & 0xFF; /* Decrypt input data */
  159. if (outsw) { /* putting data in tmp file */
  160. if (*tape == 0)
  161. tape = iotape; /* rewind encryption tape */
  162. *inptr = ch ^ *tape++; /* re-encrypt and replace value */
  163. }
  164. inptr++;
  165. return (ch);
  166. }
  167. char breakch; /* tell which char ended rnum */
  168. void
  169. rdata()
  170. { /* "read" data from virtual file */
  171. int sect;
  172. char ch;
  173. inptr = data_file; /* Pointer to virtual data file */
  174. srandom(SEED); /* which is lightly encrypted. */
  175. clsses = 1;
  176. for (;;) { /* read data sections */
  177. sect = next() - '0'; /* 1st digit of section number */
  178. #ifdef VERBOSE
  179. printf("Section %c", sect + '0');
  180. #endif
  181. if ((ch = next()) != LF) { /* is there a second digit? */
  182. FLUSHLF;
  183. #ifdef VERBOSE
  184. putchar(ch);
  185. #endif
  186. sect = 10 * sect + ch - '0';
  187. }
  188. #ifdef VERBOSE
  189. putchar('\n');
  190. #endif
  191. switch (sect) {
  192. case 0: /* finished reading database */
  193. return;
  194. case 1: /* long form descriptions */
  195. rdesc(1);
  196. break;
  197. case 2: /* short form descriptions */
  198. rdesc(2);
  199. break;
  200. case 3: /* travel table */
  201. rtrav();
  202. break;
  203. case 4: /* vocabulary */
  204. rvoc();
  205. break;
  206. case 5: /* object descriptions */
  207. rdesc(5);
  208. break;
  209. case 6: /* arbitrary messages */
  210. rdesc(6);
  211. break;
  212. case 7: /* object locations */
  213. rlocs();
  214. break;
  215. case 8: /* action defaults */
  216. rdflt();
  217. break;
  218. case 9: /* liquid assets */
  219. rliq();
  220. break;
  221. case 10: /* class messages */
  222. rdesc(10);
  223. break;
  224. case 11: /* hints */
  225. rhints();
  226. break;
  227. case 12: /* magic messages */
  228. rdesc(12);
  229. break;
  230. default:
  231. printf("Invalid data section number: %d\n", sect);
  232. for (;;)
  233. putchar(next());
  234. }
  235. if (breakch != LF) /* routines return after "-1" */
  236. FLUSHLF;
  237. }
  238. }
  239. char nbf[12];
  240. int
  241. rnum()
  242. { /* read initial location num */
  243. char *s;
  244. tape = iotape; /* restart encryption tape */
  245. for (s = nbf, *s = 0;; s++)
  246. if ((*s = next()) == TAB || *s == '\n' || *s == LF)
  247. break;
  248. breakch = *s; /* save char for rtrav() */
  249. *s = 0; /* got the number as ascii */
  250. if (nbf[0] == '-')
  251. return (-1); /* end of data */
  252. return (atoi(nbf)); /* convert it to integer */
  253. }
  254. char *seekhere;
  255. void
  256. rdesc(sect) /* read description-format msgs */
  257. int sect;
  258. {
  259. int locc;
  260. char *seekstart, *maystart;
  261. seekhere = inptr; /* Where are we in virtual file? */
  262. outsw = 1; /* these msgs go into tmp file */
  263. for (oldloc = -1, seekstart = seekhere;;) {
  264. maystart = inptr; /* maybe starting new entry */
  265. if ((locc = rnum()) != oldloc && oldloc >= 0 /* finished msg */
  266. && !(sect == 5 && (locc == 0 || locc >= 100))) { /* unless sect 5 */
  267. switch (sect) { /* now put it into right table */
  268. case 1:/* long descriptions */
  269. ltext[oldloc].seekadr = seekhere;
  270. ltext[oldloc].txtlen = maystart - seekstart;
  271. break;
  272. case 2:/* short descriptions */
  273. stext[oldloc].seekadr = seekhere;
  274. stext[oldloc].txtlen = maystart - seekstart;
  275. break;
  276. case 5:/* object descriptions */
  277. ptext[oldloc].seekadr = seekhere;
  278. ptext[oldloc].txtlen = maystart - seekstart;
  279. break;
  280. case 6:/* random messages */
  281. if (oldloc >= RTXSIZ)
  282. errx(1,"Too many random msgs");
  283. rtext[oldloc].seekadr = seekhere;
  284. rtext[oldloc].txtlen = maystart - seekstart;
  285. break;
  286. case 10: /* class messages */
  287. ctext[clsses].seekadr = seekhere;
  288. ctext[clsses].txtlen = maystart - seekstart;
  289. cval[clsses++] = oldloc;
  290. break;
  291. case 12: /* magic messages */
  292. if (oldloc >= MAGSIZ)
  293. errx(1,"Too many magic msgs");
  294. mtext[oldloc].seekadr = seekhere;
  295. mtext[oldloc].txtlen = maystart - seekstart;
  296. break;
  297. default:
  298. errx(1,"rdesc called with bad section");
  299. }
  300. seekhere += maystart - seekstart;
  301. }
  302. if (locc < 0) {
  303. outsw = 0; /* turn off output */
  304. seekhere += 3; /* -1<delimiter> */
  305. return;
  306. }
  307. if (sect != 5 || (locc > 0 && locc < 100)) {
  308. if (oldloc != locc) /* starting a new message */
  309. seekstart = maystart;
  310. oldloc = locc;
  311. }
  312. FLUSHLF; /* scan the line */
  313. }
  314. }
  315. void
  316. rtrav()
  317. { /* read travel table */
  318. int locc;
  319. struct travlist *t = NULL;
  320. char *s;
  321. char buf[12];
  322. int len, m, n, entries = 0;
  323. for (oldloc = -1;;) { /* get another line */
  324. if ((locc = rnum()) != oldloc && oldloc >= 0) { /* end of entry */
  325. t->next = 0; /* terminate the old entry */
  326. /* printf("%d:%d entries\n",oldloc,entries); */
  327. /* twrite(oldloc); */
  328. }
  329. if (locc == -1)
  330. return;
  331. if (locc != oldloc) { /* getting a new entry */
  332. t = travel[locc] = (struct travlist *) malloc(sizeof(struct travlist));
  333. if ( t == NULL)
  334. err(1, NULL);
  335. /* printf("New travel list for %d\n",locc); */
  336. entries = 0;
  337. oldloc = locc;
  338. }
  339. for (s = buf;; s++) /* get the newloc number /ASCII */
  340. if ((*s = next()) == TAB || *s == LF)
  341. break;
  342. *s = 0;
  343. len = length(buf) - 1; /* quad long number handling */
  344. /* printf("Newloc: %s (%d chars)\n",buf,len); */
  345. if (len < 4) { /* no "m" conditions */
  346. m = 0;
  347. n = atoi(buf); /* newloc mod 1000 = newloc */
  348. } else { /* a long integer */
  349. n = atoi(buf + len - 3);
  350. buf[len - 3] = 0; /* terminate newloc/1000 */
  351. m = atoi(buf);
  352. }
  353. while (breakch != LF) { /* only do one line at a time */
  354. if (entries++) {
  355. t = t->next = (struct travlist *) malloc(sizeof(struct travlist));
  356. if (t == NULL)
  357. err(1, NULL);
  358. }
  359. t->tverb = rnum(); /* get verb from the file */
  360. t->tloc = n; /* table entry mod 1000 */
  361. t->conditions = m; /* table entry / 1000 */
  362. /* printf("entry %d for %d\n",entries,locc); */
  363. }
  364. }
  365. }
  366. #ifdef DEBUG
  367. void
  368. twrite(loq) /* travel options from this loc */
  369. int loq;
  370. {
  371. struct travlist *t;
  372. printf("If");
  373. speak(&ltext[loq]);
  374. printf("then\n");
  375. for (t = travel[loq]; t != 0; t = t->next) {
  376. printf("verb %d takes you to ", t->tverb);
  377. if (t->tloc <= 300)
  378. speak(&ltext[t->tloc]);
  379. else
  380. if (t->tloc <= 500)
  381. printf("special code %d\n", t->tloc - 300);
  382. else
  383. rspeak(t->tloc - 500);
  384. printf("under conditions %d\n", t->conditions);
  385. }
  386. }
  387. #endif /* DEBUG */
  388. void
  389. rvoc()
  390. {
  391. char *s; /* read the vocabulary */
  392. int index;
  393. char buf[6];
  394. for (;;) {
  395. index = rnum();
  396. if (index < 0)
  397. break;
  398. for (s = buf, *s = 0;; s++) /* get the word */
  399. if ((*s = next()) == TAB || *s == '\n' || *s == LF
  400. || *s == ' ')
  401. break;
  402. /* terminate word with newline, LF, tab, blank */
  403. if (*s != '\n' && *s != LF)
  404. FLUSHLF;/* can be comments */
  405. *s = 0;
  406. /* printf("\"%s\"=%d\n",buf,index); */
  407. vocab(buf, -2, index);
  408. }
  409. /* prht(); */
  410. }
  411. void
  412. rlocs()
  413. { /* initial object locations */
  414. for (;;) {
  415. if ((obj = rnum()) < 0)
  416. break;
  417. plac[obj] = rnum(); /* initial loc for this obj */
  418. if (breakch == TAB) /* there's another entry */
  419. fixd[obj] = rnum();
  420. else
  421. fixd[obj] = 0;
  422. }
  423. }
  424. void
  425. rdflt()
  426. { /* default verb messages */
  427. for (;;) {
  428. if ((verb = rnum()) < 0)
  429. break;
  430. actspk[verb] = rnum();
  431. }
  432. }
  433. void
  434. rliq()
  435. { /* liquid assets &c: cond bits */
  436. int bitnum;
  437. for (;;) { /* read new bit list */
  438. if ((bitnum = rnum()) < 0)
  439. break;
  440. for (;;) { /* read locs for bits */
  441. cond[rnum()] |= setbit[bitnum];
  442. if (breakch == LF)
  443. break;
  444. }
  445. }
  446. }
  447. void
  448. rhints()
  449. {
  450. int hintnum, i;
  451. hntmax = 0;
  452. for (;;) {
  453. if ((hintnum = rnum()) < 0)
  454. break;
  455. for (i = 1; i < 5; i++)
  456. hints[hintnum][i] = rnum();
  457. if (hintnum > hntmax)
  458. hntmax = hintnum;
  459. }
  460. }
  461. void
  462. rspeak(msg)
  463. int msg;
  464. {
  465. if (msg != 0)
  466. speak(&rtext[msg]);
  467. }
  468. void
  469. mspeak(msg)
  470. int msg;
  471. {
  472. if (msg != 0)
  473. speak(&mtext[msg]);
  474. }
  475. void
  476. speak(msg) /* read, decrypt, and print a message (not
  477. * ptext) */
  478. const struct text *msg; /* msg is a pointer to seek address and length
  479. * of mess */
  480. {
  481. char *s, nonfirst;
  482. s = msg->seekadr;
  483. nonfirst = 0;
  484. while (s - msg->seekadr < msg->txtlen) { /* read a line at a time */
  485. tape = iotape; /* restart decryption tape */
  486. while ((*s++ ^ *tape++) != TAB); /* read past loc num */
  487. /* assume tape is longer than location number */
  488. /* plus the lookahead put together */
  489. if ((*s ^ *tape) == '>' &&
  490. (*(s + 1) ^ *(tape + 1)) == '$' &&
  491. (*(s + 2) ^ *(tape + 2)) == '<')
  492. break;
  493. if (blklin && !nonfirst++)
  494. putchar('\n');
  495. do {
  496. if (*tape == 0)
  497. tape = iotape; /* rewind decryp tape */
  498. putchar(*s ^ *tape);
  499. } while ((*s++ ^ *tape++) != LF); /* better end with LF */
  500. }
  501. }
  502. void
  503. pspeak(m, skip) /* read, decrypt an print a ptext message */
  504. int m; /* msg is the number of all the p msgs for
  505. * this place */
  506. int skip; /* assumes object 1 doesn't have prop 1, obj 2
  507. * no prop 2 &c */
  508. {
  509. char *s, nonfirst;
  510. char *numst, save;
  511. struct text *msg;
  512. char *tbuf;
  513. msg = &ptext[m];
  514. if ((tbuf = (char *) malloc(msg->txtlen + 1)) == NULL)
  515. err(1, NULL);
  516. memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
  517. s = tbuf;
  518. nonfirst = 0;
  519. while (s - tbuf < msg->txtlen) { /* read line at a time */
  520. tape = iotape; /* restart decryption tape */
  521. for (numst = s; (*s ^= *tape++) != TAB; s++); /* get number */
  522. save = *s; /* Temporarily trash the string (cringe) */
  523. *s++ = 0; /* decrypting number within the string */
  524. if (atoi(numst) != 100 * skip && skip >= 0) {
  525. while ((*s++ ^ *tape++) != LF) /* flush the line */
  526. if (*tape == 0)
  527. tape = iotape;
  528. continue;
  529. }
  530. if ((*s ^ *tape) == '>' && (*(s + 1) ^ *(tape + 1)) == '$' &&
  531. (*(s + 2) ^ *(tape + 2)) == '<')
  532. break;
  533. if (blklin && !nonfirst++)
  534. putchar('\n');
  535. do {
  536. if (*tape == 0)
  537. tape = iotape;
  538. putchar(*s ^ *tape);
  539. } while ((*s++ ^ *tape++) != LF); /* better end with LF */
  540. if (skip < 0)
  541. break;
  542. }
  543. free(tbuf);
  544. }