mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 09:49:14 +00:00
GLK: TADS2: Added code for tokenizer & vocabulary
This commit is contained in:
parent
0279143a62
commit
e83972f502
@ -99,6 +99,7 @@ MODULE_OBJS := \
|
||||
tads/tads2/error.o \
|
||||
tads/tads2/error_handling.o \
|
||||
tads/tads2/file_io.o \
|
||||
tads/tads2/line_source_file.o \
|
||||
tads/tads2/memory_cache.o \
|
||||
tads/tads2/memory_cache_heap.o \
|
||||
tads/tads2/memory_cache_loader.o \
|
||||
|
@ -34,8 +34,20 @@ osfildef *osfoprb(const char *fname, os_filetype_t typ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
osfildef *osfoprwtb(const char *fname, os_filetype_t typ) {
|
||||
Common::DumpFile *df = new Common::DumpFile();
|
||||
if (df->open(fname))
|
||||
return df;
|
||||
delete df;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int osfrb(osfildef *fp, void *buf, size_t count) {
|
||||
return fp->read(buf, count);
|
||||
return dynamic_cast<Common::ReadStream *>(fp)->read(buf, count);
|
||||
}
|
||||
|
||||
bool osfwb(osfildef *fp, void *buf, size_t count) {
|
||||
return dynamic_cast<Common::WriteStream *>(fp)->write(buf, count) != count;
|
||||
}
|
||||
|
||||
} // End of namespace TADS
|
||||
|
@ -38,6 +38,12 @@
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
|
||||
#define OSPATHCHAR '/'
|
||||
#define OSPATHALT ""
|
||||
#define OSPATHURL "/"
|
||||
#define OSPATHSEP ':'
|
||||
#define OS_NEWLINE_SEQ "\n"
|
||||
|
||||
|
||||
/* Defined for Gargoyle. */
|
||||
#define HAVE_STDINT_
|
||||
@ -92,8 +98,12 @@ namespace TADS {
|
||||
|
||||
#define OSFNMAX 255
|
||||
|
||||
/* File handle structure for osfxxx functions. */
|
||||
typedef Common::SeekableReadStream osfildef;
|
||||
/**
|
||||
* File handle structure for osfxxx functions
|
||||
* Note that we need to define it as a Common::Stream since the type is used by
|
||||
* TADS for both reading and writing files
|
||||
*/
|
||||
typedef Common::Stream osfildef;
|
||||
|
||||
/* Directory handle for searches via os_open_dir() et al. */
|
||||
typedef Common::FSNode *osdirhdl_t;
|
||||
@ -188,18 +198,18 @@ osfildef *osfoprwt(const char *fname, os_filetype_t typ);
|
||||
#define osfoprs osfoprt
|
||||
|
||||
/* Open binary file for reading. */
|
||||
osfildef *osfoprb(const char *fname, os_filetype_t typ);
|
||||
inline osfildef *osfoprb(const char *fname, os_filetype_t typ);
|
||||
|
||||
/* Open binary file for reading/writing. If the file already exists,
|
||||
* keep the existing contents. Create a new file if it doesn't already
|
||||
* exist. */
|
||||
osfildef*
|
||||
osfoprwb( const char* fname, os_filetype_t typ );
|
||||
osfoprwb(const char *fname, os_filetype_t typ);
|
||||
|
||||
/* Open binary file for reading/writing. If the file already exists,
|
||||
/* Open binary file for writing. If the file already exists,
|
||||
* truncate the existing contents. Create a new file if it doesn't
|
||||
* already exist. */
|
||||
#define osfoprwtb(fname,typ) (fopen((fname),"w+b"))
|
||||
inline osfildef *osfoprwtb(const char *fname, os_filetype_t typ);
|
||||
|
||||
/* Get a line of text from a text file. */
|
||||
#define osfgets fgets
|
||||
@ -208,7 +218,7 @@ osfoprwb( const char* fname, os_filetype_t typ );
|
||||
#define osfputs fputs
|
||||
|
||||
/* Write bytes to file. */
|
||||
#define osfwb(fp,buf,bufl) (fwrite((buf),(bufl),1,(fp))!=1)
|
||||
inline bool osfwb(osfildef *fp, void *buf, size_t count);
|
||||
|
||||
/* Flush buffered writes to a file. */
|
||||
#define osfflush fflush
|
||||
|
@ -28,6 +28,8 @@
|
||||
#define GLK_TADS_TADS2_FILE_IO
|
||||
|
||||
#include "glk/tads/tads2/lib.h"
|
||||
#include "glk/tads/tads2/memory_cache_loader.h"
|
||||
#include "glk/tads/tads2/object.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
@ -35,6 +37,9 @@ namespace TADS2 {
|
||||
|
||||
/* forward declarations */
|
||||
struct voccxdef;
|
||||
struct tokpdef;
|
||||
struct tokthdef;
|
||||
struct tokcxdef;
|
||||
|
||||
/* load-on-demand context (passed in by mcm in load callback) */
|
||||
typedef struct fiolcxdef fiolcxdef;
|
||||
@ -65,20 +70,16 @@ void fiowrt(struct mcmcxdef *mctx, voccxdef *vctx,
|
||||
#define FIOFLIN2 0x80 /* new-style line records */
|
||||
|
||||
/* read game from binary file; sets up loader callback context */
|
||||
void fiord(struct mcmcxdef *mctx, voccxdef *vctx,
|
||||
struct tokcxdef *tctx,
|
||||
char *fname, char *exename,
|
||||
struct fiolcxdef *setupctx, objnum *preinit, uint *flagp,
|
||||
struct tokpdef *path, uchar **fmtsp, uint *fmtlp,
|
||||
uint *pcntptr, int flags, struct appctxdef *appctx,
|
||||
char *argv0);
|
||||
void fiord(mcmcxdef *mctx, voccxdef *vctx, tokcxdef *tctx, char *fname,
|
||||
char *exename, fiolcxdef *setupctx, objnum *preinit, uint *flagp,
|
||||
tokpdef *path, uchar **fmtsp, uint *fmtlp, uint *pcntptr, int flags,
|
||||
appctxdef *appctx, char *argv0);
|
||||
|
||||
/* shut down load-on-demand subsystem, close load file */
|
||||
void fiorcls(fiolcxdef *ctx);
|
||||
|
||||
/* loader callback - load an object on demand */
|
||||
void OS_LOADDS fioldobj(void *ctx, mclhd handle, uchar *ptr,
|
||||
ushort siz);
|
||||
void OS_LOADDS fioldobj(void *ctx, mclhd handle, uchar *ptr, ushort siz);
|
||||
|
||||
/*
|
||||
* Save a game - returns TRUE on failure. We'll save the file to
|
||||
|
@ -134,7 +134,7 @@ void varused();
|
||||
* anything outside of the normal ASCII set as spaces.
|
||||
*/
|
||||
#define t_isspace(c) \
|
||||
(((unsigned char)(c)) <= 127 && isspace((unsigned char)(c)))
|
||||
(((unsigned char)(c)) <= 127 && Common::isSpace((unsigned char)(c)))
|
||||
|
||||
|
||||
/* round a size to worst-case alignment boundary */
|
||||
|
33
engines/glk/tads/tads2/line_source_file.cpp
Normal file
33
engines/glk/tads/tads2/line_source_file.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/tads/tads2/line_source_file.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
namespace TADS2 {
|
||||
|
||||
|
||||
|
||||
} // End of namespace TADS2
|
||||
} // End of namespace TADS
|
||||
} // End of namespace Glk
|
170
engines/glk/tads/tads2/line_source_file.h
Normal file
170
engines/glk/tads/tads2/line_source_file.h
Normal file
@ -0,0 +1,170 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_TADS_TADS2_LINE_SOURCE_FILE
|
||||
#define GLK_TADS_TADS2_LINE_SOURCE_FILE
|
||||
|
||||
#include "glk/tads/tads2/lib.h"
|
||||
#include "glk/tads/tads2/debug.h"
|
||||
#include "glk/tads/tads2/line_source.h"
|
||||
#include "glk/tads/tads2/object.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
namespace TADS2 {
|
||||
|
||||
struct tokpdef;
|
||||
|
||||
/* maximum number of pages of debugging records we can keep */
|
||||
#define LINFPGMAX 128
|
||||
|
||||
/*
|
||||
* executable line information structure: this record relates one
|
||||
* executable line to the object containing the p-code, and the offset
|
||||
* in the object of the p-code for the start of the line
|
||||
*/
|
||||
struct linfinfo {
|
||||
/*
|
||||
* OPCLINE data (file seek position or line number, depending on how
|
||||
* the game was compiled: -ds -> file seek offset, -ds2 -> line
|
||||
* number)
|
||||
*/
|
||||
ulong fpos;
|
||||
|
||||
/* object number */
|
||||
objnum objn;
|
||||
|
||||
/* offset from start of code */
|
||||
uint ofs;
|
||||
};
|
||||
|
||||
/*
|
||||
* file line source
|
||||
*/
|
||||
struct linfdef {
|
||||
lindef linflin; /* superclass data */
|
||||
osfildef *linffp; /* file pointer for this line source */
|
||||
char linfbuf[100]; /* buffer for the line contents */
|
||||
int linfbufnxt; /* offset in buffer of start of next line */
|
||||
int linfnxtlen; /* length of data after linfbufnxt */
|
||||
ulong linfnum; /* current line number */
|
||||
ulong linfseek; /* seek position of current line */
|
||||
mcmcxdef *linfmem; /* memory manager context */
|
||||
mcmon linfpg[LINFPGMAX]; /* pages for debugging records */
|
||||
ulong linfcrec; /* number of debugger records written so far */
|
||||
char linfnam[1]; /* name of file being read */
|
||||
};
|
||||
|
||||
/* initialize a file line source, opening the file for the line source */
|
||||
linfdef *linfini(mcmcxdef *mctx, errcxdef *errctx, char *filename,
|
||||
int flen, tokpdef *path, int must_find_file,
|
||||
int new_line_records);
|
||||
|
||||
/* initialize a pre-allocated linfdef, skipping debugger page setup */
|
||||
void linfini2(mcmcxdef *mctx, linfdef *linf,
|
||||
char *filename, int flen, osfildef *fp, int new_line_records);
|
||||
|
||||
/* get next line from line source */
|
||||
int linfget(lindef *lin);
|
||||
|
||||
/* generate printable rep of current position in source (for errors) */
|
||||
void linfppos(lindef *lin, char *buf, uint bufl);
|
||||
|
||||
/* close line source */
|
||||
void linfcls(lindef *lin);
|
||||
|
||||
/* generate source-line debug instruction operand */
|
||||
void linfglop(lindef *lin, uchar *buf);
|
||||
|
||||
/* generate new-style source-line debug instructino operand */
|
||||
void linfglop2(lindef *lin, uchar *buf);
|
||||
|
||||
/* save line source to binary (.gam) file */
|
||||
int linfwrt(lindef *lin, osfildef *fp);
|
||||
|
||||
/* load a file-line-source from binary (.gam) file */
|
||||
int linfload(osfildef *fp, dbgcxdef *dbgctx, errcxdef *ec,
|
||||
tokpdef *path);
|
||||
|
||||
/* add a debugger line record for the current line */
|
||||
void linfcmp(lindef *lin, uchar *buf);
|
||||
|
||||
/* find nearest line record to a file seek location */
|
||||
void linffind(lindef *lin, char *buf, objnum *objp, uint *ofsp);
|
||||
|
||||
/* activate line source for debugging */
|
||||
void linfact(lindef *lin);
|
||||
|
||||
/* disactivate line source */
|
||||
void linfdis(lindef *lin);
|
||||
|
||||
/* get current seek position */
|
||||
void linftell(lindef *lin, uchar *pos);
|
||||
|
||||
/* seek */
|
||||
void linfseek(lindef *lin, uchar *pos);
|
||||
|
||||
/* read */
|
||||
int linfread(lindef *lin, uchar *buf, uint siz);
|
||||
|
||||
/* add a signed delta to a seek positon */
|
||||
void linfpadd(lindef *lin, uchar *pos, long delta);
|
||||
|
||||
/* query whether at top of file */
|
||||
int linfqtop(lindef *lin, uchar *pos);
|
||||
|
||||
/* read one line at current seek position */
|
||||
int linfgets(lindef *lin, uchar *buf, uint bufsiz);
|
||||
|
||||
/* get name of line source */
|
||||
void linfnam(lindef *lin, char *buf);
|
||||
|
||||
/* get the current line number */
|
||||
ulong linflnum(lindef *lin);
|
||||
|
||||
/* go to top or bottom */
|
||||
void linfgoto(lindef *lin, int where);
|
||||
|
||||
/* return the current offset in the line source */
|
||||
long linfofs(lindef *lin);
|
||||
|
||||
/* renumber an object */
|
||||
void linfren(lindef *lin, objnum oldnum, objnum newnum);
|
||||
|
||||
/* delete an object */
|
||||
void linfdelnum(lindef *lin, objnum objn);
|
||||
|
||||
/* copy line records to an array of linfinfo structures */
|
||||
void linf_copy_linerecs(linfdef *linf, linfinfo *info);
|
||||
|
||||
/* debugging echo */
|
||||
#ifdef DEBUG
|
||||
# define LINFDEBUG(x) x
|
||||
#else /* DEBUG */
|
||||
# define LINFDEBUG(x)
|
||||
#endif /* DEBUG */
|
||||
|
||||
} // End of namespace TADS2
|
||||
} // End of namespace TADS
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
@ -56,6 +56,7 @@ void TADS2::runGame() {
|
||||
}
|
||||
|
||||
void TADS2::trdmain1(errcxdef *errctx) {
|
||||
#ifdef TODO
|
||||
osfildef *swapfp = (osfildef *)0;
|
||||
runcxdef runctx;
|
||||
bifcxdef bifctx;
|
||||
@ -99,7 +100,7 @@ void TADS2::trdmain1(errcxdef *errctx) {
|
||||
char *charmap = 0; /* character map file */
|
||||
int charmap_none; /* explicitly do not use a character set */
|
||||
int doublespace = TRUE; /* formatter double-space setting */
|
||||
#ifdef TODO
|
||||
|
||||
NOREG((&loadopen))
|
||||
|
||||
/* initialize the output formatter */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
||||
#include "glk/tads/tads2/lib.h"
|
||||
#include "glk/tads/tads2/error_handling.h"
|
||||
#include "glk/tads/tads2/line_source.h"
|
||||
#include "glk/tads/tads2/line_source_file.h"
|
||||
#include "glk/tads/tads2/memory_cache.h"
|
||||
|
||||
namespace Glk {
|
||||
@ -356,7 +357,7 @@ struct tokcxdef {
|
||||
int tokcxifcnt; /* number of #endif's we expect to find */
|
||||
char tokcxif[TOKIFNEST]; /* #if state for each nesting level */
|
||||
int tokcxifcur; /* current #if state, obeying nesting */
|
||||
struct linfdef *tokcxhdr; /* list of previously included headers */
|
||||
linfdef *tokcxhdr; /* list of previously included headers */
|
||||
tokscdef *tokcxsc[1]; /* special character table */
|
||||
};
|
||||
|
||||
@ -453,16 +454,16 @@ void tok_write_defines(tokcxdef *ctx, osfildef *fp, errcxdef *ec);
|
||||
|
||||
/* determine if a char is a valid non-initial character in a symbol name */
|
||||
#define TOKISSYM(c) \
|
||||
(isalpha((uchar)(c)) || isdigit((uchar)(c)) || (c)=='_' || (c)=='$')
|
||||
(Common::isAlpha((uchar)(c)) || Common::isDigit((uchar)(c)) || (c)=='_' || (c)=='$')
|
||||
|
||||
/* numeric conversion and checking macros */
|
||||
#define TOKISHEX(c) \
|
||||
(isdigit((uchar)(c))||((c)>='a'&&(c)<='f')||((c)>='A'&&(c)<='F'))
|
||||
(Common::isDigit((uchar)(c))||((c)>='a'&&(c)<='f')||((c)>='A'&&(c)<='F'))
|
||||
#define TOKISOCT(c) \
|
||||
(isdigit((uchar)(c))&&!((c)=='8'||(c)=='9'))
|
||||
(Common::isDigit((uchar)(c))&&!((c)=='8'||(c)=='9'))
|
||||
|
||||
#define TOKHEX2INT(c) \
|
||||
(isdigit((uchar)c)?(c)-'0':((c)>='a'?(c)-'a'+10:(c)-'A'+10))
|
||||
(Common::isDigit((uchar)c)?(c)-'0':((c)>='a'?(c)-'a'+10:(c)-'A'+10))
|
||||
#define TOKOCT2INT(c) ((c)-'0')
|
||||
#define TOKDEC2INT(c) ((c)-'0')
|
||||
|
||||
|
@ -22,12 +22,912 @@
|
||||
|
||||
#include "glk/tads/tads2/run.h"
|
||||
#include "glk/tads/tads2/vocabulary.h"
|
||||
#include "glk/tads/tads2/error.h"
|
||||
#include "glk/tads/tads2/memory_cache_heap.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
namespace TADS2 {
|
||||
|
||||
// TODO: Rest of vocabulary stuff
|
||||
|
||||
/*
|
||||
* Main vocabulary context. This can be saved globally if desired, so
|
||||
* that routines that don't have any other access to it (such as
|
||||
* Unix-style signal handlers) can reach it.
|
||||
*/
|
||||
voccxdef *main_voc_ctx = 0;
|
||||
|
||||
#ifdef VOCW_IN_CACHE
|
||||
vocwdef *vocwget(voccxdef *ctx, uint idx)
|
||||
{
|
||||
uint pg;
|
||||
|
||||
if (idx == VOCCXW_NONE)
|
||||
return 0;
|
||||
|
||||
/* get the page we need */
|
||||
pg = idx/VOCWPGSIZ;
|
||||
|
||||
/* if it's not locked, lock it */
|
||||
if (pg != ctx->voccxwplck)
|
||||
{
|
||||
/* unlock the old page */
|
||||
if (ctx->voccxwplck != MCMONINV)
|
||||
mcmunlck(ctx->voccxmem, ctx->voccxwp[ctx->voccxwplck]);
|
||||
|
||||
/* lock the new page */
|
||||
ctx->voccxwpgptr = (vocwdef *)mcmlck(ctx->voccxmem,
|
||||
ctx->voccxwp[pg]);
|
||||
ctx->voccxwplck = pg;
|
||||
}
|
||||
|
||||
/* return the entry on that page */
|
||||
return ctx->voccxwpgptr + (idx % VOCWPGSIZ);
|
||||
}
|
||||
#endif /*VOCW_IN_CACHE */
|
||||
|
||||
/* hash value is based on first 6 characters only to allow match-in-6 */
|
||||
uint vochsh(uchar *t, int len)
|
||||
{
|
||||
uint ret = 0;
|
||||
|
||||
if (len > 6) len = 6;
|
||||
for ( ; len ; --len, ++t)
|
||||
ret = (ret + (uint)(vocisupper(*t) ? tolower(*t) : *t))
|
||||
& (VOCHASHSIZ - 1);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* copy vocabulary word, and convert to lower case */
|
||||
static void voccpy(uchar *dst, uchar *src, int len)
|
||||
{
|
||||
for ( ; len ; --len, ++dst, ++src)
|
||||
*dst = vocisupper(*src) ? tolower(*src) : *src;
|
||||
}
|
||||
|
||||
/* allocate and set up a new vocwdef record, linking into a vocdef's list */
|
||||
static void vocwset(voccxdef *ctx, vocdef *v, prpnum p, objnum objn,
|
||||
int classflg)
|
||||
{
|
||||
vocwdef *vw;
|
||||
uint inx;
|
||||
vocwdef *vw2;
|
||||
|
||||
/*
|
||||
* look through the vocdef list to see if there's an existing entry
|
||||
* with the DELETED marker -- if so, simply undelete it
|
||||
*/
|
||||
for (inx = v->vocwlst, vw = vocwget(ctx, inx) ; vw ;
|
||||
inx = vw->vocwnxt, vw = vocwget(ctx, inx))
|
||||
{
|
||||
/* if this entry was deleted, and otherwise matches, undelete it */
|
||||
if ((vw->vocwflg & VOCFDEL)
|
||||
&& vw->vocwobj == objn && vw->vocwtyp == p)
|
||||
{
|
||||
/*
|
||||
* Remove the deleted flag. We will otherwise leave the
|
||||
* flags unchanged, since the VOCFDEL flag applies only to
|
||||
* statically allocated objects, and hence the original
|
||||
* flags should take precedence over any run-time flags.
|
||||
*/
|
||||
vw->vocwflg &= ~VOCFDEL;
|
||||
|
||||
/* we're done */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure the word+object+type record isn't already defined */
|
||||
for (inx = v->vocwlst, vw = vocwget(ctx, inx) ; vw ;
|
||||
inx = vw->vocwnxt, vw = vocwget(ctx, inx))
|
||||
{
|
||||
if (vw->vocwobj == objn && vw->vocwtyp == p
|
||||
&& (vw->vocwflg & VOCFCLASS) == (classflg & VOCFCLASS))
|
||||
{
|
||||
/* it matches - don't add a redundant record */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* look in the free list for an available vocwdef */
|
||||
if (ctx->voccxwfre != VOCCXW_NONE)
|
||||
{
|
||||
inx = ctx->voccxwfre;
|
||||
vw = vocwget(ctx, inx); /* get the free vocwdef */
|
||||
ctx->voccxwfre = vw->vocwnxt; /* unlink from free list */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allocate another page of vocwdef's if necssary */
|
||||
if ((ctx->voccxwalocnt % VOCWPGSIZ) == 0)
|
||||
{
|
||||
int pg = ctx->voccxwalocnt / VOCWPGSIZ;
|
||||
|
||||
/* make sure we haven't exceeded the available page count */
|
||||
if (pg >= VOCWPGMAX) errsig(ctx->voccxerr, ERR_VOCMNPG);
|
||||
|
||||
/* allocate on the new page */
|
||||
#ifdef VOCW_IN_CACHE
|
||||
mcmalo(ctx->voccxmem, (ushort)(VOCWPGSIZ * sizeof(vocwdef)),
|
||||
&ctx->voccxwp[pg]);
|
||||
mcmunlck(ctx->voccxmem, ctx->voccxwp[pg]);
|
||||
#else
|
||||
ctx->voccxwp[pg] =
|
||||
(vocwdef *)mchalo(ctx->voccxerr,
|
||||
(VOCWPGSIZ * sizeof(vocwdef)),
|
||||
"vocwset");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* get the next entry, and increment count of used entries */
|
||||
inx = ctx->voccxwalocnt++;
|
||||
vw = vocwget(ctx, inx);
|
||||
}
|
||||
|
||||
/* link the new vocwdef into the vocdef's relation list */
|
||||
vw->vocwnxt = v->vocwlst;
|
||||
v->vocwlst = inx;
|
||||
|
||||
/* set up the new vocwdef */
|
||||
vw->vocwtyp = (uchar)p;
|
||||
vw->vocwobj = objn;
|
||||
vw->vocwflg = classflg;
|
||||
|
||||
/*
|
||||
* Scan the list and make sure we're not adding a redundant verb.
|
||||
* Don't bother with the warning if this is a class.
|
||||
*/
|
||||
if (p == PRP_VERB && (ctx->voccxflg & VOCCXFVWARN)
|
||||
&& (vw->vocwflg & VOCFCLASS) == 0)
|
||||
{
|
||||
for (vw2 = vocwget(ctx, v->vocwlst) ; vw2 ;
|
||||
vw2 = vocwget(ctx, vw2->vocwnxt))
|
||||
{
|
||||
/*
|
||||
* if this is a different object, and it's not a class, and
|
||||
* it's defined as a verb, warn about it
|
||||
*/
|
||||
if (vw2 != vw
|
||||
&& (vw2->vocwflg & VOCFCLASS) == 0
|
||||
&& vw2->vocwtyp == PRP_VERB)
|
||||
{
|
||||
if (v->vocln2 != 0)
|
||||
errlog2(ctx->voccxerr, ERR_VOCREVB,
|
||||
ERRTSTR,
|
||||
errstr(ctx->voccxerr,
|
||||
(char *)v->voctxt, v->voclen),
|
||||
ERRTSTR,
|
||||
errstr(ctx->voccxerr,
|
||||
(char *)v->voctxt + v->voclen, v->vocln2));
|
||||
else
|
||||
errlog1(ctx->voccxerr, ERR_VOCREVB,
|
||||
ERRTSTR,
|
||||
errstr(ctx->voccxerr,
|
||||
(char *)v->voctxt, v->voclen));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set up a vocdef record, and link into hash table */
|
||||
static void vocset(voccxdef *ctx, vocdef *v, prpnum p, objnum objn,
|
||||
int classflg, uchar *wrdtxt, int len,
|
||||
uchar *wrd2, int len2)
|
||||
{
|
||||
uint hshval = vochsh(wrdtxt, len);
|
||||
|
||||
v->vocnxt = ctx->voccxhsh[hshval];
|
||||
ctx->voccxhsh[hshval] = v;
|
||||
|
||||
v->voclen = len;
|
||||
v->vocln2 = len2;
|
||||
voccpy(v->voctxt, wrdtxt, len);
|
||||
if (wrd2) voccpy(v->voctxt + len, wrd2, len2);
|
||||
|
||||
/* allocate and initialize a vocwdef for the object */
|
||||
vocwset(ctx, v, p, objn, classflg);
|
||||
}
|
||||
|
||||
/* internal addword - already parsed into two words and have lengths */
|
||||
void vocadd2(voccxdef *ctx, prpnum p, objnum objn, int classflg,
|
||||
uchar *wrdtxt, int len, uchar *wrd2, int len2)
|
||||
{
|
||||
vocdef *v;
|
||||
vocdef *prv;
|
||||
uint need;
|
||||
uint hshval;
|
||||
|
||||
/* if the word is null, ignore it entirely */
|
||||
if (len == 0 && len2 == 0)
|
||||
return;
|
||||
|
||||
/* look for a vocdef entry with the same word text */
|
||||
hshval = vochsh(wrdtxt, len);
|
||||
for (v = ctx->voccxhsh[hshval] ; v ; v = v->vocnxt)
|
||||
{
|
||||
/* if it matches on both words, use this entry */
|
||||
if (v->voclen == len && !memcmp(wrdtxt, v->voctxt, (size_t)len)
|
||||
&& ((!wrd2 && v->vocln2 == 0)
|
||||
|| (v->vocln2 == len2 &&
|
||||
!memcmp(wrd2, v->voctxt + len, (size_t)len2))))
|
||||
{
|
||||
vocwset(ctx, v, p, objn, classflg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* look for a free vocdef entry of the same size */
|
||||
for (prv = (vocdef *)0, v = ctx->voccxfre ; v ; prv = v, v = v->vocnxt)
|
||||
if (v->voclen == len + len2) break;
|
||||
|
||||
if (v)
|
||||
{
|
||||
/* we found something - unlink from free list */
|
||||
if (prv) prv->vocnxt = v->vocnxt;
|
||||
else ctx->voccxfre = v->vocnxt;
|
||||
|
||||
/* reuse the entry */
|
||||
v->vocwlst = VOCCXW_NONE;
|
||||
vocset(ctx, v, p, objn, classflg, wrdtxt, len, wrd2, len2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* didn't find an existing vocdef; allocate a new one */
|
||||
need = sizeof(vocdef) + len + len2 - 1;
|
||||
if (ctx->voccxrem < need)
|
||||
{
|
||||
/* not enough space in current page; allocate a new one */
|
||||
ctx->voccxpool = mchalo(ctx->voccxerr, VOCPGSIZ, "vocadd2");
|
||||
ctx->voccxrem = VOCPGSIZ;
|
||||
}
|
||||
|
||||
/* use top of current pool, and update pool pointer and size */
|
||||
v = (vocdef *)ctx->voccxpool;
|
||||
need = osrndsz(need);
|
||||
ctx->voccxpool += need;
|
||||
if (ctx->voccxrem > need) ctx->voccxrem -= need;
|
||||
else ctx->voccxrem = 0;
|
||||
|
||||
/* set up new vocdef */
|
||||
v->vocwlst = VOCCXW_NONE;
|
||||
vocset(ctx, v, p, objn, classflg, wrdtxt, len, wrd2, len2);
|
||||
}
|
||||
|
||||
static void voc_parse_words(char **wrdtxt, int *len, char **wrd2, int *len2)
|
||||
{
|
||||
/* get length and pointer to actual text */
|
||||
*len = osrp2(*wrdtxt) - 2;
|
||||
*wrdtxt += 2;
|
||||
|
||||
/* see if there's a second word - look for a space */
|
||||
for (*wrd2 = *wrdtxt, *len2 = *len ; *len2 && !vocisspace(**wrd2) ;
|
||||
++*wrd2, --*len2) ;
|
||||
if (*len2)
|
||||
{
|
||||
*len -= *len2;
|
||||
while (*len2 && vocisspace(**wrd2)) ++*wrd2, --*len2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no space ==> no second word */
|
||||
*wrd2 = (char *)0;
|
||||
}
|
||||
}
|
||||
|
||||
void vocadd(voccxdef *ctx, prpnum p, objnum objn, int classflg, char *wrdtxt)
|
||||
{
|
||||
int len;
|
||||
char *wrd2;
|
||||
int len2;
|
||||
|
||||
voc_parse_words(&wrdtxt, &len, &wrd2, &len2);
|
||||
vocadd2(ctx, p, objn, classflg, (uchar *)wrdtxt, len, (uchar *)wrd2, len2);
|
||||
}
|
||||
|
||||
/* make sure we have a page table entry for an object, allocating one if not */
|
||||
void vocialo(voccxdef *ctx, objnum obj)
|
||||
{
|
||||
if (!ctx->voccxinh[obj >> 8])
|
||||
{
|
||||
ctx->voccxinh[obj >> 8] =
|
||||
(vocidef **)mchalo(ctx->voccxerr,
|
||||
(256 * sizeof(vocidef *)), "vocialo");
|
||||
memset(ctx->voccxinh[obj >> 8], 0, (size_t)(256 * sizeof(vocidef *)));
|
||||
}
|
||||
}
|
||||
|
||||
/* add an inheritance/location record */
|
||||
void vociadd(voccxdef *ctx, objnum obj, objnum loc,
|
||||
int numsc, objnum *sc, int flags)
|
||||
{
|
||||
vocidef *v;
|
||||
vocidef *min;
|
||||
vocidef *prv;
|
||||
vocidef *minprv = nullptr;
|
||||
|
||||
/* make sure we have a page table entry for this object */
|
||||
vocialo(ctx, obj);
|
||||
|
||||
/* look in free list for an entry that's big enough */
|
||||
for (prv = (vocidef *)0, min = (vocidef *)0, v = ctx->voccxifr ; v ;
|
||||
prv = v, v = v->vocinxt)
|
||||
{
|
||||
if (v->vocinsc == numsc)
|
||||
{
|
||||
min = v;
|
||||
minprv = prv;
|
||||
break;
|
||||
}
|
||||
else if (v->vocinsc > numsc)
|
||||
{
|
||||
if (!min || v->vocinsc < min->vocinsc)
|
||||
{
|
||||
min = v;
|
||||
minprv = prv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!min)
|
||||
{
|
||||
uint need;
|
||||
|
||||
/* nothing in free list; allocate a new entry */
|
||||
need = osrndsz(sizeof(vocidef) + (numsc - 1)*sizeof(objnum));
|
||||
if (ctx->voccxilst + need >= VOCISIZ)
|
||||
{
|
||||
/* nothing left on current page; allocate a new page */
|
||||
ctx->voccxip[++(ctx->voccxiplst)] =
|
||||
mchalo(ctx->voccxerr, VOCISIZ, "vociadd");
|
||||
ctx->voccxilst = 0;
|
||||
}
|
||||
|
||||
/* allocate space out of current page */
|
||||
v = (vocidef *)(ctx->voccxip[ctx->voccxiplst] + ctx->voccxilst);
|
||||
ctx->voccxilst += need;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlink from chain and use */
|
||||
v = min;
|
||||
if (minprv)
|
||||
minprv->vocinxt = v->vocinxt;
|
||||
else
|
||||
ctx->voccxifr = v->vocinxt;
|
||||
}
|
||||
|
||||
/* set up the entry */
|
||||
if (vocinh(ctx, obj) != (vocidef *)0) errsig(ctx->voccxerr, ERR_VOCINUS);
|
||||
v->vociloc = loc;
|
||||
v->vociilc = MCMONINV;
|
||||
v->vociflg = (flags & ~VOCIFXLAT);
|
||||
v->vocinsc = numsc;
|
||||
if (numsc)
|
||||
{
|
||||
if (flags & VOCIFXLAT)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < numsc ; ++i)
|
||||
v->vocisc[i] = osrp2(&sc[i]);
|
||||
}
|
||||
else
|
||||
memcpy(v->vocisc, sc, (size_t)(numsc * sizeof(objnum)));
|
||||
}
|
||||
vocinh(ctx, obj) = v; /* set page table entry */
|
||||
}
|
||||
|
||||
/* revert all objects to original state, using inheritance records */
|
||||
void vocrevert(voccxdef *vctx)
|
||||
{
|
||||
vocidef ***vpg;
|
||||
vocidef **v;
|
||||
int i;
|
||||
int j;
|
||||
objnum obj;
|
||||
|
||||
/*
|
||||
* Go through the inheritance records. Delete each dynamically
|
||||
* allocated object, and revert each static object to its original
|
||||
* load state.
|
||||
*/
|
||||
for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
|
||||
{
|
||||
if (!*vpg) continue;
|
||||
for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j)
|
||||
{
|
||||
if (*v)
|
||||
{
|
||||
/* if the object was dynamically allocated, delete it */
|
||||
if ((*v)->vociflg & VOCIFNEW)
|
||||
{
|
||||
/* delete vocabulary and inheritance data for the object */
|
||||
vocidel(vctx, obj);
|
||||
vocdel(vctx, obj);
|
||||
|
||||
/* delete the object */
|
||||
mcmfre(vctx->voccxmem, (mcmon)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* revert the object */
|
||||
mcmrevert(vctx->voccxmem, (mcmon)obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Revert the vocabulary list: delete all newly added words, and
|
||||
* undelete all original words marked as deleted.
|
||||
*/
|
||||
vocdel1(vctx, MCMONINV, (char *)0, 0, TRUE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/* initialize voc context */
|
||||
void vocini(voccxdef *vocctx, errcxdef *errctx, mcmcxdef *memctx,
|
||||
runcxdef *runctx, objucxdef *undoctx,
|
||||
int fuses, int daemons, int notifiers)
|
||||
{
|
||||
CLRSTRUCT(*vocctx);
|
||||
vocctx->voccxerr = errctx;
|
||||
vocctx->voccxiplst = (uint)-1;
|
||||
vocctx->voccxilst = VOCISIZ;
|
||||
vocctx->voccxmem = memctx;
|
||||
vocctx->voccxrun = runctx;
|
||||
vocctx->voccxundo = undoctx;
|
||||
|
||||
vocctx->voccxme =
|
||||
vocctx->voccxme_init =
|
||||
vocctx->voccxvtk =
|
||||
vocctx->voccxstr =
|
||||
vocctx->voccxnum =
|
||||
vocctx->voccxit =
|
||||
vocctx->voccxhim =
|
||||
vocctx->voccxprd =
|
||||
vocctx->voccxpre =
|
||||
vocctx->voccxpre2 =
|
||||
vocctx->voccxppc =
|
||||
vocctx->voccxlsv =
|
||||
vocctx->voccxpreinit =
|
||||
vocctx->voccxper =
|
||||
vocctx->voccxprom =
|
||||
vocctx->voccxpostprom =
|
||||
vocctx->voccxpdis =
|
||||
vocctx->voccxper2 =
|
||||
vocctx->voccxperp =
|
||||
vocctx->voccxpdef =
|
||||
vocctx->voccxpdef2 =
|
||||
vocctx->voccxpask =
|
||||
vocctx->voccxpask2 =
|
||||
vocctx->voccxpask3 =
|
||||
vocctx->voccxinitrestore =
|
||||
vocctx->voccxpuv =
|
||||
vocctx->voccxpnp =
|
||||
vocctx->voccxpostact =
|
||||
vocctx->voccxendcmd =
|
||||
vocctx->voccxher = MCMONINV;
|
||||
vocctx->voccxthc = 0;
|
||||
#ifdef VOCW_IN_CACHE
|
||||
vocctx->voccxwplck = MCMONINV;
|
||||
#endif
|
||||
|
||||
vocctx->voccxactor = MCMONINV;
|
||||
vocctx->voccxverb = MCMONINV;
|
||||
vocctx->voccxprep = MCMONINV;
|
||||
vocctx->voccxdobj = 0;
|
||||
vocctx->voccxiobj = 0;
|
||||
|
||||
vocctx->voccxunknown = 0;
|
||||
vocctx->voccxlastunk = 0;
|
||||
|
||||
vocctx->voc_stk_ptr = 0;
|
||||
vocctx->voc_stk_cur = 0;
|
||||
vocctx->voc_stk_end = 0;
|
||||
|
||||
/* allocate fuses, daemons, notifiers */
|
||||
vocinialo(vocctx, &vocctx->voccxfus, (vocctx->voccxfuc = fuses));
|
||||
vocinialo(vocctx, &vocctx->voccxdmn, (vocctx->voccxdmc = daemons));
|
||||
vocinialo(vocctx, &vocctx->voccxalm, (vocctx->voccxalc = notifiers));
|
||||
|
||||
/* no entries in vocwdef free list yet */
|
||||
vocctx->voccxwfre = VOCCXW_NONE;
|
||||
}
|
||||
|
||||
/* uninitialize the voc context */
|
||||
void vocterm(voccxdef *ctx)
|
||||
{
|
||||
/* delete the fuses, daemons, and notifiers */
|
||||
voctermfree(ctx->voccxfus);
|
||||
voctermfree(ctx->voccxdmn);
|
||||
voctermfree(ctx->voccxalm);
|
||||
|
||||
/* delete the private stack */
|
||||
if (ctx->voc_stk_ptr != 0)
|
||||
mchfre(ctx->voc_stk_ptr);
|
||||
}
|
||||
|
||||
/* clean up the vocab context */
|
||||
void voctermfree(vocddef *what)
|
||||
{
|
||||
if (what != 0)
|
||||
mchfre(what);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through all words for a particular object, calling a
|
||||
* function with each vocwdef found. If objn == MCMONINV, we'll call
|
||||
* the callback for every word.
|
||||
*/
|
||||
void voc_iterate(voccxdef *ctx, objnum objn,
|
||||
void (*fn)(void *, vocdef *, vocwdef *), void *fnctx)
|
||||
{
|
||||
int i;
|
||||
vocdef *v;
|
||||
vocdef **vp;
|
||||
vocwdef *vw;
|
||||
uint idx;
|
||||
|
||||
/* go through each hash value looking for matching words */
|
||||
for (i = VOCHASHSIZ, vp = ctx->voccxhsh ; i ; ++vp, --i)
|
||||
{
|
||||
/* go through all words in this hash chain */
|
||||
for (v = *vp ; v ; v = v->vocnxt)
|
||||
{
|
||||
/* go through each object relation for this word */
|
||||
for (idx = v->vocwlst, vw = vocwget(ctx, idx) ; vw ;
|
||||
idx = vw->vocwnxt, vw = vocwget(ctx, idx))
|
||||
{
|
||||
/*
|
||||
* if this word is for this object, call the callback
|
||||
*/
|
||||
if (objn == MCMONINV || vw->vocwobj == objn)
|
||||
(*fn)(fnctx, v, vw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* callback context for voc_count */
|
||||
struct voc_count_ctx
|
||||
{
|
||||
int cnt;
|
||||
int siz;
|
||||
prpnum prp;
|
||||
};
|
||||
|
||||
/* callback for voc_count */
|
||||
static void voc_count_cb(void *ctx0, vocdef *voc, vocwdef *vocw)
|
||||
{
|
||||
struct voc_count_ctx *ctx = (struct voc_count_ctx *)ctx0;
|
||||
|
||||
VARUSED(vocw);
|
||||
|
||||
/*
|
||||
* If it matches the property (or we want all properties), count
|
||||
* it. Don't count deleted objects.
|
||||
*/
|
||||
if ((ctx->prp == 0 || ctx->prp == vocw->vocwtyp)
|
||||
&& !(vocw->vocwflg & VOCFDEL))
|
||||
{
|
||||
/* count the word */
|
||||
ctx->cnt++;
|
||||
|
||||
/* count the size */
|
||||
ctx->siz += voc->voclen + voc->vocln2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number and size of words defined for an object. The size
|
||||
* returns the total byte count from all the words involved. Do not
|
||||
* include deleted words in the count.
|
||||
*/
|
||||
void voc_count(voccxdef *ctx, objnum objn, prpnum prp, int *cnt, int *siz)
|
||||
{
|
||||
struct voc_count_ctx fnctx;
|
||||
|
||||
/* set up the context with zero initial counts */
|
||||
fnctx.cnt = 0;
|
||||
fnctx.siz = 0;
|
||||
fnctx.prp = prp;
|
||||
|
||||
/* iterate over all words for the object with our callback */
|
||||
voc_iterate(ctx, objn, voc_count_cb, &fnctx);
|
||||
|
||||
/* return the data */
|
||||
if (cnt) *cnt = fnctx.cnt;
|
||||
if (siz) *siz = fnctx.siz;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete a particular word associated with an object, or all words if
|
||||
* the word pointer is null. If the word isn't marked as added at
|
||||
* runtime (i.e., the VOCFNEW flag is not set for the word), the word is
|
||||
* simply marked as deleted, rather than being actually deleted.
|
||||
* However, if the 'really_delete' flag is set, the word is actually
|
||||
* deleted. If the 'revert' flag is true, this routine deletes _every_
|
||||
* dynamically created word, and undeletes all dynamically deleted words
|
||||
* that were in the original vocabulary.
|
||||
*/
|
||||
void vocdel1(voccxdef *ctx, objnum objn, char *wrd1, prpnum prp,
|
||||
int really_delete, int revert, int keep_undo)
|
||||
{
|
||||
int i;
|
||||
vocdef *v;
|
||||
vocdef *prv;
|
||||
vocdef *nxt;
|
||||
vocdef **vp;
|
||||
vocwdef *vw;
|
||||
vocwdef *prvw;
|
||||
vocwdef *nxtw;
|
||||
uint nxtidx;
|
||||
uint idx;
|
||||
int deleted_vocdef;
|
||||
char *wrd2 = nullptr;
|
||||
int len1 = 0, len2 = 0;
|
||||
int do_del;
|
||||
char *orgwrd;
|
||||
|
||||
/* parse the word if provided */
|
||||
orgwrd = wrd1;
|
||||
if (wrd1)
|
||||
voc_parse_words(&wrd1, &len1, &wrd2, &len2);
|
||||
|
||||
/* go through each hash value looking for matching words */
|
||||
for (i = VOCHASHSIZ, vp = ctx->voccxhsh ; i ; ++vp, --i)
|
||||
{
|
||||
/* go through all words in this hash chain */
|
||||
for (prv = (vocdef *)0, v = *vp ; v ; v = nxt)
|
||||
{
|
||||
/* remember next word in hash chain */
|
||||
nxt = v->vocnxt;
|
||||
|
||||
/* if this word doesn't match, skip it */
|
||||
if (wrd1)
|
||||
{
|
||||
/* compare the first word */
|
||||
if (v->voclen != len1
|
||||
|| memicmp((char *)v->voctxt, wrd1, (size_t)len1))
|
||||
{
|
||||
prv = v;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there's a second word, compare it as well */
|
||||
if (wrd2 && (v->vocln2 != len2
|
||||
|| memicmp((char *)v->voctxt + len1,
|
||||
wrd2, (size_t)len2)))
|
||||
{
|
||||
prv = v;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* presume we're not going to delete this vocdef */
|
||||
deleted_vocdef = FALSE;
|
||||
|
||||
/* go through all object relations for this word */
|
||||
for (prvw = 0, idx = v->vocwlst, vw = vocwget(ctx, idx) ; vw ;
|
||||
vw = nxtw, idx = nxtidx)
|
||||
{
|
||||
/* remember next word in relation list */
|
||||
nxtidx = vw->vocwnxt;
|
||||
nxtw = vocwget(ctx, nxtidx);
|
||||
|
||||
/*
|
||||
* figure out whether to delete this word, based on the
|
||||
* caller's specified operating mode
|
||||
*/
|
||||
if (revert)
|
||||
{
|
||||
/* if reverting, delete all new words */
|
||||
do_del = (vw->vocwflg & VOCFNEW);
|
||||
|
||||
/* also, remove the DELETED flag if present */
|
||||
vw->vocwflg &= ~VOCFDEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* delete the word if the object number matches,
|
||||
* AND either we're not searching for a specific
|
||||
* vocabulary word (in which case wrd1 will be null)
|
||||
* or the word matches the vocabulary word we're
|
||||
* seeking (in which case the part of speech must
|
||||
* match)
|
||||
*/
|
||||
do_del = (vw->vocwobj == objn
|
||||
&& (wrd1 == 0 || vw->vocwtyp == prp));
|
||||
|
||||
/*
|
||||
* if we're not in really_delete mode, and the word
|
||||
* matches and it wasn't dynamically added at
|
||||
* run-time, simply mark it as deleted -- this will
|
||||
* allow it to be undeleted if the game is reverted
|
||||
* to RESTART conditions
|
||||
*/
|
||||
if (do_del && !really_delete && !(vw->vocwflg & VOCFNEW))
|
||||
{
|
||||
/* geneate undo for the operation */
|
||||
if (keep_undo && orgwrd)
|
||||
vocdusave_delwrd(ctx, objn, prp,
|
||||
vw->vocwflg, orgwrd);
|
||||
|
||||
/* just mark the word for deletion, but keep vw */
|
||||
vw->vocwflg |= VOCFDEL;
|
||||
do_del = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* now delete the structure if we decided we should */
|
||||
if (do_del)
|
||||
{
|
||||
/* geneate undo for the operation */
|
||||
if (keep_undo && orgwrd)
|
||||
vocdusave_delwrd(ctx, objn, prp, vw->vocwflg, orgwrd);
|
||||
|
||||
/* unlink this vocwdef from the vocdef's list */
|
||||
if (prvw)
|
||||
prvw->vocwnxt = vw->vocwnxt;
|
||||
else
|
||||
v->vocwlst = vw->vocwnxt;
|
||||
|
||||
/* link the vocwdef into the vocwdef free list */
|
||||
vw->vocwnxt = ctx->voccxwfre;
|
||||
ctx->voccxwfre = idx;
|
||||
|
||||
/*
|
||||
* if there's nothing left in the vocdef's list,
|
||||
* delete the entire vocdef as well
|
||||
*/
|
||||
if (v->vocwlst == VOCCXW_NONE)
|
||||
{
|
||||
if (prv) prv->vocnxt = v->vocnxt;
|
||||
else *vp = v->vocnxt;
|
||||
|
||||
/* link into free chain */
|
||||
v->vocnxt = ctx->voccxfre;
|
||||
ctx->voccxfre = v;
|
||||
|
||||
/* note that it's been deleted */
|
||||
deleted_vocdef = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we're not deleting the word, so move prvw forward */
|
||||
prvw = vw;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we didn't delete this vocdef, move prv forward onto it */
|
||||
if (!deleted_vocdef)
|
||||
prv = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* delete all vocabulary for an object */
|
||||
void vocdel(voccxdef *ctx, objnum objn)
|
||||
{
|
||||
vocdel1(ctx, objn, (char *)0, (prpnum)0, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* delete object inheritance records for a particular object */
|
||||
void vocidel(voccxdef *ctx, objnum obj)
|
||||
{
|
||||
vocidef *v;
|
||||
|
||||
/* get entry out of page table, and clear page table slot */
|
||||
v = vocinh(ctx, obj);
|
||||
vocinh(ctx, obj) = (vocidef *)0;
|
||||
|
||||
/* link into free list */
|
||||
if (v)
|
||||
{
|
||||
v->vocinxt = ctx->voccxifr;
|
||||
ctx->voccxifr = v;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find template matching a verb+object+prep combination; return TRUE
|
||||
* if a suitable template is found, FALSE otherwise.
|
||||
*/
|
||||
int voctplfnd(voccxdef *ctx, objnum verb_in, objnum prep,
|
||||
uchar *tplout, int *newstyle)
|
||||
{
|
||||
uchar *tplptr;
|
||||
uchar *thistpl;
|
||||
int found;
|
||||
int tplcnt;
|
||||
uint tplofs;
|
||||
objnum verb;
|
||||
|
||||
/* look for a new-style template first */
|
||||
tplofs = objgetap(ctx->voccxmem, verb_in, PRP_TPL2, &verb, FALSE);
|
||||
if (tplofs)
|
||||
{
|
||||
/* flag the presence of the new-style template */
|
||||
*newstyle = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no new-style template - look for old version */
|
||||
tplofs = objgetap(ctx->voccxmem, verb_in, PRP_TPL, &verb, FALSE);
|
||||
*newstyle = FALSE;
|
||||
}
|
||||
|
||||
/* inherit templates until we run out of them */
|
||||
for (;;)
|
||||
{
|
||||
/* if we found something already, use it */
|
||||
if (tplofs)
|
||||
{
|
||||
size_t siz;
|
||||
|
||||
/* figure the size of this template style */
|
||||
siz = (*newstyle ? VOCTPL2SIZ : VOCTPLSIZ);
|
||||
|
||||
/* lock the verb object, and get the property value pointer */
|
||||
tplptr = mcmlck(ctx->voccxmem, verb);
|
||||
thistpl = prpvalp(tplptr + tplofs);
|
||||
|
||||
/* first byte is number of templates in array */
|
||||
tplcnt = *thistpl++;
|
||||
|
||||
/* look for a template that matches the preposition object */
|
||||
for (found = FALSE ; tplcnt ; thistpl += siz, --tplcnt)
|
||||
{
|
||||
if (voctplpr(thistpl) == prep)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock the object and return the value if we found one */
|
||||
mcmunlck(ctx->voccxmem, verb);
|
||||
if (found)
|
||||
{
|
||||
memcpy(tplout, thistpl, siz);
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* try inheriting a template (new-style, then old-style) */
|
||||
tplofs = objgetap(ctx->voccxmem, verb_in, PRP_TPL2, &verb, TRUE);
|
||||
if (tplofs)
|
||||
*newstyle = TRUE;
|
||||
else
|
||||
{
|
||||
tplofs = objgetap(ctx->voccxmem, verb_in, PRP_TPL, &verb, TRUE);
|
||||
*newstyle = FALSE;
|
||||
}
|
||||
|
||||
/* return not-found if we couldn't inherit it */
|
||||
if (!tplofs)
|
||||
return FALSE;
|
||||
|
||||
/* use the newly found verb */
|
||||
verb_in = verb;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the "Me" object
|
||||
*/
|
||||
void voc_set_me(voccxdef *ctx, objnum new_me)
|
||||
{
|
||||
/* save undo for the change */
|
||||
vocdusave_me(ctx, ctx->voccxme);
|
||||
|
||||
/* set the new "Me" object */
|
||||
ctx->voccxme = new_me;
|
||||
}
|
||||
|
||||
} // End of namespace TADS2
|
||||
} // End of namespace TADS
|
||||
|
@ -27,6 +27,7 @@
|
||||
#ifndef GLK_TADS_TADS2_VOCABULARY
|
||||
#define GLK_TADS_TADS2_VOCABULARY
|
||||
|
||||
#include "common/util.h"
|
||||
#include "glk/tads/tads2/lib.h"
|
||||
#include "glk/tads/tads2/object.h"
|
||||
#include "glk/tads/tads2/property.h"
|
||||
@ -645,11 +646,11 @@ void vocdusave_me(voccxdef *ctx, objnum old_me);
|
||||
uint vochsh(uchar *t, int len);
|
||||
|
||||
/* TADS versions of isalpha, isspace, isdigit, etc */
|
||||
#define vocisupper(c) ((uchar)(c) <= 127 && isupper((uchar)(c)))
|
||||
#define vocislower(c) ((uchar)(c) <= 127 && islower((uchar)(c)))
|
||||
#define vocisalpha(c) ((uchar)(c) > 127 || isalpha((uchar)(c)))
|
||||
#define vocisspace(c) ((uchar)(c) <= 127 && isspace((uchar)(c)))
|
||||
#define vocisdigit(c) ((uchar)(c) <= 127 && isdigit((uchar)(c)))
|
||||
#define vocisupper(c) ((uchar)(c) <= 127 && Common::isUpper((uchar)(c)))
|
||||
#define vocislower(c) ((uchar)(c) <= 127 && Common::isLower((uchar)(c)))
|
||||
#define vocisalpha(c) ((uchar)(c) > 127 || Common::isAlpha((uchar)(c)))
|
||||
#define vocisspace(c) ((uchar)(c) <= 127 && Common::isSpace((uchar)(c)))
|
||||
#define vocisdigit(c) ((uchar)(c) <= 127 && Common::isDigit((uchar)(c)))
|
||||
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user