File: [local] / src / games / adventure / io.c (download)
Revision 1.16, Mon Mar 27 00:10:14 2006 UTC (18 years, 2 months ago) by tedu
Branch: MAIN
CVS Tags: OPENBSD_4_6_BASE, OPENBSD_4_6, OPENBSD_4_5_BASE, OPENBSD_4_5, OPENBSD_4_4_BASE, OPENBSD_4_4, OPENBSD_4_3_BASE, OPENBSD_4_3, OPENBSD_4_2_BASE, OPENBSD_4_2, OPENBSD_4_1_BASE, OPENBSD_4_1, OPENBSD_4_0_BASE, OPENBSD_4_0 Changes since 1.15: +8 -5 lines
assorted fixes mostly from coverity via netbsd via jasper adriaanse via tech
|
/* $OpenBSD: io.c,v 1.16 2006/03/27 00:10:14 tedu Exp $ */
/* $NetBSD: io.c,v 1.3 1995/04/24 12:21:37 cgd Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* The game adventure was originally written in Fortran by Will Crowther
* and Don Woods. It was later translated to C and enhanced by Jim
* Gillogly. This code is derived from software contributed to Berkeley
* by Jim Gillogly at The Rand Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
#if 0
static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 5/31/93";
#else
static char rcsid[] = "$OpenBSD: io.c,v 1.16 2006/03/27 00:10:14 tedu Exp $";
#endif
#endif /* not lint */
/* Re-coding of advent in C: file i/o and user i/o */
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "hdr.h"
#include "extern.h"
/* Get command from user. No prompt, usually. */
void
getin(char *wrd1, size_t siz1, char *wrd2, size_t siz2)
{
char *s, *slast;
int ch, first;
*wrd2 = 0; /* in case it isn't set here */
for (s = wrd1, first = 1, slast = wrd1 + siz1 - 1;;) {
if ((ch = getchar()) >= 'A' && ch <= 'Z')
ch = ch - ('A' - 'a');
/* convert to upper case */
switch (ch) { /* start reading from user */
case '\n':
*s = 0;
return;
case ' ':
if (s == wrd1 || s == wrd2) /* initial blank */
continue;
*s = 0;
if (first) { /* finished 1st wd; start 2nd */
first = 0;
s = wrd2;
slast = wrd2 + siz2 - 1;
break;
} else { /* finished 2nd word */
FLUSHLINE;
*s = 0;
return;
}
case EOF:
printf("user closed input stream, quitting...\n");
exit(0);
default:
if (s == slast) { /* string too long */
printf("Give me a break!!\n");
*wrd1 = *wrd2 = 0;
FLUSHLINE;
return;
}
*s++ = ch;
}
}
}
#if 0 /* Not used */
int
confirm(char *mesg) /* confirm irreversible action */
{
int result;
int ch;
printf("%s", mesg); /* tell him what he did */
if ((ch = getchar()) == 'y') /* was his first letter a 'y'? */
result = 1;
else if (ch == EOF) {
printf("user closed input stream, quitting...\n");
exit(0);
} else
result = 0;
FLUSHLINE;
return (result);
}
#endif
int
yes(int x, int y, int z) /* confirm with rspeak */
{
int result;
int ch;
for (;;) {
rspeak(x); /* tell him what we want*/
if ((ch = getchar())=='y')
result = TRUE;
else if (ch=='n')
result = FALSE;
else if (ch == EOF) {
printf("user closed input stream, quitting...\n");
exit(0);
}
if (ch != '\n')
FLUSHLINE;
if (ch == 'y' || ch == 'n')
break;
printf("Please answer the question.\n");
}
if (result == TRUE)
rspeak(y);
if (result == FALSE)
rspeak(z);
return (result);
}
int
yesm(int x, int y, int z) /* confirm with mspeak */
{
int result;
int ch;
for (;;) {
mspeak(x); /* tell him what we want */
if ((ch = getchar()) == 'y')
result = TRUE;
else if (ch == 'n')
result = FALSE;
else if (ch == EOF) {
printf("user closed input stream, quitting...\n");
exit(0);
}
if (ch != '\n')
FLUSHLINE;
if (ch == 'y' || ch == 'n')
break;
printf("Please answer the question.\n");
}
if (result == TRUE)
mspeak(y);
if (result == FALSE)
mspeak(z);
return (result);
}
/* FILE *inbuf,*outbuf; */
char *inptr; /* Pointer into virtual disk */
int outsw = 0; /* putting stuff to data file? */
const char iotape[] = "Ax3F'\003tt$8h\315qer*h\017nGKrX\207:!l";
const char *tape = iotape; /* pointer to encryption tape */
int
next(void) /* next virtual char, bump adr */
{
int ch;
ch=(*inptr ^ random()) & 0xFF; /* Decrypt input data */
if (outsw) { /* putting data in tmp file */
if (*tape == 0)
tape = iotape; /* rewind encryption tape */
*inptr = ch ^ *tape++; /* re-encrypt and replace value */
}
inptr++;
return (ch);
}
char breakch; /* tell which char ended rnum */
void
rdata(void) /* "read" data from virtual file */
{
int sect;
char ch;
inptr = data_file; /* Pointer to virtual data file */
srandom(SEED); /* which is lightly encrypted. */
clsses = 1;
for (;;) { /* read data sections */
sect = next() - '0'; /* 1st digit of section number */
#ifdef VERBOSE
printf("Section %c", sect + '0');
#endif
if ((ch = next()) != LF) { /* is there a second digit? */
FLUSHLF;
#ifdef VERBOSE
putchar(ch);
#endif
sect = 10 * sect + ch - '0';
}
#ifdef VERBOSE
putchar('\n');
#endif
switch (sect) {
case 0: /* finished reading database */
return;
case 1: /* long form descriptions */
rdesc(1);
break;
case 2: /* short form descriptions */
rdesc(2);
break;
case 3: /* travel table */
rtrav();
break;
case 4: /* vocabulary */
rvoc();
break;
case 5: /* object descriptions */
rdesc(5);
break;
case 6: /* arbitrary messages */
rdesc(6);
break;
case 7: /* object locations */
rlocs();
break;
case 8: /* action defaults */
rdflt();
break;
case 9: /* liquid assets */
rliq();
break;
case 10: /* class messages */
rdesc(10);
break;
case 11: /* hints */
rhints();
break;
case 12: /* magic messages */
rdesc(12);
break;
default:
printf("Invalid data section number: %d\n", sect);
for (;;)
putchar(next());
}
if (breakch != LF) /* routines return after "-1" */
FLUSHLF;
}
}
char nbf[12];
int
rnum(void) /* read initial location num */
{
char *s;
tape = iotape; /* restart encryption tape */
for (s = nbf, *s = 0;; s++)
if ((*s = next()) == TAB || *s == '\n' || *s == LF)
break;
breakch = *s; /* save char for rtrav() */
*s = 0; /* got the number as ascii */
if (nbf[0] == '-')
return (-1); /* end of data */
return (atoi(nbf)); /* convert it to integer */
}
char *seekhere;
void
rdesc(int sect) /* read description-format msgs */
{
int locc;
char *seekstart, *maystart;
seekhere = inptr; /* Where are we in virtual file?*/
outsw = 1; /* these msgs go into tmp file */
for (oldloc = -1, seekstart = seekhere;;) {
maystart = inptr; /* maybe starting new entry */
if ((locc = rnum()) != oldloc && oldloc >= 0 /* finished msg */
&& !(sect == 5 && (locc == 0 || locc >= 100)))/* unless sect 5*/
{
switch (sect) { /* now put it into right table */
case 1: /* long descriptions */
ltext[oldloc].seekadr = seekhere;
ltext[oldloc].txtlen = maystart - seekstart;
break;
case 2: /* short descriptions */
stext[oldloc].seekadr = seekhere;
stext[oldloc].txtlen = maystart - seekstart;
break;
case 5: /* object descriptions */
ptext[oldloc].seekadr = seekhere;
ptext[oldloc].txtlen = maystart - seekstart;
break;
case 6: /* random messages */
if (oldloc >= RTXSIZ)
errx(1, "Too many random msgs");
rtext[oldloc].seekadr = seekhere;
rtext[oldloc].txtlen = maystart - seekstart;
break;
case 10:/* class messages */
ctext[clsses].seekadr = seekhere;
ctext[clsses].txtlen = maystart - seekstart;
cval[clsses++] = oldloc;
break;
case 12:/* magic messages */
if (oldloc >= MAGSIZ)
errx(1, "Too many magic msgs");
mtext[oldloc].seekadr = seekhere;
mtext[oldloc].txtlen = maystart - seekstart;
break;
default:
errx(1, "rdesc called with bad section");
}
seekhere += maystart - seekstart;
}
if (locc < 0) {
outsw = 0; /* turn off output */
seekhere += 3; /* -1<delimiter> */
return;
}
if (sect != 5 || (locc > 0 && locc < 100)) {
if (oldloc != locc)/* starting a new message */
seekstart = maystart;
oldloc = locc;
}
FLUSHLF; /* scan the line */
}
}
void
rtrav(void) /* read travel table */
{
int locc;
struct travlist *t;
char *s;
char buf[12];
int len, m, n, entries;
for (oldloc = -1;;) { /* get another line */
if ((locc = rnum()) != oldloc && oldloc >= 0) { /* end of entry */
t->next = NULL; /* terminate the old entry */
/* printf("%d:%d entries\n", oldloc, entries); */
/* twrite(oldloc); */
}
if (locc == -1)
return;
if (locc != oldloc) { /* getting a new entry */
t = travel[locc] = calloc(1, sizeof(*t));
if (t == NULL)
err(1, NULL);
/* printf("New travel list for %d\n", locc); */
entries = 0;
oldloc = locc;
}
for (s = buf; ; *s++) /* get the newloc number /ASCII */
if ((*s = next()) == TAB || *s == LF)
break;
*s = 0;
len = length(buf) - 1; /* quad long number handling */
/* printf("Newloc: %s (%d chars)\n", buf, len); */
if (len < 4) { /* no "m" conditions */
m = 0;
n = atoi(buf); /* newloc mod 1000 = newloc */
} else { /* a long integer */
n = atoi(buf + len - 3);
buf[len - 3] = 0; /* terminate newloc/1000*/
m = atoi(buf);
}
while (breakch != LF) { /* only do one line at a time */
if (t == NULL)
errx(1, "corrupt file");
if (entries++) {
t->next = calloc(1, sizeof (*t->next));
if (t->next == NULL)
err(1, NULL);
t = t->next;
}
t->tverb = rnum();/* get verb from the file */
t->tloc = n; /* table entry mod 1000 */
t->conditions = m;/* table entry / 1000 */
/* printf("entry %d for %d\n", entries, locc); */
}
}
}
#ifdef DEBUG
void
twrite(int loq) /* travel options from this loc */
{
struct travlist *t;
printf("If");
speak(<ext[loq]);
printf("then\n");
for (t = travel[loq]; t != 0; t = t->next) {
printf("verb %d takes you to ", t->tverb);
if (t->tloc <= 300)
speak(<ext[t->tloc]);
else if (t->tloc <= 500)
printf("special code %d\n", t->tloc - 300);
else
rspeak(t->tloc - 500);
printf("under conditions %d\n", t->conditions);
}
}
#endif /* DEBUG */
void
rvoc(void)
{
char *s; /* read the vocabulary */
int index;
char buf[6];
for (;;) {
index = rnum();
if (index < 0)
break;
for (s = buf, *s = 0;; s++) /* get the word */
if ((*s = next()) == TAB || *s == '\n' || *s == LF
|| *s == ' ')
break;
/* terminate word with newline, LF, tab, blank */
if (*s != '\n' && *s != LF)
FLUSHLF; /* can be comments */
*s = 0;
/* printf("\"%s\"=%d\n", buf, index);*/
vocab(buf, -2, index);
}
/* prht(); */
}
void
rlocs(void) /* initial object locations */
{
for (;;) {
if ((obj = rnum()) < 0)
break;
plac[obj] = rnum(); /* initial loc for this obj */
if (breakch == TAB) /* there's another entry */
fixd[obj] = rnum();
else
fixd[obj] = 0;
}
}
void
rdflt(void) /* default verb messages */
{
for (;;) {
if ((verb = rnum()) < 0)
break;
actspk[verb] = rnum();
}
}
void
rliq(void) /* liquid assets &c: cond bits */
{
int bitnum;
for (;;) { /* read new bit list */
if ((bitnum = rnum()) < 0)
break;
for (;;) { /* read locs for bits */
cond[rnum()] |= setbit[bitnum];
if (breakch == LF)
break;
}
}
}
void
rhints(void)
{
int hintnum, i;
hntmax = 0;
for (;;) {
if ((hintnum = rnum()) < 0)
break;
for (i = 1; i < 5; i++)
hints[hintnum][i] = rnum();
if (hintnum > hntmax)
hntmax = hintnum;
}
}
void
rspeak(int msg)
{
if (msg != 0)
speak(&rtext[msg]);
}
void
mspeak(int msg)
{
if (msg != 0)
speak(&mtext[msg]);
}
/*
* Read, decrypt, and print a message (not ptext)
* msg is a pointer to seek address and length of mess
*/
void
speak(const struct text *msg)
{
char *s, nonfirst;
s = msg->seekadr;
nonfirst = 0;
while (s - msg->seekadr < msg->txtlen) { /* read a line at a time */
tape = iotape; /* restart decryption tape */
while ((*s++ ^ *tape++) != TAB); /* read past loc num */
/* assume tape is longer than location number */
/* plus the lookahead put together */
if ((*s ^ *tape) == '>' &&
(*(s + 1) ^ *(tape + 1)) == '$' &&
(*(s + 2) ^ *(tape + 2)) == '<')
break;
if (blklin && !nonfirst++)
putchar('\n');
do {
if (*tape == 0)
tape = iotape;/* rewind decryp tape */
putchar(*s ^ *tape);
} while ((*s++ ^ *tape++) != LF); /* better end with LF */
}
}
/*
* Read, decrypt an print a ptext message
* msg is the number of all the p msgs for this place
* assumes object 1 doesn't have prop 1, obj 2 no prop 2 &c
*/
void
pspeak(int m, int skip)
{
char *s, nonfirst;
char *numst, save;
struct text *msg;
char *tbuf;
msg = &ptext[m];
if ((tbuf = (char *) malloc(msg->txtlen + 1)) == 0)
err(1, NULL);
memcpy(tbuf, msg->seekadr, msg->txtlen + 1); /* Room to null */
s = tbuf;
nonfirst = 0;
while (s - tbuf < msg->txtlen) { /* read line at a time */
tape = iotape; /* restart decryption tape */
for (numst = s; (*s ^= *tape++) != TAB; s++)
; /* get number */
save = *s; /* Temporarily trash the string (cringe) */
*s++ = 0; /* decrypting number within the string */
if (atoi(numst) != 100 * skip && skip >= 0) {
while ((*s++ ^ * tape++) != LF) /* flush the line */
if (*tape == 0)
tape = iotape;
continue;
}
if ((*s^ * tape) == '>' && (*(s + 1) ^ * (tape + 1)) == '$' &&
(*(s + 2) ^ * (tape + 2)) == '<')
break;
if (blklin && !nonfirst++)
putchar('\n');
do {
if (*tape == 0)
tape = iotape;
putchar(*s^ * tape);
} while ((*s++ ^ * tape++) != LF); /* better end with LF */
if (skip < 0)
break;
}
free(tbuf);
}