Files
nethack/src/sfstruct.c

367 lines
8.0 KiB
C

/* NetHack 3.7 sfstruct.c $NHDT-Date: 1559994625 2019/06/08 11:50:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.121 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
/*
* historical structlevel savefile writing and reading routines follow.
* These were moved here from save.c and restore.c between 3.6.3 and 3.7.0.
*/
#ifdef TRACE_BUFFERING
#ifdef bufon
#undef bufon
#endif
#ifdef bufoff
#undef bufoff
#endif
#ifdef bflush
#undef bflush
#endif
#ifdef bwrite
#undef bwrite
#endif
#ifdef bclose
#undef bclose
#endif
#ifdef mread
#undef mread
#endif
#ifdef minit
#undef minit
#endif
void FDECL(newread, (NHFILE *, int, int, genericptr_t, unsigned int));
void FDECL(bufon, (int));
void FDECL(bufoff, (int));
void FDECL(bflush, (int));
void FDECL(bwrite, (int, genericptr_t, unsigned int));
void FDECL(mread, (int, genericptr_t, unsigned int));
void NDECL(minit);
void FDECL(bclose, (int));
#endif /* TRACE_BUFFERING */
static int FDECL(getidx, (int, int));
#if defined(UNIX) || defined(WIN32)
#define USE_BUFFERING
#endif
struct restore_info restoreinfo = {
"externalcomp", 0,
};
#define MAXFD 5
enum {NOFLG = 0, NOSLOT = 1};
static int bw_sticky[MAXFD] = {-1,-1,-1,-1,-1};
static int bw_buffered[MAXFD] = {0,0,0,0,0};
#ifdef USE_BUFFERING
static FILE *bw_FILE[MAXFD] = {0,0,0,0,0};
#endif
/*
* Presumably, the fdopen() to allow use of stdio fwrite()
* over write() was done for performance or functionality
* reasons to help some particular platform long ago.
*
* There have been some issues being encountered with the
* implementation due to having an individual set of
* tracking variables, even though there were nested
* sets of open fd (like INSURANCE).
*
* This uses an individual tracking entry for each fd
* being used.
*
* Some notes:
*
* Once buffered IO (stdio) has been enabled on the file
* associated with a descriptor via fdopen():
*
* 1. If you use bufoff and bufon to try and toggle the
* use of write vs fwrite; the code just tracks which
* routine is to be called through the tracking
* variables and acts accordingly.
* bw_sticky[] - used to find the index number for
* the fd that is stored in it, or -1
* if it is a free slot.
* bw_buffered[] - indicator that buffered IO routines
* are available for use.
* bw_FILE[] - the non-zero FILE * for use in calling
* fwrite() when bw_buffered[] is also
* non-zero.
*
* 2. It is illegal to call close(fd) after fdopen(), you
* must always use fclose() on the FILE * from
* that point on, so care must be taken to never call
* close(fd) on the underlying fd or bad things will
* happen.
*/
static int
getidx(fd, flg)
int fd, flg;
{
int i, retval = -1;
for (i = 0; i < MAXFD; ++i)
if (bw_sticky[i] == fd)
return i;
if (flg == NOSLOT)
return retval;
for (i = 0; i < MAXFD; ++i)
if (bw_sticky[i] < 0) {
bw_sticky[i] = fd;
retval = i;
break;
}
return retval;
}
/* Let caller know that bclose() should handle it (TRUE) */
boolean
close_check(fd)
int fd;
{
int idx = getidx(fd, NOSLOT);
boolean retval = FALSE;
if (idx >= 0)
retval = TRUE;
return retval;
}
void
bufon(fd)
int fd;
{
int idx = getidx(fd, NOFLG);
if (idx >= 0) {
bw_sticky[idx] = fd;
#ifdef USE_BUFFERING
if (bw_buffered[idx])
panic("buffering already enabled");
if (!bw_FILE[idx]) {
if ((bw_FILE[idx] = fdopen(fd, "w")) == 0)
panic("buffering of file %d failed", fd);
}
bw_buffered[idx] = (bw_FILE[idx] != 0);
#else
bw_buffered[idx] = 1;
#endif
}
}
void
bufoff(fd)
int fd;
{
int idx = getidx(fd, NOFLG);
if (idx >= 0) {
bflush(fd);
bw_buffered[idx] = 0; /* just a flag that says "use write(fd)" */
}
}
void
bclose(fd)
int fd;
{
int idx = getidx(fd, NOSLOT);
bufoff(fd); /* sets bw_buffered[idx] = 0 */
if (idx >= 0) {
#ifdef USE_BUFFERING
if (bw_FILE[idx]) {
(void) fclose(bw_FILE[idx]);
bw_FILE[idx] = 0;
} else
#endif
close(fd);
/* return the idx to the pool */
bw_sticky[idx] = -1;
}
return;
}
void
bflush(fd)
int fd;
{
int idx = getidx(fd, NOFLG);
if (idx >= 0) {
#ifdef USE_BUFFERING
if (bw_FILE[idx]) {
if (fflush(bw_FILE[idx]) == EOF)
panic("flush of savefile failed!");
}
#endif
}
return;
}
void
bwrite(fd, loc, num)
register int fd;
register genericptr_t loc;
register unsigned num;
{
boolean failed;
int idx = getidx(fd, NOFLG);
if (idx >= 0) {
#ifdef MFLOPPY
bytes_counted += num;
if (count_only)
return;
#endif
#ifdef USE_BUFFERING
if (bw_buffered[idx] && bw_FILE[idx]) {
failed = (fwrite(loc, (int) num, 1, bw_FILE[idx]) != 1);
} else
#endif /* UNIX */
{
/* lint wants 3rd arg of write to be an int; lint -p an unsigned */
#if defined(BSD) || defined(ULTRIX) || defined(WIN32) || defined(_MSC_VER)
failed = ((long) write(fd, loc, (int) num) != (long) num);
#else /* e.g. SYSV, __TURBOC__ */
failed = ((long) write(fd, loc, num) != (long) num);
#endif
}
if (failed) {
#if defined(UNIX) || defined(VMS) || defined(__EMX__)
if (g.program_state.done_hup)
nh_terminate(EXIT_FAILURE);
else
#endif
panic("cannot write %u bytes to file #%d", num, fd);
}
} else
impossible("fd not in list (%d)?", fd);
}
/* ===================================================== */
void
minit()
{
return;
}
void
mread(fd, buf, len)
register int fd;
register genericptr_t buf;
register unsigned int len;
{
register int rlen;
#if defined(BSD) || defined(ULTRIX)
#define readLenType int
#else /* e.g. SYSV, __TURBOC__ */
#define readLenType unsigned
#endif
rlen = read(fd, buf, (readLenType) len);
if ((readLenType) rlen != (readLenType) len) {
if (restoreinfo.mread_flags == 1) { /* means "return anyway" */
restoreinfo.mread_flags = -1;
return;
} else {
pline("Read %d instead of %u bytes.", rlen, len);
if (g.restoring) {
(void) nhclose(fd);
(void) delete_savefile();
error("Error restoring old game.");
}
panic("Error reading level file.");
}
}
}
#ifdef TRACE_BUFFERING
static FILE *tracefile;
#define TFILE "trace-buffering.log"
#define TRACE(xx) \
tracefile = fopen(TFILE, "a"); \
(void) fprintf(tracefile, "%s from %s:%d (%d)\n", __FUNCTION__, fncname, linenum, xx); \
fclose(tracefile);
void
Bufon(fd, fncname, linenum)
int fd;
const char *fncname;
int linenum;
{
TRACE(fd);
bufon(fd);
}
void
Bufoff(fd, fncname, linenum)
int fd;
const char *fncname;
int linenum;
{
TRACE(fd);
bufoff(fd);
}
void
Bflush(fd, fncname, linenum)
int fd;
const char *fncname;
int linenum;
{
TRACE(fd);
bflush(fd);
}
void
Bwrite(fd, loc, num, fncname, linenum)
register int fd;
register genericptr_t loc;
register unsigned num;
const char *fncname;
int linenum;
{
TRACE(fd);
bwrite(fd, loc, num);
}
void
Bclose(fd, fncname, linenum)
int fd;
const char *fncname;
int linenum;
{
TRACE(fd);
bclose(fd);
}
void
Minit(fncname, linenum)
const char *fncname;
int linenum;
{
TRACE(-1);
minit();
}
void
Mread(fd, buf, len, fncname, linenum)
register int fd;
register genericptr_t buf;
register unsigned int len;
const char *fncname;
int linenum;
{
TRACE(fd);
mread(fd, buf, len);
}
#endif