aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/glk/module.mk1
-rw-r--r--engines/glk/tads/tads2/ler.cpp179
-rw-r--r--engines/glk/tads/tads2/ler.h287
3 files changed, 467 insertions, 0 deletions
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index bb55c98cfb..9a3aa37edb 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -45,6 +45,7 @@ MODULE_OBJS := \
scott/scott.o \
tads/detection.o \
tads/tads.o \
+ tads/tads2/ler.o \
tads/tads2/tads2.o \
tads/tads3/tads3.o
diff --git a/engines/glk/tads/tads2/ler.cpp b/engines/glk/tads/tads2/ler.cpp
new file mode 100644
index 0000000000..9213d0bc5b
--- /dev/null
+++ b/engines/glk/tads/tads2/ler.cpp
@@ -0,0 +1,179 @@
+/* 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 "ler.h"
+
+namespace Glk {
+namespace TADS {
+namespace TADS2 {
+
+int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv) {
+ int outlen = 0;
+ int argi = 0;
+ int len;
+ char buf[20];
+ char *p = nullptr;
+ char fmtchar;
+
+ while (*fmt != '\0' && outbufl > 1) {
+ switch(*fmt) {
+ case '\\':
+ ++fmt;
+ len = 1;
+ switch(*fmt) {
+ case '\0':
+ --fmt;
+ break;
+ case '\n':
+ p = "\n";
+ break;
+ case '\t':
+ p = "\t";
+ break;
+ default:
+ p = fmt;
+ break;
+ }
+ break;
+
+ case '%':
+ ++fmt;
+ fmtchar = *fmt;
+ if (argi >= argc) fmtchar = 1; // too many - ignore it
+ switch(fmtchar) {
+ case '\0':
+ --fmt;
+ len = 0;
+ break;
+
+ case '%':
+ p = "%";
+ len = 1;
+ break;
+
+ case 'd':
+ sprintf(buf, "%d", argv[argi].erraint);
+ len = strlen(buf);
+ p = buf;
+ break;
+
+ case 'u':
+ sprintf(buf, "%u", argv[argi].erraint);
+ len = strlen(buf);
+ p = buf;
+ break;
+
+ case 's':
+ p = argv[argi].errastr;
+ len = strlen(p);
+ break;
+
+ default:
+ p = "";
+ len = 0;
+ --argi;
+ break;
+ }
+ ++argi;
+ break;
+
+ default:
+ p = fmt;
+ len = 1;
+ break;
+ }
+
+ /* copy output that was set up above */
+ if (len != 0) {
+ if (outbufl >= len) {
+ memcpy(outbuf, p, (size_t)len);
+ outbufl -= len;
+ outbuf += len;
+ } else if (outbufl > 1) {
+ memcpy(outbuf, p, (size_t)outbufl - 1);
+ outbufl = 1;
+ }
+ outlen += len;
+ }
+ ++fmt;
+ }
+
+ // add a null terminator
+ if (outbufl != 0)
+ *outbuf++ = '\0';
+
+ // return the length
+ return outlen;
+}
+
+#if defined(DEBUG) && !defined(ERR_NO_MACRO)
+void errjmp(jmp_buf buf, int e) {
+ longjmp(buf, e);
+}
+#endif /* DEBUG */
+
+#ifdef ERR_NO_MACRO
+
+void errsign(errcxdef *ctx, int e, char *facility) {
+ strncpy(ctx->errcxptr->errfac, facility, ERRFACMAX);
+ ctx->errcxptr->errfac[ERRFACMAX] = '\0';
+ ctx->errcxofs = 0;
+ longjmp(ctx->errcxptr->errbuf, e);
+}
+
+void errsigf(errcxdef *ctx, char *facility, int e) {
+ errargc(ctx, 0);
+ errsign(ctx, e, facility);
+}
+
+char *errstr(errcxdef *ctx, const char *str, int len) {
+ char *ret = &ctx->errcxbuf[ctx->errcxofs];
+
+ memcpy(ret, str, (size_t)len);
+ ret[len] = '\0';
+ ctx->errcxofs += len + 1;
+ return(ret);
+}
+
+void errrse1(errcxdef *ctx, errdef *fr) {
+ errargc(ctx, fr->erraac);
+ memcpy(ctx->errcxptr->erraav, fr->erraav,
+ (size_t)(fr->erraac * sizeof(erradef)));
+ errsign(ctx, fr->errcode, fr->errfac);
+}
+
+void errlogn(errcxdef *ctx, int err, char *facility) {
+ ctx->errcxofs = 0;
+ (*ctx->errcxlog)(ctx->errcxlgc, facility, err, ctx->errcxptr->erraac,
+ ctx->errcxptr->erraav);
+}
+
+void errlogf(errcxdef *ctx, char *facility, int err) {
+ errargc(ctx, 0);
+ errlogn(ctx, err, facility);
+}
+
+#endif /* ERR_NO_MACRO */
+
+} // End of namespace TADS2
+} // End of namespace TADS
+} // End of namespace Glk
diff --git a/engines/glk/tads/tads2/ler.h b/engines/glk/tads/tads2/ler.h
new file mode 100644
index 0000000000..5301a0f53a
--- /dev/null
+++ b/engines/glk/tads/tads2/ler.h
@@ -0,0 +1,287 @@
+/* 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_LER
+#define GLK_TADS_TADS2_LER
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+
+namespace Glk {
+namespace TADS {
+namespace TADS2 {
+
+// maximum length of a facility identifier
+#define ERRFACMAX 6
+
+union erradef {
+ int erraint; // integer argument
+ char *errastr; // text string argument
+};
+
+struct errdef {
+ errdef * errprv; // previous error frame
+ int errcode; // error code of exception being handled
+ char errfac[ERRFACMAX+1]; // facility of current error
+ erradef erraav[10]; // parameters for error
+ int erraac; // count of parameters in argc
+// jmp_buf errbuf; // jump buffer for current error frame
+};
+
+#define ERRBUFSIZ 512
+
+// seek location record for an error message by number
+struct errmfdef {
+ uint errmfnum; // error number
+ size_t errmfseek; // seek location of this message
+};
+
+struct errcxdef {
+ errdef *errcxptr; // current error frame
+ void (*errcxlog)(void *, char *fac, int err, int argc, erradef *);
+ // error logging callback function
+ void *errcxlgc; // context for error logging callback
+ int errcxofs; // offset in argument buffer
+ char errcxbuf[ERRBUFSIZ]; // space for argument strings
+ Common::SeekableReadStream *errcxfp; // message file, if one is being used
+ errmfdef *errcxseek; // seek locations of messages in file
+ uint errcxsksz; // size of errcxseek array
+ size_t errcxbase; // offset in physical file of logical error file
+ struct appctxdef *errcxappctx; // host application context
+};
+typedef struct errcxdef errcxdef;
+
+// begin protected code
+#define ERRBEGIN(ctx) \
+ { \
+ errdef fr_; \
+ if ((fr_.errcode = setjmp(fr_.errbuf)) == 0) \
+ { \
+ fr_.errprv = (ctx)->errcxptr; \
+ (ctx)->errcxptr = &fr_;
+
+// end protected code, begin error handler
+#define ERRCATCH(ctx, e) \
+ assert(1==1 && (ctx)->errcxptr != fr_.errprv); \
+ (ctx)->errcxptr = fr_.errprv; \
+ } \
+ else \
+ { \
+ assert(2==2 && (ctx)->errcxptr != fr_.errprv); \
+ (e) = fr_.errcode; \
+ (ctx)->errcxptr = fr_.errprv;
+
+// retrieve argument (int, string) in current error frame
+#define errargint(argnum) (fr_.erraav[argnum].erraint)
+#define errargstr(argnum) (fr_.erraav[argnum].errastr)
+
+
+#define ERREND(ctx) \
+ } \
+ }
+
+// end protected code, begin cleanup (no handling; just cleaning up)
+#define ERRCLEAN(ctx) \
+ assert((ctx)->errcxptr != fr_.errprv); \
+ (ctx)->errcxptr = fr_.errprv; \
+ } \
+ else \
+ { \
+ assert((ctx)->errcxptr != fr_.errprv); \
+ (ctx)->errcxptr = fr_.errprv;
+
+#define ERRENDCLN(ctx) \
+ errrse(ctx); \
+ } \
+ }
+
+
+
+// argument types for errors with arguments
+#define ERRTINT erraint
+#define ERRTSTR errastr
+
+// set argument count in error frame
+#define errargc(ctx,cnt) ((ctx)->errcxptr->erraac=(cnt))
+
+// enter string argument; returns pointer to argument used in errargv
+#ifdef ERR_NO_MACRO
+char *errstr(errcxdef *ctx, const char *str, int len);
+#else /* ERR_NO_MACRO */
+
+#define errstr(ctx,str,len) \
+ ((memcpy(&(ctx)->errcxbuf[(ctx)->errcxofs],str,(size_t)len), \
+ (ctx)->errcxofs += (len), \
+ (ctx)->errcxbuf[(ctx)->errcxofs++] = '\0'), \
+ &(ctx)->errcxbuf[(ctx)->errcxofs-(len)-1])
+
+#endif /* ERR_NO_MACRO */
+
+/* set argument in error frame argument vector */
+#define errargv(ctx,index,typ,arg) \
+ ((ctx)->errcxptr->erraav[index].typ=(arg))
+
+// signal an error with argument count already set
+#ifdef ERR_NO_MACRO
+void errsign(errcxdef *ctx, int e, char *facility);
+#else /* ERR_NO_MACRO */
+# ifdef DEBUG
+void errjmp(jmp_buf buf, int e);
+# define errsign(ctx, e, fac) \
+ (strncpy((ctx)->errcxptr->errfac, fac, ERRFACMAX),\
+ (ctx)->errcxptr->errfac[ERRFACMAX]='\0',\
+ (ctx)->errcxofs=0, errjmp((ctx)->errcxptr->errbuf, e))
+# else /* DEBUG */
+# define errsign(ctx, e, fac) \
+ (strncpy((ctx)->errcxptr->errfac, fac, ERRFACMAX),\
+ (ctx)->errcxptr->errfac[ERRFACMAX]='\0',\
+ (ctx)->errcxofs=0, longjmp((ctx)->errcxptr->errbuf, e))
+# endif /* DEBUG */
+#endif /* ERR_NO_MACRO */
+
+
+// signal an error with no arguments
+#ifdef ERR_NO_MACRO
+void errsigf(errcxdef *ctx, char *facility, int err);
+#else /* ERR_NO_MACRO */
+#define errsigf(ctx, fac, e) (errargc(ctx,0),errsign(ctx,e,fac))
+#endif /* ERR_NO_MACRO */
+
+// signal an error with one argument
+#define errsigf1(ctx, fac, e, typ1, arg1) \
+ (errargv(ctx,0,typ1,arg1),errargc(ctx,1),errsign(ctx,e,fac))
+
+// signal an error with two arguments
+#define errsigf2(ctx, fac, e, typ1, arg1, typ2, arg2) \
+ (errargv(ctx,0,typ1,arg1), errargv(ctx,1,typ2,arg2), \
+ errargc(ctx,2), errsign(ctx,e,fac))
+
+// resignal the current error - only usable within exception handlers
+#ifdef ERR_NO_MACRO
+void errrse1(errcxdef *ctx, errdef *fr);
+# define errrse(ctx) errrse1(ctx, &fr_)
+#else /* ERR_NO_MACRO */
+
+// void errrse(errcxdef *ctx);
+# define errrse(ctx) \
+ (errargc(ctx, fr_.erraac),\
+ memcpy((ctx)->errcxptr->erraav, fr_.erraav, \
+ (size_t)(fr_.erraac*sizeof(erradef))),\
+ errsign(ctx, fr_.errcode, fr_.errfac))
+
+#endif /* ERR_NO_MACRO */
+
+/**
+ * For use in an error handler (ERRCATCH..ERREND) only: Copy the
+ * parameters from the error currently being handled to the enclosing
+ * frame. This is useful when "keeping" an error being handled - i.e.,
+ * the arguments will continue to be used outside of the
+ * ERRCATCH..ERREND code.
+ */
+#define errkeepargs(ctx) errcopyargs(ctx, &fr_)
+
+/**
+ * copy the parameters for an error from another frame into the current
+ * frame - this can be used when we want to be able to display an error
+ * that occurred in an inner frame within code that is protected by a
+ * new enclosing error frame
+ */
+#define errcopyargs(ctx, fr) \
+ (errargc((ctx), (fr)->erraac), \
+ memcpy((ctx)->errcxptr->erraav, (fr)->erraav, \
+ (size_t)((fr)->erraac*sizeof(erradef))))
+
+// log error that's been caught, using arguments already caught
+#define errclog(ctx) \
+ ((*(ctx)->errcxlog)((ctx)->errcxlgc,fr_.errfac,fr_.errcode,\
+ fr_.erraac,fr_.erraav))
+
+// log an error that's been set up but not signalled yet
+#define errprelog(ctx, err) \
+ ((*(ctx)->errcxlog)((ctx)->errcxlgc,(ctx)->errcxptr->errfac,\
+ err,(ctx)->errcxptr->erraac,\
+ (ctx)->errcxptr->erraav))
+
+// log an error (no signalling, just reporting)
+#ifdef ERR_NO_MACRO
+void errlogn(errcxdef *ctx, int err, char *facility);
+#else /* ERR_NO_MACRO */
+
+#define errlogn(ctx,err,fac) \
+ ((ctx)->errcxofs=0,\
+ (*(ctx)->errcxlog)((ctx)->errcxlgc,fac,err,(ctx)->errcxptr->erraac,\
+ (ctx)->errcxptr->erraav))
+
+#endif /* ERR_NO_MACRO */
+
+// log an error with no arguments
+#ifdef ERR_NO_MACRO
+void errlogf(errcxdef *ctx, char *facility, int err);
+#else /* ERR_NO_MACRO */
+
+// void errlogf(errcxdef *ctx, char *facility, int err);
+#define errlogf(ctx,fac,err) (errargc(ctx,0),errlogn(ctx,err,fac))
+
+#endif /* ERR_NO_MACRO */
+
+// log an error with one argument
+#define errlogf1(ctx, fac, e, typ1, arg1) \
+ (errargv(ctx,0,typ1,arg1),errargc(ctx,1),errlogn(ctx,e,fac))
+
+// log an error with two arguments
+#define errlogf2(ctx, fac, e, typ1, arg1, typ2, arg2) \
+ (errargv(ctx,0,typ1,arg1),errargv(ctx,1,typ2,arg2),\
+ errargc(ctx,2),errlogn(ctx,e,fac))
+
+
+/**
+ * Format an error message, sprintf-style, using arguments in an
+ * erradef array (which is passed to the error-logging callback).
+ * Returns the length of the output string, even if the actual
+ * output string was truncated because the outbuf was too short.
+ * (If called with outbufl == 0, nothing will be written out, but
+ * the size of the buffer needed, minus the terminating null byte,
+ * will be computed and returned.)
+ */
+extern int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv);
+
+// get the text of an error
+void errmsg(errcxdef *ctx, char *outbuf, uint outbufl, uint err);
+
+// initialize error subsystem, opening error message file if necessary
+void errini(errcxdef *ctx, Common::SeekableReadStream *fp);
+
+// allocate and initialize error context, free error context
+errcxdef *lerini();
+void lerfre(errcxdef *ctx);
+
+// error message structure - number + text
+struct errmdef {
+ uint errmerr; // error number
+ char *errmtxt; // text of error message
+};
+
+} // End of namespace TADS2
+} // End of namespace TADS
+} // End of namespace Glk
+
+#endif