The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
481 lines
9.9 KiB
C
481 lines
9.9 KiB
C
/* NetHack 3.6 macfile.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */
|
|
/* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
/*
|
|
* macfile.c
|
|
* MAC file I/O routines
|
|
*/
|
|
|
|
#include "hack.h"
|
|
#include "macwin.h"
|
|
|
|
#ifndef __MACH__
|
|
#include <files.h>
|
|
#include <errors.h>
|
|
#include <resources.h>
|
|
#include <memory.h>
|
|
#include <TextUtils.h>
|
|
#include <ToolUtils.h>
|
|
#endif
|
|
|
|
#include "dlb.h"
|
|
|
|
/*
|
|
* We should get the default dirID and volRefNum (from name) from prefs and
|
|
* the situation at startup... For now, this will have to do.
|
|
*/
|
|
|
|
/* The HandleFiles are resources built into the application which are treated
|
|
as read-only files: if we fail to open a file we look for a resource */
|
|
|
|
#define FIRST_HF 32000 /* file ID of first HandleFile */
|
|
#define MAX_HF 6 /* Max # of open HandleFiles */
|
|
|
|
#define APP_NAME_RES_ID (-16396)
|
|
|
|
typedef struct handlefile {
|
|
long type; /* Resource type */
|
|
short id; /* Resource id */
|
|
long mark; /* Current position */
|
|
long size; /* total size */
|
|
Handle data; /* The resource, purgeable */
|
|
} HandleFile;
|
|
|
|
static HandleFile *IsHandleFile(int);
|
|
static int OpenHandleFile(const unsigned char *, long);
|
|
static int CloseHandleFile(int);
|
|
static int ReadHandleFile(int, void *, unsigned);
|
|
static long SetHandleFilePos(int, short, long);
|
|
|
|
HandleFile theHandleFiles[MAX_HF];
|
|
MacDirs theDirs; /* also referenced in macwin.c */
|
|
|
|
static HandleFile *
|
|
IsHandleFile(int fd)
|
|
{
|
|
HandleFile *hfp = NULL;
|
|
|
|
if (fd >= FIRST_HF && fd < FIRST_HF + MAX_HF) {
|
|
/* in valid range, check for data */
|
|
hfp = &theHandleFiles[fd - FIRST_HF];
|
|
if (!hfp->data)
|
|
hfp = NULL;
|
|
}
|
|
return hfp;
|
|
}
|
|
|
|
static int
|
|
OpenHandleFile(const unsigned char *name, long fileType)
|
|
{
|
|
int i;
|
|
Handle h;
|
|
Str255 s;
|
|
|
|
for (i = 0; i < MAX_HF; i++) {
|
|
if (theHandleFiles[i].data == 0L)
|
|
break;
|
|
}
|
|
|
|
if (i >= MAX_HF)
|
|
return -1;
|
|
|
|
h = GetNamedResource(fileType, name);
|
|
if (!h)
|
|
return (-1);
|
|
|
|
theHandleFiles[i].data = h;
|
|
theHandleFiles[i].size = GetHandleSize(h);
|
|
GetResInfo(h, &theHandleFiles[i].id, (void *) &theHandleFiles[i].type, s);
|
|
theHandleFiles[i].mark = 0L;
|
|
|
|
return (i + FIRST_HF);
|
|
}
|
|
|
|
static int
|
|
CloseHandleFile(int fd)
|
|
{
|
|
if (!IsHandleFile(fd)) {
|
|
return -1;
|
|
}
|
|
fd -= FIRST_HF;
|
|
ReleaseResource(theHandleFiles[fd].data);
|
|
theHandleFiles[fd].data = 0L;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ReadHandleFile(int fd, void *ptr, unsigned len)
|
|
{
|
|
unsigned maxBytes;
|
|
Handle h;
|
|
|
|
if (!IsHandleFile(fd))
|
|
return -1;
|
|
|
|
fd -= FIRST_HF;
|
|
maxBytes = theHandleFiles[fd].size - theHandleFiles[fd].mark;
|
|
if (len > maxBytes)
|
|
len = maxBytes;
|
|
|
|
h = theHandleFiles[fd].data;
|
|
|
|
HLock(h);
|
|
BlockMove(*h + theHandleFiles[fd].mark, ptr, len);
|
|
HUnlock(h);
|
|
theHandleFiles[fd].mark += len;
|
|
|
|
return (len);
|
|
}
|
|
|
|
static long
|
|
SetHandleFilePos(int fd, short whence, long pos)
|
|
{
|
|
long curpos;
|
|
|
|
if (!IsHandleFile(fd))
|
|
return -1;
|
|
|
|
fd -= FIRST_HF;
|
|
|
|
curpos = theHandleFiles[fd].mark;
|
|
switch (whence) {
|
|
case SEEK_CUR:
|
|
curpos += pos;
|
|
break;
|
|
case SEEK_END:
|
|
curpos = theHandleFiles[fd].size - pos;
|
|
break;
|
|
default: /* set */
|
|
curpos = pos;
|
|
break;
|
|
}
|
|
|
|
if (curpos < 0)
|
|
curpos = 0;
|
|
else if (curpos > theHandleFiles[fd].size)
|
|
curpos = theHandleFiles[fd].size;
|
|
|
|
theHandleFiles[fd].mark = curpos;
|
|
|
|
return curpos;
|
|
}
|
|
|
|
void
|
|
C2P(const char *c, unsigned char *p)
|
|
{
|
|
int len = strlen(c), i;
|
|
|
|
if (len > 255)
|
|
len = 255;
|
|
|
|
for (i = len; i > 0; i--)
|
|
p[i] = c[i - 1];
|
|
p[0] = len;
|
|
}
|
|
|
|
void
|
|
P2C(const unsigned char *p, char *c)
|
|
{
|
|
int idx = *p++;
|
|
for (; idx > 0; idx--)
|
|
*c++ = *p++;
|
|
*c = '\0';
|
|
}
|
|
|
|
static void
|
|
replace_resource(Handle new_res, ResType its_type, short its_id,
|
|
Str255 its_name)
|
|
{
|
|
Handle old_res;
|
|
|
|
SetResLoad(false);
|
|
old_res = Get1Resource(its_type, its_id);
|
|
SetResLoad(true);
|
|
if (old_res) {
|
|
RemoveResource(old_res);
|
|
DisposeHandle(old_res);
|
|
}
|
|
|
|
AddResource(new_res, its_type, its_id, its_name);
|
|
}
|
|
|
|
int
|
|
maccreat(const char *name, long fileType)
|
|
{
|
|
return macopen(name, O_RDWR | O_CREAT | O_TRUNC, fileType);
|
|
}
|
|
|
|
int
|
|
macopen(const char *name, int flags, long fileType)
|
|
{
|
|
short refNum;
|
|
short perm;
|
|
Str255 s;
|
|
|
|
C2P(name, s);
|
|
if (flags & O_CREAT) {
|
|
if (HCreate(theDirs.dataRefNum, theDirs.dataDirID, s, TEXT_CREATOR,
|
|
fileType) && (flags & O_EXCL)) {
|
|
return -1;
|
|
}
|
|
#if 0 /* Fails during makedefs */
|
|
if (fileType == SAVE_TYPE) {
|
|
short resRef;
|
|
HCreateResFile(theDirs.dataRefNum, theDirs.dataDirID, s);
|
|
resRef = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, s,
|
|
fsRdWrPerm);
|
|
if (resRef != -1) {
|
|
Handle name;
|
|
Str255 plnamep;
|
|
|
|
C2P(gp.plname, plnamep);
|
|
name = (Handle)NewString(plnamep);
|
|
if (name)
|
|
replace_resource(name, 'STR ', PLAYER_NAME_RES_ID,
|
|
"\pPlayer Name");
|
|
|
|
/* The application name resource. See IM VI, page 9-21. */
|
|
name = (Handle)GetString(APP_NAME_RES_ID);
|
|
if (name) {
|
|
DetachResource(name);
|
|
replace_resource(name, 'STR ', APP_NAME_RES_ID,
|
|
"\pApplication Name");
|
|
}
|
|
|
|
CloseResFile(resRef);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
/*
|
|
* Here, we should check for file type, maybe a SFdialog if
|
|
* we fail with default, etc. etc. Besides, we should use HOpen
|
|
* and permissions.
|
|
*/
|
|
if ((flags & O_RDONLY) == O_RDONLY) {
|
|
perm = fsRdPerm;
|
|
}
|
|
if ((flags & O_WRONLY) == O_WRONLY) {
|
|
perm = fsWrPerm;
|
|
}
|
|
if ((flags & O_RDWR) == O_RDWR) {
|
|
perm = fsRdWrPerm;
|
|
}
|
|
if (HOpen(theDirs.dataRefNum, theDirs.dataDirID, s, perm, &refNum)) {
|
|
return OpenHandleFile(s, fileType);
|
|
}
|
|
if (flags & O_TRUNC) {
|
|
if (SetEOF(refNum, 0L)) {
|
|
FSClose(refNum);
|
|
return -1;
|
|
}
|
|
}
|
|
return refNum;
|
|
}
|
|
|
|
int
|
|
macclose(int fd)
|
|
{
|
|
if (IsHandleFile(fd)) {
|
|
CloseHandleFile(fd);
|
|
} else {
|
|
if (FSClose(fd)) {
|
|
return -1;
|
|
}
|
|
FlushVol((StringPtr) 0, theDirs.dataRefNum);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
macread(int fd, void *ptr, unsigned len)
|
|
{
|
|
long amt = len;
|
|
|
|
if (IsHandleFile(fd)) {
|
|
return ReadHandleFile(fd, ptr, amt);
|
|
} else {
|
|
short err = FSRead(fd, &amt, ptr);
|
|
|
|
return ((err == noErr) || (err == eofErr && len)) ? amt : -1;
|
|
}
|
|
}
|
|
|
|
#if 0 /* this function isn't used, if you use it, uncomment prototype in \
|
|
macwin.h */
|
|
char *
|
|
macgets (int fd, char *ptr, unsigned len)
|
|
{
|
|
int idx = 0;
|
|
char c;
|
|
|
|
while (-- len > 0) {
|
|
if (macread (fd, ptr + idx, 1) <= 0)
|
|
return (char *)0;
|
|
c = ptr[idx++];
|
|
if (c == '\n' || c == '\r')
|
|
break;
|
|
}
|
|
ptr [idx] = '\0';
|
|
return ptr;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
int
|
|
macwrite(int fd, void *ptr, unsigned len)
|
|
{
|
|
long amt = len;
|
|
|
|
if (IsHandleFile(fd))
|
|
return -1;
|
|
if (FSWrite(fd, &amt, ptr) == noErr)
|
|
return (amt);
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
long
|
|
macseek(int fd, long where, short whence)
|
|
{
|
|
short posMode;
|
|
long curPos;
|
|
|
|
if (IsHandleFile(fd)) {
|
|
return SetHandleFilePos(fd, whence, where);
|
|
}
|
|
|
|
switch (whence) {
|
|
default:
|
|
posMode = fsFromStart;
|
|
break;
|
|
case SEEK_CUR:
|
|
posMode = fsFromMark;
|
|
break;
|
|
case SEEK_END:
|
|
posMode = fsFromLEOF;
|
|
break;
|
|
}
|
|
|
|
if (SetFPos(fd, posMode, where) == noErr && GetFPos(fd, &curPos) == noErr)
|
|
return (curPos);
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
int
|
|
macunlink(const char *name)
|
|
{
|
|
Str255 pname;
|
|
|
|
C2P(name, pname);
|
|
return (HDelete(theDirs.dataRefNum, theDirs.dataDirID, pname) == noErr
|
|
? 0
|
|
: -1);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
boolean
|
|
rsrc_dlb_init(void)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
rsrc_dlb_cleanup(void)
|
|
{
|
|
}
|
|
|
|
boolean
|
|
rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode)
|
|
{
|
|
#if defined(__SC__) || defined(__MRC__)
|
|
#pragma unused(mode)
|
|
#endif
|
|
Str255 pname;
|
|
|
|
C2P(name, pname);
|
|
dp->fd = OpenHandleFile(pname, 'File'); /* automatically read-only */
|
|
return dp->fd >= 0;
|
|
}
|
|
|
|
int
|
|
rsrc_dlb_fclose(dlb *dp)
|
|
{
|
|
return CloseHandleFile(dp->fd);
|
|
}
|
|
|
|
int
|
|
rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp)
|
|
{
|
|
int nread;
|
|
|
|
if (size < 0 || quan < 0)
|
|
return 0;
|
|
nread = ReadHandleFile(dp->fd, buf, (unsigned) size * (unsigned) quan);
|
|
|
|
return nread / size; /* # of whole pieces (== quan in normal case) */
|
|
}
|
|
|
|
int
|
|
rsrc_dlb_fseek(dlb *dp, long pos, int whence)
|
|
{
|
|
return SetHandleFilePos(dp->fd, whence, pos);
|
|
}
|
|
|
|
char *
|
|
rsrc_dlb_fgets(char *buf, int len, dlb *dp)
|
|
{
|
|
HandleFile *hfp = IsHandleFile(dp->fd);
|
|
char *p;
|
|
int bytesLeft, n = 0;
|
|
|
|
if (hfp && hfp->mark < hfp->size) {
|
|
bytesLeft = hfp->size - hfp->mark;
|
|
if (bytesLeft < len)
|
|
len = bytesLeft;
|
|
|
|
HLock(hfp->data);
|
|
for (n = 0, p = *hfp->data + hfp->mark; n < len; n++, p++) {
|
|
buf[n] = *p;
|
|
if (*p == '\r')
|
|
buf[n] = '\n';
|
|
if (buf[n] == '\n') {
|
|
n++; /* we want the return in the buffer */
|
|
break;
|
|
}
|
|
}
|
|
HUnlock(hfp->data);
|
|
|
|
hfp->mark += n;
|
|
if (n != 0)
|
|
buf[n] = '\0'; /* null terminate result */
|
|
}
|
|
|
|
return n ? buf : NULL;
|
|
}
|
|
|
|
int
|
|
rsrc_dlb_fgetc(dlb *dp)
|
|
{
|
|
HandleFile *hfp = IsHandleFile(dp->fd);
|
|
int ret;
|
|
|
|
if (!hfp || hfp->size <= hfp->mark)
|
|
return EOF;
|
|
|
|
ret = *(unsigned char *) (*hfp->data + hfp->mark);
|
|
hfp->mark++;
|
|
return ret;
|
|
}
|
|
|
|
long
|
|
rsrc_dlb_ftell(dlb *dp)
|
|
{
|
|
HandleFile *hfp = IsHandleFile(dp->fd);
|
|
|
|
if (!hfp)
|
|
return 0;
|
|
return hfp->mark;
|
|
}
|