Files
scummvm-cursorfix/engines/glk/tads/tads2/object.h
2026-02-02 04:50:13 +01:00

396 lines
16 KiB
C++

/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLK_TADS_TADS2_OBJECT
#define GLK_TADS_TADS2_OBJECT
#include "glk/tads/tads.h"
#include "glk/tads/tads2/lib.h"
#include "glk/tads/tads2/memory_cache.h"
#include "glk/tads/tads2/property.h"
namespace Glk {
namespace TADS {
namespace TADS2 {
/**
* object number
*/
typedef ushort objnum;
/**
* For non-class objects, we'll leave some space free in the object so
* that a few properties can be added without having to resize the
* object. Class objects will probably never have anything added, so
* there's no need for extra space.
*/
#define OBJEXTRA 64
# define OBJFCLS 0x01 /* object is a class */
/**
* The object structure is actually laid out portably, using unaligned
* 2-byte arrays, stored least significant byte first, for each ushort
* (including the objnum array for the superclasses). The actual
* entries are at these offsets on all machines:
*
* objws 0
* objflg 2
* objnsc 4
* objnprop 6
* objfree 8
* objrst 10
* objstat 12
* objsc[0] 14
* objsc[1] 16
* etc
*
* If the OBJFINDEX flag is set, the object has a property index.
* The index occurs after the last superclass (so it's where the
* property data would go if there were no index), and the property
* data follows. Each index entry consists of a pair of two-byte
* entries: the first is the property number, and the second is
* its offset within the object. For performance reasons, an index
* is only built on a class object -- whenever a property is changed
* within an object, the entire index must be rebuilt, because the
* locations of many properties within the object can be changed by
* a single property change in the object. The index is ordered by
* property number, so it can be searched using a binary search.
* Furthermore, "ignored" properties are excluded from the index;
* only the active instance of a particular property is stored.
* The index must be maintained by all routines that can change
* property information: setp, delp, revert, etc.
*
* Preceding the index table is a two-byte entry that gives the
* offset of the properties. Since the properties immediately
* follow the index, this can be used to deduce how large a space
* is available for the index itself.
*/
typedef uchar objdef;
#define OBJDEFSIZ 14 /* "sizeof(objdef)" - size of object header w/o sc's */
/* object flags */
#define OBJFCLASS 1 /* object is a class */
#define OBJFINDEX 2 /* object has a property index */
#define OBJFMOD 4 /* object has been modified by a newer definition */
/* undo context */
struct objucxdef {
mcmcxdef *objucxmem; /* cache manager context */
errcxdef *objucxerr; /* error context */
ushort objucxsiz; /* size of the undo buffer */
ushort objucxhead; /* head (position of next write) */
ushort objucxtail; /* tail (position of oldest record) */
ushort objucxprv; /* previous head pointer */
ushort objucxtop; /* highest head value written */
void (*objucxcun)(void *ctx, uchar *data);
/* apply a client undo record */
ushort (*objucxcsz)(void *ctx, uchar *data);
/* get size of a client undo record */
void *objucxccx; /* client undo context */
uchar objucxbuf[1]; /* undo buffer */
};
/*
* Undo records are kept in a circular buffer allocated as part of an
* undo context. Offsets within the buffer are kept for the head, tail,
* and previous head records. The head always points to the byte at
* which the next undo record will be written. The previous head points
* to the most recently written undo record; it contains a back link to
* the undo record before that, and so forth back through the entire
* chain. (These reverse links are necessary because undo records vary
* in size depending on the data contained within.) The tail points to
* the oldest undo record that's still in the buffer. Conceptually, the
* head is always "above" the tail in the buffer; since the buffer is
* circular, the tail may have a higher address, but this just means
* that the buffer wraps around at the top. When the head bumps into
* the tail (i.e., the head address is physically below or equal to the
* tail address, and the head is then advanced so that its address
* becomes higher than the tail's), the tail is advanced by discarding
* as many of the least recent undo records as necessary to make room
* for the new head position. When the head and the previous head point
* to the same place, we have no undo records in the buffer.
*/
/**
* The first byte of an undo record specifies what action is to be
* undone. If a property was added, it is undone merely by deleting the
* property. If a property was changed, it is undone by setting the
* property back to its old value. An additional special flag indicates
* a "savepoint." Normally, all changes back to a savepoint will be
* undone.
*/
#define OBJUADD 1 /* a property was added (undo by deleting) */
#define OBJUCHG 2 /* a property was changed (change back to old value) */
#define OBJUSAV 3 /* savepoint marker (no property information) */
#define OBJUOVR 4 /* override original property (set orig to IGNORE) */
#define OBJUCLI 5 /* client undo record (any client data) */
/*
* After the control byte (OBJUxxx), the object number, property
* number, datatype, and data value will follow; some or all of these
* may be omitted, depending on the control byte.
*/
/* get object flags */
#define objflg(o) ((ushort)osrp2(((char *)(o)) + 2))
/* get object flags */
#define objsflg(o, val) oswp2(((char *)(o)) + 2, val)
/* given an object pointer, get a pointer to the first prpdef */
/* prpdef *objprp(objdef *objptr); */
#define objprp(o) ((prpdef *)(objsc(o) + 2*objnsc(o)))
/* given an object pointer, get number of properties in the prpdef */
/* int objnprop(objdef *objptr); */
#define objnprop(o) ((ushort)osrp2(((char *)(o)) + 6))
/* set number of properties */
/* void objsnp(objdef *objptr, int newnum); */
#define objsnp(o,n) oswp2(((char *)(o)) + 6, n)
/* given an object pointer, get offset of free space */
/* int objfree(objdef *objptr); */
#define objfree(o) ((ushort)osrp2(((char *)(o)) + 8))
/* set free space pointer */
/* void objsfree(objdef *objptr, int newfree); */
#define objsfree(o,n) oswp2(((char *)(o)) + 8, n)
/* get number of static properties */
/* ushort objstat(objdef *objptr); */
#define objstat(o) ((ushort)osrp2(((char *)(o)) + 10))
/* set number of static properties */
/* void objsetst(objdef *objptr, int newstat); */
#define objsetst(o,n) oswp2(((char *)(o)) + 10, n)
/* get reset size (size of static properties) */
/* ushort objrst(objdef *objptr); */
#define objrst(o) ((ushort)osrp2(((char *)(o)) + 12))
/* set reset size */
/* void objsetrst(objdef *objptr, uint newrst); */
#define objsetrst(o,n) oswp2(((char *)(o)) + 12, n)
/* given an object pointer, get first superclass pointer */
/* uchar *objsc(objdef *objptr); */
#define objsc(o) (((uchar *)(o)) + OBJDEFSIZ)
/* given an object pointer, get number of superclasses */
/* int objnsc(objdef *objptr); */
#define objnsc(o) ((ushort)osrp2(((char *)(o)) + 4))
/* set number of superclasses */
/* void objsnsc(objdef *objptr, int num); */
#define objsnsc(o,n) oswp2(((char *)(o)) + 4, n)
/* given a prpdef, get the next prpdef */
/* prpdef *objpnxt(prpdef *p); */
#define objpnxt(p) \
((prpdef *)(((uchar *)(p)) + PRPHDRSIZ + prpsize(p)))
/* get pointer to free prpdef */
/* prpdef *objpfre(objdef *objptr); */
#define objpfre(o) ((prpdef *)(((uchar *)(o)) + objfree(o)))
/* given a prpdef and an object pointer, compute the prpdef offset */
/* uint objpofs(objdef *objptr, prpdef *propptr); */
#define objpofs(o,p) ((uint)((p) ? (((uchar *)(p)) - ((uchar *)(o))) : 0))
/* given an object pointer and a property offset, get prpdef pointer */
/* prpdef *objofsp(objdef *objptr, uint propofs); */
#define objofsp(o,ofs) ((prpdef *)((ofs) ? (((uchar *)(o)) + (ofs)) : 0))
/*
* Get the first superclass of an object. If it doesn't have any
* superclasses, return invalid.
*/
objnum objget1sc(mcmcxdef *ctx, objnum objn);
/*
* Get an object's property WITHOUT INHERITANCE. If the object has the
* indicated property set, the byte OFFSET of the prpdef within the
* object is returned. The offset will remain valid until any type of
* operation that sets a property in the object (such as objdelp,
* objsetp, or an undo operation). An offset of zero means that the
* property was not set in the object.
*/
uint objgetp(mcmcxdef *ctx, objnum objn, prpnum prop,
dattyp *typptr);
/*
* Get the *ending* offset of the given property's value, without any
* inheritance. Returns the byte offset one past the end of the
* property's data.
*/
uint objgetp_end(mcmcxdef *ctx, objnum objn, prpnum prop);
/*
* Get a property of an object, either from the object or from a
* superclass (inherited). If the inh flag is TRUE, we do not look
* at all in the object itself, but restrict our search to inherited
* properties only. We return the byte OFFSET of the prpdef within
* the object in which the prpdef is found; the superclass object
* itself is NOT locked upon return, but we will NOT unlock the
* object passed in. If the offset is zero, the property was not
* found. The offset returned is valid until any operation that
* sets a property in the object (such as objdelp, objsetp, or an
* undo operation).
*/
uint objgetap(mcmcxdef *ctx, noreg objnum objn, prpnum prop,
objnum *orn, int inh);
/*
* expand an object by a requested amount, returning a pointer to the
* object's new location if it must be moved. The object will be
* unlocked and relocked by this call. On return, the actual amount
* of space ADDED to the object will be returned.
*/
objdef *objexp(mcmcxdef *ctx, objnum obj, ushort *siz);
/*
* Set an object's property, deleting the original value of the
* property if it existed. If an undo context is provided, write an
* undo record for the change; if the undo context pointer is null, no
* undo information is retained.
*/
void objsetp(mcmcxdef *ctx, objnum obj, prpnum prop,
dattyp typ, const void *val, objucxdef *undoctx);
/*
* Delete a property. If mark_only is true, we'll only mark the
* property as deleted without actually reclaiming its space; this is
* necessary when removing a code property (type DAT_CODE) any time
* other code properties may follow, because p-code is not entirely
* self-relative and thus can't always be relocated within an object.
*/
void objdelp(mcmcxdef *mctx, objnum objn, prpnum prop, int mark_only);
/*
* Set up for emitting code into an object. Writes a property header
* of type 'code', and returns the offset of the next free byte in the
* object. Call objendemt when done. The datatype argument is
* provided so that list generation can be done through the same
* mechanism, since parser lists must be converted to run-time
* lists via the code generator.
*/
uint objemt(mcmcxdef *ctx, objnum objn, prpnum prop, dattyp typ);
/* done emitting code into property, finish setting object info */
void objendemt(mcmcxdef *ctx, objnum objn, prpnum prop, uint endofs);
/*
* Determine if undo records should be kept. Undo records should be
* kept only if a savepoint is present in the undo log. If no savepoint
* is present, adding undo records would be useless, since it will not
* be possible to apply the undo information.
*/
int objuok(objucxdef *undoctx);
/*
* Reserve space in an undo buffer, deleting old records as needed.
* Returns a pointer to the reserved space.
*/
uchar *objures(objucxdef *undoctx, uchar cmd, ushort siz);
/* advance the tail pointer in an undo buffer over the record it points to */
void objutadv(objucxdef *undoctx);
/* apply one undo record, and remove it from undo list */
void obj1undo(mcmcxdef *mctx, objucxdef *undoctx);
/*
* Undo back to the most recent savepoint. If there is no savepoint in
* the undo list, NOTHING will be undone. This prevents reaching an
* inconsistent state in which some, but not all, of the operations
* between two savepoints are undone: either all operations between two
* savepoints will be undone, or none will.
*/
void objundo(mcmcxdef *mctx, objucxdef *undoctx);
/* set an undo savepoint */
void objusav(objucxdef *undoctx);
/* initialize undo context */
objucxdef *objuini(mcmcxdef *memctx, ushort undosiz,
void (*undocb)(void *ctx, uchar *data),
ushort (*sizecb)(void *ctx, uchar *data),
void *callctx);
/* free the undo context - releases memory allocated by objuini() */
void objuterm(objucxdef *undoctx);
/* discard all undo context (for times such as restarting) */
void objulose(objucxdef *undoctx);
/*
* Allocate and initialize a new object. The caller specifies the
* number of superclasses to be allocated, and the amount of space (in
* bytes) for the object's property data. The caller must fill in the
* superclass array. Upon return, the object is allocated and locked,
* and is initialized with no properties. A pointer to the object's
* memory is returned, and *objnptr receives the object number.
*/
objdef *objnew(mcmcxdef *mctx, int sccnt, ushort propspace,
objnum *objnptr, int classflg);
/* initialize an already allocated object */
void objini(mcmcxdef *mctx, int sccnt, objnum objn, int classflg);
/*
* Add space for additional superclasses to an object. The object can
* already have some properties set (if it doesn't, it can just be
* reinitialized).
*/
void objaddsc(mcmcxdef *mctx, int sccnt, objnum objn);
/*
* Delete an object's properties and superclasses. The 'mindel'
* parameter specifies the minimum property number to be deleted.
* Properties below this are considered "system" properties that are not
* to be deleted. This could be used by a development environment to
* store the source for an object as a special system property in the
* object; when the object is recompiled, all of the object's properties
* and superclasses must be deleted except the source property, which is
* retained even after recompilation.
*/
void objclr(mcmcxdef *mctx, objnum objn, prpnum mindel);
/* Build or rebuild an object's property index */
void objindx(mcmcxdef *mctx, objnum objn);
/* set up just-compiled object: mark static part and original properties */
void objcomp(mcmcxdef *mctx, objnum objn, int for_debug);
/* revert an object to original post-compilation state */
void objrevert(void *mctx, mcmon objn);
/* reset 'ignore' flags for a newly reconstructed object */
void objsetign(mcmcxdef *mctx, objnum objn);
} // End of namespace TADS2
} // End of namespace TADS
} // End of namespace Glk
#endif