(linenum→info "unix/slp.c:2238")

bsd-games/2.17/adventure/io.c

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