aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2019-06-17 22:36:31 -0700
committerPaul Gilbert2019-06-22 14:40:49 -0700
commit08bc570308b0698090ce668dc7dca4c0c76dd3df (patch)
tree59baa530a4f79b16185c5422ed9f2b706011c8b2
parent84dfa6d3b83e080f099ad606dc7fbeb40ebe4b97 (diff)
downloadscummvm-rg350-08bc570308b0698090ce668dc7dca4c0c76dd3df.tar.gz
scummvm-rg350-08bc570308b0698090ce668dc7dca4c0c76dd3df.tar.bz2
scummvm-rg350-08bc570308b0698090ce668dc7dca4c0c76dd3df.zip
GLK: ALAN2: Initial import of full set of interpreter files
-rw-r--r--engines/glk/alan2/acode.h306
-rw-r--r--engines/glk/alan2/alan_version.cpp45
-rw-r--r--engines/glk/alan2/alan_version.h36
-rw-r--r--engines/glk/alan2/args.cpp308
-rw-r--r--engines/glk/alan2/args.h50
-rw-r--r--engines/glk/alan2/debug.cpp506
-rw-r--r--engines/glk/alan2/debug.h47
-rw-r--r--engines/glk/alan2/decode.cpp193
-rw-r--r--engines/glk/alan2/decode.h49
-rw-r--r--engines/glk/alan2/exe.cpp1845
-rw-r--r--engines/glk/alan2/exe.h127
-rw-r--r--engines/glk/alan2/glkio.cpp47
-rw-r--r--engines/glk/alan2/glkio.h48
-rw-r--r--engines/glk/alan2/glkstart.cpp65
-rw-r--r--engines/glk/alan2/glkstart.h70
-rw-r--r--engines/glk/alan2/inter.cpp893
-rw-r--r--engines/glk/alan2/inter.h38
-rw-r--r--engines/glk/alan2/main.h155
-rw-r--r--engines/glk/alan2/params.cpp159
-rw-r--r--engines/glk/alan2/params.h66
-rw-r--r--engines/glk/alan2/parse.cpp846
-rw-r--r--engines/glk/alan2/parse.h54
-rw-r--r--engines/glk/alan2/readline.cpp560
-rw-r--r--engines/glk/alan2/readline.h46
-rw-r--r--engines/glk/alan2/reverse.cpp552
-rw-r--r--engines/glk/alan2/reverse.h46
-rw-r--r--engines/glk/alan2/rules.cpp83
-rw-r--r--engines/glk/alan2/rules.h44
-rw-r--r--engines/glk/alan2/stack.cpp74
-rw-r--r--engines/glk/alan2/stack.h48
-rw-r--r--engines/glk/alan2/sysdep.cpp493
-rw-r--r--engines/glk/alan2/sysdep.h409
-rw-r--r--engines/glk/alan2/term.cpp123
-rw-r--r--engines/glk/alan2/term.h42
-rw-r--r--engines/glk/alan2/types.h469
-rw-r--r--engines/glk/alan2/util.h54
-rw-r--r--engines/glk/alan2/version.h59
-rw-r--r--engines/glk/module.mk16
38 files changed, 8789 insertions, 282 deletions
diff --git a/engines/glk/alan2/acode.h b/engines/glk/alan2/acode.h
new file mode 100644
index 0000000000..5fee277c6c
--- /dev/null
+++ b/engines/glk/alan2/acode.h
@@ -0,0 +1,306 @@
+/* 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_ALAN2_ACODE
+#define GLK_ALAN2_ACODE
+
+namespace Glk {
+namespace Alan2 {
+
+typedef size_t Aptr; /* Type for an ACODE memory address */
+
+typedef unsigned int Aword; /* Type for an ACODE word */
+typedef unsigned int Aaddr; /* Type for an ACODE address */
+typedef unsigned int Abool; /* Type for an ACODE Boolean value */
+typedef signed int Aint; /* Type for an ACODE Integer value */
+typedef int CodeValue; /* Definition for the packing process */
+
+#ifdef UNUSED
+#if INT_MAX==0x7fffffff
+typedef unsigned int Aword; /* Type for an ACODE word */
+typedef unsigned int Aaddr; /* Type for an ACODE address */
+typedef unsigned int Abool; /* Type for an ACODE Boolean value */
+typedef signed int Aint; /* Type for an ACODE Integer value */
+typedef int CodeValue; /* Definition for the packing process */
+#elif LONG_MAX==0x7fffffff
+typedef unsigned long Aword; /* Type for an ACODE word */
+typedef unsigned long Aaddr; /* Type for an ACODE address */
+typedef unsigned long Abool; /* Type for an ACODE Boolean value */
+typedef signed long Aint; /* Type for an ACODE Integer value */
+typedef long CodeValue; /* Definition for the packing process */
+#else
+#error "Can't find a 32-bit integer type"
+#endif
+#endif
+
+/* Constants for the Acode file, words/block & bytes/block */
+#define BLOCKLEN 256L
+#define BLOCKSIZE (BLOCKLEN*sizeof(Aword))
+
+
+/* Definitions for the packing process */
+#define VALUEBITS 16
+
+#define EOFChar 256
+#define TOPVALUE (((CodeValue)1<<VALUEBITS) - 1) /* Highest value possible */
+
+/* Half and quarter points in the code value range */
+#define ONEQUARTER (TOPVALUE/4+1) /* Point after first quarter */
+#define HALF (2*ONEQUARTER) /* Point after first half */
+#define THREEQUARTER (3*ONEQUARTER) /* Point after third quarter */
+
+
+/* AMACHINE Word Classes */
+typedef int WrdKind;
+#define WRD_SYN 0 /* 1 - Synonym */
+#define WRD_ADJ 1 /* 2 - Adjective */
+#define WRD_ALL 2 /* 4 - All */
+#define WRD_BUT 3 /* 8 - But */
+#define WRD_CONJ 4 /* 16 - Conjunction */
+#define WRD_PREP 5 /* 32 - Preposition */
+#define WRD_DIR 6 /* 64 - Direction */
+#define WRD_IT 7 /* 128 - It */
+#define WRD_NOISE 8 /* 256 - Noise word */
+#define WRD_NOUN 9 /* 512 - Noun */
+#define WRD_ACT 10 /* 1024 - Actor */
+#define WRD_THEM 11 /* 2048 - Them */
+#define WRD_VRB 12 /* 4096 - Verb */
+#define WRD_CLASSES 13
+
+
+
+/* Syntax element classifications */
+#define EOS (-2) /* End Of Syntax */
+
+/* Syntax element flag bits */
+#define MULTIPLEBIT 0x1
+#define OMNIBIT 0x2
+
+
+/* Parameter Classes */
+typedef enum ClaKind { /* NOTE! These must have the same order as */
+ CLA_OBJ = 1, /* the name classes in NAM.H */
+ CLA_CNT = (int)CLA_OBJ<<1,
+ CLA_ACT = (int)CLA_CNT<<1,
+ CLA_NUM = (int)CLA_ACT<<1,
+ CLA_STR = (int)CLA_NUM<<1,
+ CLA_COBJ = (int)CLA_STR<<1,
+ CLA_CACT = (int)CLA_COBJ<<1
+} ClaKind;
+
+
+/* Verb Qualifiers */
+typedef enum QualClass {
+ Q_DEFAULT,
+ Q_AFTER,
+ Q_BEFORE,
+ Q_ONLY
+} QualClass;
+
+
+/* The AMACHINE Operations */
+typedef enum OpClass {
+ C_CONST,
+ C_STMOP,
+ C_CURVAR
+} OpClass;
+
+typedef enum InstClass {
+ I_PRINT, /* Print a string from the text file */
+ I_QUIT,
+ I_LOOK,
+ I_SAVE,
+ I_RESTORE,
+ I_LIST, /* List contents of a container */
+ I_EMPTY,
+ I_SCORE,
+ I_VISITS,
+ I_SCHEDULE,
+ I_CANCEL,
+ I_LOCATE,
+ I_MAKE,
+ I_SET, /* Set a numeric attribute to the */
+ /* value on top of stack */
+ I_STRSET, /* Set a string valued attribute to a */
+ /* copy of the string on top of stack, */
+ /* deallocate current contents first */
+ I_GETSTR, /* Get a string contents from text */
+ /* file, create a copy and push it */
+ /* on top of stack */
+ I_INCR, /* Increment an attribute */
+ I_DECR, /* Decrement a numeric attribute */
+ I_USE,
+ I_IN,
+ I_DESCRIBE,
+ I_SAY,
+ I_SAYINT,
+ I_SAYSTR,
+ I_IF,
+ I_ELSE,
+ I_ENDIF,
+ I_ATTRIBUTE,
+ I_STRATTR, /* Push a copy of a string attribute */
+ I_HERE,
+ I_NEAR,
+ I_WHERE,
+ I_AND,
+ I_OR,
+ I_NE,
+ I_EQ,
+ I_STREQ, /* String compare */
+ I_STREXACT,
+ I_LE,
+ I_GE,
+ I_LT,
+ I_GT,
+ I_PLUS,
+ I_MINUS,
+ I_MULT,
+ I_DIV,
+ I_NOT,
+ I_UMINUS,
+ I_RND,
+ I_SUM, /* SUM-aggregate */
+ I_MAX, /* MAX-aggregate */
+ I_COUNT, /* COUNT-aggregate */
+ I_RETURN,
+ I_SYSTEM,
+ I_RESTART, /* INTRODUCED: v2.7 */
+ I_BTW, /* INTRODUCED: v2.8 */
+ I_CONTAINS, /* -""- */
+ I_DEPSTART, /* -""- */
+ I_DEPCASE, /* -""- */
+ I_DEPEXEC, /* -""- */
+ I_DEPELSE, /* -""- */
+ I_DEPEND /* -""- */
+} InstClass;
+
+
+typedef enum VarClass {
+ V_PARAM,
+ V_CURLOC,
+ V_CURACT,
+ V_CURVRB,
+ V_SCORE
+} VarClass;
+
+
+#define I_CLASS(x) ((x)>>28)
+#define I_OP(x) ((x&0x8000000)?(x)|0x0f0000000:(x)&0x0fffffff)
+
+
+typedef struct AcdHdr {
+/* Important info */
+ char vers[4]; /* 01 - Version of compiler */
+ Aword size; /* 02 - Size of ACD-file in Awords */
+/* Options */
+ Abool pack; /* 03 - Is the text packed ? */
+ Aword paglen; /* 04 - Length of a page */
+ Aword pagwidth; /* 05 - and width */
+ Aword debug; /* 06 - Option debug */
+/* Data structures */
+ Aaddr dict; /* 07 - Dictionary */
+ Aaddr oatrs; /* 08 - Object default attributes */
+ Aaddr latrs; /* 09 - Location default attributes */
+ Aaddr aatrs; /* 0a - Actor default attributes */
+ Aaddr acts; /* 0b - Actor table */
+ Aaddr objs; /* 0c - Object table */
+ Aaddr locs; /* 0d - Location table */
+ Aaddr stxs; /* 0e - Syntax table */
+ Aaddr vrbs; /* 0f - Verb table */
+ Aaddr evts; /* 10 - Event table */
+ Aaddr cnts; /* 11 - Container table */
+ Aaddr ruls; /* 12 - Rule table */
+ Aaddr init; /* 13 - String init table */
+ Aaddr start; /* 14 - Start code */
+ Aword msgs; /* 15 - Messages table */
+/* Miscellaneous */
+ Aword objmin, objmax; /* 16 - Interval for object codes */
+ Aword actmin, actmax; /* 18 - Interval for actor codes */
+ Aword cntmin, cntmax; /* 1a - Interval for container codes */
+ Aword locmin, locmax; /* 1c - Interval for location codes */
+ Aword dirmin, dirmax; /* 1e - Interval for direction codes */
+ Aword evtmin, evtmax; /* 20 - Interval for event codes */
+ Aword rulmin, rulmax; /* 22 - Interval for rule codes */
+ Aword maxscore; /* 24 - Maximum score */
+ Aaddr scores; /* 25 - Score table */
+ Aaddr freq; /* 26 - Address to Char freq's for coding */
+ Aword acdcrc; /* 27 - Checksum for acd code (excl. hdr) */
+ Aword txtcrc; /* 28 - Checksum for text data file */
+} AcdHdr;
+
+/* Error message numbers */
+typedef enum MsgKind {
+ M_HUH, /* Obsolete */
+ M_WHAT,
+ M_WHAT_ALL,
+ M_WHAT_IT,
+ M_WHAT_THEM,
+ M_MULTIPLE,
+ M_WANT,
+ M_NOUN,
+ M_AFTER_BUT,
+ M_BUT_ALL,
+ M_NOT_MUCH,
+ M_WHICH_ONE,
+ M_NO_SUCH,
+ M_NO_WAY,
+ M_CANT0,
+ M_CANT,
+ M_NOTHING, /* Obsolete */
+ M_SEEOBJ1,
+ M_SEEOBJ2,
+ M_SEEOBJ3,
+ M_SEEOBJ4,
+ M_SEEACT,
+ M_CONTAINS1,
+ M_CONTAINS2,
+ M_CONTAINS3,
+ M_CONTAINS4,
+ M_CONTAINS5,
+ M_EMPTY1,
+ M_EMPTY2,
+ M_SCORE1,
+ M_SCORE2,
+ M_UNKNOWN_WORD,
+ M_MORE,
+ M_AGAIN,
+ M_SAVEWHERE,
+ M_SAVEOVERWRITE,
+ M_SAVEFAILED,
+ M_SAVEMISSING,
+ M_SAVEVERS,
+ M_SAVENAME,
+ M_RESTOREFROM,
+ M_REALLY, /* CHANGED: v2.7 from M_RESTART */
+ M_QUITACTION, /* INTRODUCED: v2.7, so M_ARTICLE moved */
+ M_ARTICLE, /* INTRODUCED: v2.6 but replaced the M_NOMSG*/
+ MSGMAX
+} MsgKind;
+
+#define M_ARTICLE26 M_QUITACTION
+#define M_MSGMAX26 M_ARTICLE
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/alan_version.cpp b/engines/glk/alan2/alan_version.cpp
new file mode 100644
index 0000000000..d3e1b9dde7
--- /dev/null
+++ b/engines/glk/alan2/alan_version.cpp
@@ -0,0 +1,45 @@
+/* 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/alan2/alan_version.h"
+
+namespace Glk {
+namespace Alan2 {
+
+Product alan = {
+ "Alan",
+ "Adventure Language System",
+ "Alan 2.8(6)",
+ "Alan 2.8(6) -- Adventure Language System (2001-07-13 14:35)",
+ "2001-07-13",
+ "14:35:07",
+ "Thomas Nilsson",
+ "",
+ "cygwin",
+ {"2.8(6)", 2, 8, 6, 995034907, ""}
+};
+
+static char *alanId =
+ "@(#)RELEASE ";
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/alan_version.h b/engines/glk/alan2/alan_version.h
new file mode 100644
index 0000000000..1a75394bc5
--- /dev/null
+++ b/engines/glk/alan2/alan_version.h
@@ -0,0 +1,36 @@
+/* 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_ALAN2_ALAN_VERSION
+#define GLK_ALAN2_ALAN_VERSION
+
+#include "glk/alan2/version.h"
+
+namespace Glk {
+namespace Alan2 {
+
+extern Product alan;
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/args.cpp b/engines/glk/alan2/args.cpp
new file mode 100644
index 0000000000..aceb00b67a
--- /dev/null
+++ b/engines/glk/alan2/args.cpp
@@ -0,0 +1,308 @@
+/* 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 <string>
+#ifndef __PACIFIC__
+#include "glk/alan2/args.h"
+#else
+/* I have no idea at all why the include does not work in Pacific C ... */
+extern void args(int argc, char* argv[]);
+#endif
+
+#include "glk/alan2/main.h"
+
+#ifdef __mac__
+#include "glk/alan2/macArgs.h"
+#endif
+
+#ifdef __amiga__
+#include <libraries/dosextens.h>
+#ifdef AZTEC_C
+struct FileHandle *con = NULL;
+#else
+/* Geek Gadgets GCC */
+BPTR window;
+BPTR cd;
+#endif
+#endif
+
+#ifdef GLK
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/glkio.h"
+#include "glk/alan2/sysdep.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+static void switches(
+ unsigned argc,
+ char *argv[]
+)
+#else
+static void switches(argc, argv)
+ unsigned argc;
+ char *argv[];
+#endif
+{
+ uint i;
+
+ advnam = "";
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+#ifdef GLK
+ switch (g_vm->glk_char_to_lower(argv[i][1])) {
+#else
+ switch (tolower(argv[i][1])) {
+#endif
+ case 'i':
+ errflg = FALSE;
+ break;
+ case 't':
+ trcflg = TRUE;
+ break;
+ case 'd':
+ dbgflg = TRUE;
+ break;
+ case 's':
+ trcflg = TRUE;
+ stpflg = TRUE;
+ break;
+ case 'l':
+ logflg = TRUE;
+ break;
+ case 'v':
+ verbose = TRUE;
+ break;
+ case 'n':
+ statusflg = FALSE;
+ break;
+ default:
+ printf("Unrecognized switch, -%c\n", argv[i][1]);
+ usage();
+ terminate(0);
+ }
+ } else {
+ advnam = argv[i];
+ if (strcmp(&advnam[strlen(advnam)-4], ".acd") == 0
+ || strcmp(&advnam[strlen(advnam)-4], ".ACD") == 0
+ || strcmp(&advnam[strlen(advnam)-4], ".dat") == 0
+ || strcmp(&advnam[strlen(advnam)-4], ".DAT") == 0)
+ advnam[strlen(advnam)-4] = '\0';
+ }
+ }
+}
+
+
+
+#ifdef __amiga__
+
+#include <intuition/intuition.h>
+#include <workbench/workbench.h>
+
+#include <clib/exec_protos.h>
+#include <clib/dos_protos.h>
+#include <clib/icon_protos.h>
+
+#include <fcntl.h>
+
+extern struct Library *IconBase;
+
+#ifndef AZTEC_C
+/* Actually Geek Gadgets GCC with libnix */
+
+/* Aztec C has its own pre-main wbparse which was used in Arun 2.7, with GCC we
+ need to do it ourselves. */
+
+#include <clib/intuition_protos.h>
+
+extern unsigned long *__stdfiledes; /* The libnix standard I/O file descriptors */
+
+void
+wb_parse(void)
+{
+ char *cp;
+ struct DiskObject *dop;
+ struct FileHandle *fhp;
+
+ if (_WBenchMsg->sm_NumArgs == 1) /* If no argument use program icon/info */
+ dop = GetDiskObject((UBYTE *)_WBenchMsg->sm_ArgList[0].wa_Name);
+ else {
+ BPTR olddir = CurrentDir(_WBenchMsg->sm_ArgList[1].wa_Lock);
+ dop = GetDiskObject((UBYTE *)_WBenchMsg->sm_ArgList[1].wa_Name);
+ CurrentDir(olddir);
+ }
+ if (dop != 0 && (cp = (char *)FindToolType((UBYTE **)dop->do_ToolTypes,
+ (UBYTE *)"WINDOW")) != NULL)
+ ;
+ else /* Could not find a WINDOW tool type */
+ cp = "CON:10/10/480/160/Arun:Default Window/CLOSE";
+ if ((window = Open((UBYTE *)cp, (long)MODE_OLDFILE))) {
+ fhp = (struct FileHandle *) ((long)window << 2);
+ SetConsoleTask(fhp->fh_Type);
+ SelectInput(window);
+ SelectOutput(window);
+ __stdfiledes[0] = Input();
+ __stdfiledes[1] = Output();
+ } else
+ exit(-1L);
+ FreeDiskObject(dop);
+}
+#endif
+#endif
+
+
+#ifdef _PROTOTYPES_
+void args(
+ int argc,
+ char * argv[]
+)
+#else
+void args(argc, argv)
+ int argc;
+ char *argv[];
+#endif
+{
+ char *prgnam;
+
+#ifdef __mac__
+#include <console.h>
+#ifdef __MWERKS__
+#include <SIOUX.h>
+#endif
+ short msg, files;
+ static char advbuf[256], prgbuf[256];
+ /*AppFile af;*/
+ OSErr oe;
+
+#ifdef __MWERKS__
+ /*SIOUXSettings.setupmenus = FALSE;*/
+ SIOUXSettings.autocloseonquit = FALSE;
+ SIOUXSettings.asktosaveonclose = FALSE;
+ SIOUXSettings.showstatusline = FALSE;
+#endif
+
+ GetMacArgs(advbuf);
+ advnam = advbuf;
+
+#else
+#ifdef __amiga__
+
+ if (argc == 0) { /* If started from Workbench get WbArgs : Aztec C & GG GCC */
+ struct WBStartup *WBstart;
+
+ if ((IconBase = OpenLibrary("icon.library", 0)) == NULL)
+ syserr("Could not open 'icon.library'");
+ /* If started from WB normal main is called with argc == 0 and argv = WBstartup message */
+ WBstart = (struct WBStartup *)argv;
+#ifndef AZTEC_C
+ /* Geek Gadgets GCC */
+ wb_parse();
+#endif
+ advnam = prgnam = WBstart->sm_ArgList[0].wa_Name;
+ if (WBstart->sm_NumArgs > 0) {
+ cd = CurrentDir(DupLock(WBstart->sm_ArgList[1].wa_Lock));
+ advnam = WBstart->sm_ArgList[1].wa_Name;
+ }
+ /* Possibly other tooltypes ... */
+ } else {
+ /* Started from a CLI */
+ if ((prgnam = strrchr(argv[0], '/')) == NULL
+ && (prgnam = strrchr(argv[0], ':')) == NULL)
+ prgnam = argv[0];
+ else
+ prgnam++;
+ /* Now look at the switches and arguments */
+ switches(argc, argv);
+ if (advnam[0] == '\0')
+ /* No game given, try program name */
+ if (stricmp(prgnam, PROGNAME) != 0
+ && strstr(prgnam, PROGNAME) == 0)
+ advnam = strdup(argv[0]);
+ }
+#else
+#if defined(__dos__) || defined(__win__)
+ if ((prgnam = strrchr(argv[0], '\\')) == NULL
+ && (prgnam = strrchr(argv[0], '/')) == NULL
+ && (prgnam = strrchr(argv[0], ':')) == NULL)
+ prgnam = argv[0];
+ else
+ prgnam++;
+ if (strlen(prgnam) > 4
+ && (strcmp(&prgnam[strlen(prgnam)-4], ".EXE") == 0
+ || strcmp(&prgnam[strlen(prgnam)-4], ".exe") == 0))
+ prgnam[strlen(prgnam)-4] = '\0';
+ /* Now look at the switches and arguments */
+ switches(argc, argv);
+ if (advnam[0] == '\0')
+ /* No game given, try program name */
+ if (stricmp(prgnam, PROGNAME) != 0
+ && strstr(prgnam, PROGNAME) == 0)
+ advnam = strdup(argv[0]);
+#else
+#if defined __vms__
+ if ((prgnam = strrchr(argv[0], ']')) == NULL
+ && (prgnam = strrchr(argv[0], '>')) == NULL
+ && (prgnam = strrchr(argv[0], ':')) == NULL)
+ prgnam = argv[0];
+ else
+ prgnam++;
+ if (strrchr(prgnam, ';') != NULL)
+ *strrchr(prgnam, ';') = '\0';
+ if (strlen(prgnam) > 4
+ && (strcmp(&prgnam[strlen(prgnam)-4], ".EXE") == 0
+ || strcmp(&prgnam[strlen(prgnam)-4], ".exe") == 0))
+ prgnam[strlen(prgnam)-4] = '\0';
+ /* Now look at the switches and arguments */
+ switches(argc, argv);
+ if (advnam[0] == '\0')
+ /* No game given, try program name */
+ if (strcmp(prgnam, PROGNAME) != 0
+ && strstr(prgnam, PROGNAME) == 0)
+ advnam = strdup(argv[0]);
+#else
+#if defined(__unix__) || defined(__APPLE__)
+ if ((prgnam = strrchr(argv[0], '/')) == NULL)
+ prgnam = strdup(argv[0]);
+ else
+ prgnam = strdup(&prgnam[1]);
+ if (strrchr(prgnam, ';') != NULL)
+ *strrchr(prgnam, ';') = '\0';
+ /* Now look at the switches and arguments */
+ switches(argc, argv);
+ if (advnam[0] == '\0')
+ /* No game given, try program name */
+ if (strcmp(prgnam, PROGNAME) != 0
+ && strstr(prgnam, PROGNAME) == 0)
+ advnam = strdup(argv[0]);
+#else
+ Unimplemented OS!
+#endif
+#endif
+#endif
+#endif
+#endif
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/args.h b/engines/glk/alan2/args.h
new file mode 100644
index 0000000000..a86d5197fe
--- /dev/null
+++ b/engines/glk/alan2/args.h
@@ -0,0 +1,50 @@
+/* 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_ALAN2_ARGS
+#define GLK_ALAN2_ARGS
+
+/* Handles the various startup methods on all machines.
+ *
+ * Main function args() will set up global variable advnam and the flags,
+ * the terminal will also be set up and connected.
+ */
+
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#ifndef PROGNAME
+#define PROGNAME "alan2"
+#endif
+
+#ifdef _PROTOTYPES_
+extern void args(int argc, char *argv[]);
+#else
+extern void args();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/debug.cpp b/engines/glk/alan2/debug.cpp
new file mode 100644
index 0000000000..dc353c7729
--- /dev/null
+++ b/engines/glk/alan2/debug.cpp
@@ -0,0 +1,506 @@
+/* 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/alan2/types.h"
+#ifdef HAVE_SHORT_FILENAMES
+#include "glk/alan2/av.h"
+#else
+#include "glk/alan2/alan_version.h"
+#endif
+
+#ifdef USE_READLINE
+#include "glk/alan2/readline.h"
+#endif
+
+#include "glk/alan2/inter.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/parse.h"
+#include "glk/alan2/exe.h"
+
+#include "glk/alan2/debug.h"
+
+#ifdef GLK
+#include "glk/alan2/glkio.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+static void showatrs(
+ Aword atradr
+)
+#else
+static void showatrs(atradr)
+ Aword atradr;
+#endif
+{
+ AtrElem *at;
+ int i;
+ char str[80];
+
+ if (atradr == 0) return;
+
+ i = 1;
+ for (at = (AtrElem *) addrTo(atradr); !endOfTable(at); at++) {
+ sprintf(str, "$i%3ld: %ld (%s)", (long) i, (unsigned long) at->val, (char *) addrTo(at->stradr));
+#if ISO == 0
+ fromIso(str, str);
+#endif
+ output(str);
+ i++;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void showobjs(void)
+#else
+static void showobjs()
+#endif
+{
+ char str[80];
+ int obj;
+
+ output("OBJECTS:");
+ for (obj = OBJMIN; obj <= OBJMAX; obj++) {
+ sprintf(str, "$i%3ld: ", (long) obj);
+ output(str);
+ say(obj);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void showobj(
+ int obj
+)
+#else
+static void showobj(obj)
+ int obj;
+#endif
+{
+ char str[80];
+#define OBJ (obj-OBJMIN)
+
+
+ if (!isObj(obj)) {
+ sprintf(str, "Object number out of range. Between %ld and %ld, please.", (unsigned long) OBJMIN, (unsigned long) OBJMAX);
+ output(str);
+ return;
+ }
+
+ sprintf(str, "OBJECT %d :", obj);
+ output(str);
+ say(obj);
+
+ sprintf(str, "$iLocation = %ld", (unsigned long) where(obj));
+ output(str);
+ if (isLoc(objs[OBJ].loc))
+ say(objs[OBJ].loc);
+ else if (isCnt(objs[OBJ].loc)) {
+ if (isObj(objs[OBJ].loc)) {
+ output("in");
+ say(objs[OBJ].loc);
+ } else if (isAct(objs[OBJ].loc)) {
+ output("carried by");
+ say(objs[OBJ].loc);
+ } else
+ interpret(cnts[objs[OBJ].loc-CNTMIN].nam);
+ } else if (objs[OBJ].loc == 0)
+ output("nowhere");
+ else
+ output("Illegal location!");
+
+
+ output("$iAttributes =");
+ showatrs(objs[OBJ].atrs);
+
+#undef OBJ
+}
+
+
+#ifdef _PROTOTYPES_
+static void showcnts(void)
+#else
+static void showcnts()
+#endif
+{
+ char str[80];
+ int cnt;
+#define CNT (cnt-CNTMIN)
+
+ output("CONTAINERS:");
+ for (cnt = CNTMIN; cnt <= CNTMAX; cnt++) {
+ sprintf(str, "$i%3ld: ", (long) cnt);
+ output(str);
+ if (cnts[CNT].nam != 0)
+ interpret(cnts[CNT].nam);
+ if (cnts[CNT].parent != 0)
+ say(cnts[CNT].parent);
+ }
+
+#undef CNT
+}
+
+
+#ifdef _PROTOTYPES_
+static void showcnt(
+ int cnt
+)
+#else
+static void showcnt(cnt)
+ int cnt;
+#endif
+{
+ char str[80];
+ int i;
+ Abool found = FALSE;
+#define CNT (cnt-CNTMIN)
+
+ if (cnt < CNTMIN || cnt > CNTMAX) {
+ sprintf(str, "Container number out of range. Between %ld and %ld, please.", (unsigned long) CNTMIN, (unsigned long) CNTMAX);
+ output(str);
+ return;
+ }
+
+ sprintf(str, "CONTAINER %d :", cnt);
+ output(str);
+ if (cnts[CNT].nam != 0)
+ interpret(cnts[CNT].nam);
+ if (cnts[CNT].parent != 0) {
+ cnt = cnts[CNT].parent;
+ say(cnt);
+ sprintf(str, "$iLocation = %ld", (unsigned long) where(cnt));
+ output(str);
+ }
+ output("$iContains ");
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ if (in(i, cnt)) { /* Yes, it's in this container */
+ if (!found) {
+ output("$n");
+ found = TRUE;
+ }
+ sprintf(str, "$t$t%d: ", i);
+ output(str);
+ say(i);
+ }
+ }
+ if (!found)
+ output("nothing");
+
+#undef CNT
+}
+
+
+#ifdef _PROTOTYPES_
+static void showlocs(void)
+#else
+static void showlocs()
+#endif
+{
+ char str[80];
+ int loc;
+
+ output("LOCATIONS:");
+ for (loc = LOCMIN; loc <= LOCMAX; loc++) {
+ sprintf(str, "$i%3ld: ", (long) loc);
+ output(str);
+ say(loc);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void showloc(
+ int loc
+)
+#else
+static void showloc(loc)
+ int loc;
+#endif
+{
+ char str[80];
+
+
+ if (!isLoc(loc)) {
+ sprintf(str, "Location number out of range. Between %ld and %ld, please.", (unsigned long) LOCMIN, (unsigned long) LOCMAX);
+ output(str);
+ return;
+ }
+
+ sprintf(str, "LOCATION %d :", loc);
+ output(str);
+ say(loc);
+
+ output("$iAttributes =");
+ showatrs(locs[loc-LOCMIN].atrs);
+}
+
+
+#ifdef _PROTOTYPES_
+static void showacts(void)
+#else
+static void showacts()
+#endif
+{
+ char str[80];
+ int act;
+
+ output("ACTORS:");
+ for (act = ACTMIN; act <= ACTMAX; act++) {
+ sprintf(str, "$i%3ld:", (long) act);
+ output(str);
+ say(act);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void showact(
+ int act
+)
+#else
+static void showact(act)
+ int act;
+#endif
+{
+ char str[80];
+ Boolean oldstp;
+
+ if (!isAct(act)) {
+ sprintf(str, "Actor number out of range. Between %ld and %ld, please.", (unsigned long) ACTMIN, (unsigned long) ACTMAX);
+ output(str);
+ return;
+ }
+
+ sprintf(str, "ACTOR %d :", act);
+ output(str);
+ oldstp = stpflg; stpflg = FALSE; /* Make sure not to trace this! */
+ say(act);
+ stpflg = oldstp;
+
+ sprintf(str, "$iLocation = %ld", (unsigned long) acts[act-ACTMIN].loc);
+ output(str);
+ if (isLoc(acts[act-ACTMIN].loc))
+ say(acts[act-ACTMIN].loc);
+ else if (acts[act-ACTMIN].loc == 0)
+ output("nowhere");
+ else
+ output("Illegal location!");
+
+ sprintf(str, "$iScript = %ld", (unsigned long) acts[act-ACTMIN].script);
+ output(str);
+
+ sprintf(str, "$iStep = %ld", (unsigned long) acts[act-ACTMIN].step);
+ output(str);
+
+ output("$iAttributes =");
+ showatrs(acts[act-ACTMIN].atrs);
+}
+
+
+#ifdef _PROTOTYPES_
+static void showevts(void)
+#else
+static void showevts()
+#endif
+{
+ int evt, i;
+ char str[80];
+ Boolean scheduled;
+
+ output("EVENTS:");
+ for (evt = EVTMIN; evt <= EVTMAX; evt++) {
+ sprintf(str, "$i%d (%s):", evt, (char *)addrTo(evts[evt-EVTMIN].stradr));
+#if ISO == 0
+ fromIso(str, str);
+#endif
+ output(str);
+ scheduled = FALSE;
+ for (i = 0; i < etop; i++)
+ if ((scheduled = (eventq[i].event == evt)))
+ break;
+ if (scheduled) {
+ sprintf(str, "Scheduled for +%d, at ", eventq[i].time-cur.tick);
+ output(str);
+ say(eventq[i].where);
+ } else
+ output("Not scheduled.");
+ }
+}
+
+
+static Boolean trc, stp;
+static int loc;
+
+#ifdef _PROTOTYPES_
+void saveInfo(void)
+#else
+void saveInfo()
+#endif
+{
+ /* Save some important things */
+ trc = trcflg; trcflg = FALSE;
+ stp = stpflg; stpflg = FALSE;
+ loc = cur.loc; cur.loc = where(HERO);
+}
+
+#ifdef _PROTOTYPES_
+void restoreInfo(void)
+#else
+void restoreInfo()
+#endif
+{
+ /* Restore! */
+ trcflg = trc;
+ stpflg = stp;
+ cur.loc = loc;
+}
+
+
+#ifdef _PROTOTYPES_
+void debug(void)
+#else
+void debug()
+#endif
+{
+ char buf[256];
+ char c;
+ int i;
+
+ saveInfo();
+ while (TRUE) {
+ if (anyOutput)
+ para();
+ do {
+ output("ABUG> ");
+#ifdef USE_READLINE
+ (void) readline(buf);
+#else
+ fgets(buf, 255, stdin);
+#endif
+ lin = 1;
+ c = buf[0];
+ i = 0;
+ sscanf(&buf[1], "%d", &i);
+ } while (buf && c == '\0');
+
+ switch (toUpper(c)) {
+ case 'H':
+ case '?':
+ output(alan.longHeader);
+ output("$nABUG Commands:\
+ $iO [n] -- show object[s]\
+ $iA [n] -- show actor[s]\
+ $iL [n] -- show location[s]\
+ $iC [n] -- show container[s]\
+ $iE -- show events\
+ $iG -- go on\
+ $iT -- toggle trace mode\
+ $iS -- toggle step mode\
+ $iX -- exit debug mode\
+ $iQ -- quit game");
+ break;
+ case 'Q':
+ terminate(0);
+ case 'X':
+ dbgflg = FALSE; /* Fall through to 'G' */
+ case 'G':
+ restoreInfo();
+ return;
+ case 'O':
+ if (i == 0)
+ showobjs();
+ else
+ showobj(i);
+ break;
+ case 'C':
+ if (i == 0)
+ showcnts();
+ else
+ showcnt(i);
+ break;
+ case 'A':
+ if (i == 0)
+ showacts();
+ else
+ showact(i);
+ break;
+ case 'L':
+ if (i == 0)
+ showlocs();
+ else
+ showloc(i);
+ break;
+ case 'E':
+ showevts();
+ break;
+ case 'S':
+ if ((stp = !stp))
+ printf("Step on.");
+ else
+ printf("Step off.");
+ break;
+ case 'T':
+ if ((trc = !trc))
+ printf("Trace on.");
+ else
+ printf("Trace off.");
+ break;
+ default:
+ output("Unknown ABUG command. ? for help.");
+ break;
+ }
+ }
+}
+
+
+/*======================================================================
+
+ debugsay()
+
+ Say somethin, but make sure we don't disturb anything and that it is
+ shown to the player.
+
+*/
+#ifdef _PROTOTYPES_
+void debugsay(int item)
+#else
+void debugsay(item)
+ int item;
+#endif
+{
+ saveInfo();
+ needsp = FALSE;
+ col = 1;
+ if (item == 0)
+ printf("$null$");
+ else
+ say(item);
+ needsp = FALSE;
+ col = 1;
+ restoreInfo();
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/debug.h b/engines/glk/alan2/debug.h
new file mode 100644
index 0000000000..aac870ec42
--- /dev/null
+++ b/engines/glk/alan2/debug.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+/* TYPES */
+
+#ifndef GLK_ALAN2_DEBUG
+#define GLK_ALAN2_DEBUG
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+
+extern void saveInfo(void);
+extern void restoreInfo(void);
+extern void debug(void);
+extern void debugsay(int item);
+#else
+extern void saveInfo();
+extern void restoreInfo();
+extern void debug();
+extern void debugsay();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/decode.cpp b/engines/glk/alan2/decode.cpp
new file mode 100644
index 0000000000..4ffdc2f3b9
--- /dev/null
+++ b/engines/glk/alan2/decode.cpp
@@ -0,0 +1,193 @@
+/* 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 <stdlib.h>
+#include "glk/alan2/main.h"
+#include "glk/alan2/decode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/* Bit output */
+static int decodeBuffer; /* Bits to be input */
+static int bitsToGo; /* Bits still in buffer */
+static int garbageBits; /* Bits past EOF */
+
+
+#ifdef _PROTOTYPES_
+static int inputBit(void)
+#else
+static int inputBit()
+#endif
+{
+ int bit;
+
+ if (!bitsToGo) { /* More bits available ? */
+ decodeBuffer = txtfil->readByte(); /* No, so get more */
+ if (decodeBuffer == EOF) {
+ garbageBits++;
+ if (garbageBits > VALUEBITS-2)
+ syserr("Error in encoded data file.");
+ } else
+ bitsToGo = 8; /* Another Char, 8 new bits */
+ }
+ bit = decodeBuffer&1; /* Get next bit */
+ decodeBuffer = decodeBuffer>>1; /* and remove it */
+ bitsToGo--;
+ return bit;
+}
+
+
+/* Current state of decoding */
+
+static CodeValue value; /* Currently seen code value */
+static CodeValue low, high; /* Current code region */
+
+
+#ifdef _PROTOTYPES_
+void startDecoding(void)
+#else
+void startDecoding()
+#endif
+{
+ int i;
+
+ bitsToGo = 0;
+ garbageBits = 0;
+
+ value = 0;
+ for (i = 0; i < VALUEBITS; i++)
+ value = 2*value + inputBit();
+ low = 0;
+ high = TOPVALUE;
+}
+
+
+#ifdef _PROTOTYPES_
+int decodeChar(void)
+#else
+int decodeChar()
+#endif
+{
+ long range;
+ int f;
+ int symbol;
+
+ range = (long)(high-low) + 1;
+ f = (((long)(value-low)+1)*freq[0]-1)/range;
+
+ /* Find the symbol */
+ for (symbol = 1; (int)freq[symbol] > f; symbol++);
+
+ high = low + range*freq[symbol-1]/freq[0]-1;
+ low = low + range*freq[symbol]/freq[0];
+
+ for (;;) {
+ if (high < HALF)
+ ;
+ else if (low >= HALF) {
+ value = value - HALF;
+ low = low - HALF;
+ high = high - HALF;
+ } else if (low >= ONEQUARTER && high < THREEQUARTER) {
+ value = value - ONEQUARTER;
+ low = low - ONEQUARTER;
+ high = high - ONEQUARTER;
+ } else
+ break;
+
+ /* Scale up the range */
+ low = 2*low;
+ high = 2*high+1;
+ value = 2*value + inputBit();
+ }
+ return symbol-1;
+}
+
+
+
+/* Structure for saved decode info */
+typedef struct DecodeInfo {
+ long fpos;
+ int buffer;
+ int bits;
+ CodeValue value;
+ CodeValue high;
+ CodeValue low;
+} DecodeInfo;
+
+
+/*======================================================================
+
+ pushDecode()
+
+ Save so much info about the decoding process so it is possible to
+ restore and continue later.
+
+ */
+#ifdef _PROTOTYPES_
+void *pushDecode(void)
+#else
+void *pushDecode()
+#endif
+{
+ DecodeInfo *info;
+
+ info = (DecodeInfo *) allocate(sizeof(DecodeInfo));
+ info->fpos = txtfil->pos();
+ info->buffer = decodeBuffer;
+ info->bits = bitsToGo;
+ info->value = value;
+ info->high = high;
+ info->low = low;
+ return(info);
+}
+
+
+/*======================================================================
+
+ popDecode()
+
+ Restore enough info about the decoding process so it is possible to
+ continue after having decoded something else.
+
+ */
+#ifdef _PROTOTYPES_
+void popDecode(void *i)
+#else
+void popDecode(i)
+ void *i;
+#endif
+{
+ DecodeInfo *info = (DecodeInfo *) i;
+ fseek(txtfil, info->fpos, 0);
+ decodeBuffer = info->buffer;
+ bitsToGo = info->bits;
+ value = info->value;
+ high = info->high;
+ low = info->low;
+
+ free(info);
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/decode.h b/engines/glk/alan2/decode.h
new file mode 100644
index 0000000000..7ce15b41de
--- /dev/null
+++ b/engines/glk/alan2/decode.h
@@ -0,0 +1,49 @@
+/* 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_ALAN2_DECODE
+#define GLK_ALAN2_DECODE
+
+#include "glk/alan2/types.h"
+
+/* Arithmetic decoding module in Arun
+ */
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+extern void startDecoding(void);
+extern int decodeChar(void);
+extern void *pushDecode(void);
+extern void popDecode(void *info);
+#else
+extern void startDecoding();
+extern int decodeChar();
+extern void *pushDecode();
+extern void popDecode();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/exe.cpp b/engines/glk/alan2/exe.cpp
new file mode 100644
index 0000000000..1cccf3d32d
--- /dev/null
+++ b/engines/glk/alan2/exe.cpp
@@ -0,0 +1,1845 @@
+/* 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/alan2/types.h"
+#include "glk/alan2/alan2.h"
+
+#ifdef USE_READLINE
+#include "glk/alan2/readline.h"
+#endif
+
+#include "glk/alan2/main.h"
+#include "glk/alan2/parse.h"
+#include "glk/alan2/inter.h"
+#include "glk/alan2/stack.h"
+#include "glk/alan2/decode.h"
+
+#include "glk/alan2/exe.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#define WIDTH 80
+
+#define N_EVTS 100
+
+
+/* PUBLIC DATA */
+
+/* The event queue */
+EvtqElem eventq[N_EVTS]; /* Event queue */
+int etop = 0; /* Event queue top pointer */
+
+Boolean looking = FALSE; /* LOOKING? flag */
+
+int dscrstkp = 0; /* Describe-stack pointer */
+
+
+#ifdef _PROTOTYPES_
+void dscrobjs(void);
+void dscracts(void);
+#else
+void dscrobjs();
+void dscracts();
+#endif
+
+
+
+#ifdef _PROTOTYPES_
+void print(Aword fpos, Aword len)
+#else
+void print(fpos, len)
+ Aword fpos, len;
+#endif
+{
+ char str[2*WIDTH]; /* String buffer */
+ int outlen = 0; /* Current output length */
+ int ch;
+ int i;
+ long savfp; /* Temporary saved text file position */
+ static Boolean printFlag = FALSE; /* Printing already? */
+ Boolean savedPrintFlag = printFlag;
+ void *info; /* Saved decoding info */
+
+
+ if (len == 0) return;
+
+ if (isHere(HERO)) { /* Check if the player will see it */
+ if (printFlag) { /* Already printing? */
+ /* Save current text file position and/or decoding info */
+ if (header->pack)
+ info = pushDecode();
+ else
+ savfp = ftell(txtfil);
+ }
+ printFlag = TRUE; /* We're printing now! */
+ fseek(txtfil, fpos, 0); /* Position to start of text */
+ if (header->pack)
+ startDecoding();
+ for (outlen = 0; outlen != (int)len; outlen = outlen + strlen(str)) {
+ /* Fill the buffer from the beginning */
+ for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) {
+ if (outlen + i == (int)len) /* No more characters? */
+ break;
+ if (header->pack)
+ ch = decodeChar();
+ else
+ ch = getc(txtfil);
+ if (ch == EOFChar) /* Or end of text? */
+ break;
+ str[i] = ch;
+ }
+ str[i] = '\0';
+#if ISO == 0
+ fromIso(str, str);
+#endif
+ output(str);
+ }
+ /* And restore */
+ printFlag = savedPrintFlag;
+ if (printFlag) {
+ if (header->pack)
+ popDecode(info);
+ else
+ fseek(txtfil, savfp, 0);
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void sys(Aword fpos, Aword len)
+#else
+void sys(fpos, len)
+ Aword fpos, len;
+#endif
+{
+#ifdef GLK
+ ::error("system calls aren't supported");
+#else
+ char *command;
+
+ getstr(fpos, len); /* Returns address to string on stack */
+ command = (char *)pop();
+ int tmp = system(command);
+ free(command);
+#endif
+}
+
+
+#ifdef _PROTOTYPES_
+void getstr(Aword fpos, Aword len)
+#else
+void getstr(fpos, len)
+ Aword fpos, len;
+#endif
+{
+ char *buf = (char *)allocate(len+1);
+
+ push((Aptr) buf); /* Push the address to the string */
+ fseek(txtfil, fpos, 0); /* Position to start of text */
+ if (header->pack)
+ startDecoding();
+ while (len--)
+ if (header->pack)
+ *(buf++) = decodeChar();
+ else
+ *(buf++) = getc(txtfil);
+ *buf = '\0';
+}
+
+
+
+#ifdef _PROTOTYPES_
+void score(Aword sc)
+#else
+void score(sc)
+ Aword sc;
+#endif
+{
+ char buf[80];
+
+ if (sc == 0) {
+ prmsg(M_SCORE1);
+ sprintf(buf, "%d", cur.score);
+ output(buf);
+ prmsg(M_SCORE2);
+ sprintf(buf, "%ld.", (unsigned long) header->maxscore);
+ output(buf);
+ } else {
+ cur.score += scores[sc-1];
+ scores[sc-1] = 0;
+ }
+}
+
+#ifdef _PROTOTYPES_
+void visits(Aword v)
+#else
+void visits(v)
+ Aword v;
+#endif
+{
+ cur.visits = v;
+}
+
+
+#ifdef _PROTOTYPES_
+Boolean confirm(MsgKind msgno)
+#else
+Boolean confirm(msgno)
+ MsgKind msgno;
+#endif
+{
+ char buf[80];
+
+ /* This is a bit of a hack since we really want to compare the input,
+ it could be affirmative, but for now any input is NOT! */
+ prmsg(msgno);
+
+#ifdef USE_READLINE
+ if (!readline(buf)) return TRUE;
+#else
+ if (gets(buf) == NULL) return TRUE;
+#endif
+ col = 1;
+
+ return (buf[0] == '\0');
+}
+
+
+#ifdef _PROTOTYPES_
+void quit(void)
+#else
+void quit()
+#endif
+{
+ char buf[80];
+ char choices[10];
+
+ para();
+ while (TRUE) {
+ col = 1;
+ statusline();
+ prmsg(M_QUITACTION);
+#ifdef USE_READLINE
+ if (!readline(buf)) terminate(0);
+#else
+ if (gets(buf) == NULL) terminate(0);
+#endif
+ if (strcmp(buf, "restart") == 0)
+ //longjmp(restart_label, TRUE);
+ ::error("TODO: restart");
+ else if (strcmp(buf, "restore") == 0) {
+ restore();
+ return;
+ } else if (strcmp(buf, "quit") == 0)
+ terminate(0);
+ }
+ syserr("Fallthrough in QUIT");
+}
+
+
+
+#ifdef _PROTOTYPES_
+void restart(void)
+#else
+void restart()
+#endif
+{
+ para();
+ if (confirm(M_REALLY)) {
+ //longjmp(restart_label, TRUE);
+ ::error("TODO: restart");
+ } else
+ return;
+ syserr("Fallthrough in RESTART");
+}
+
+
+
+#ifdef _PROTOTYPES_
+void cancl(Aword evt)
+#else
+void cancl(evt)
+ Aword evt;
+#endif
+{
+ int i;
+
+ for(i = etop-1; i>=0; i--)
+ if (eventq[i].event == evt) {
+ while (i < etop-1) {
+ eventq[i].event = eventq[i+1].event;
+ eventq[i].time = eventq[i+1].time;
+ eventq[i].where = eventq[i+1].where;
+ i++;
+ }
+ etop--;
+ return;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void schedule(Aword evt, Aword whr, Aword aft)
+#else
+void schedule(evt, whr, aft)
+ Aword evt, whr, aft;
+#endif
+{ int i;
+ int time;
+
+ cancl(evt);
+ /* Check for overflow */
+ if (etop == N_EVTS) syserr("Out of event space.");
+
+ time = cur.tick+aft;
+
+ /* Bubble this event down */
+ for (i = etop; i >= 1 && eventq[i-1].time <= time; i--) {
+ eventq[i].event = eventq[i-1].event;
+ eventq[i].time = eventq[i-1].time;
+ eventq[i].where = eventq[i-1].where;
+ }
+
+ eventq[i].time = time;
+ eventq[i].where = whr;
+ eventq[i].event = evt;
+ etop++;
+}
+
+
+/*----------------------------------------------------------------------
+
+ getatr()
+
+ Get an attribute value from an attribute list
+
+ */
+#ifdef _PROTOTYPES_
+static Aptr getatr(
+ Aaddr atradr, /* IN - ACODE address to attribute table */
+ Aaddr atr /* IN - The attribute to read */
+)
+#else
+static Aptr getatr(atradr, atr)
+ Aaddr atradr; /* IN - ACODE address to attribute table */
+ Aaddr atr; /* IN - The attribute to read */
+#endif
+{
+ AtrElem *at;
+
+ at = (AtrElem *) addrTo(atradr);
+ return at[atr-1].val;
+}
+
+
+/*----------------------------------------------------------------------
+
+ setatr()
+
+ Set a particular attribute to a value.
+
+ */
+#ifdef _PROTOTYPES_
+static void setatr(
+ Aaddr atradr, /* IN - ACODE address to attribute table */
+ Aword atr, /* IN - attribute code */
+ Aword val /* IN - new value */
+)
+#else
+static void setatr(atradr, atr, val)
+ Aaddr atradr; /* IN - ACODE address to attribute table */
+ Aword atr; /* IN - attribute code */
+ Aword val; /* IN - new value */
+#endif
+{
+ AtrElem *at;
+
+ at = (AtrElem *) addrTo(atradr);
+ at[atr-1].val = val;
+}
+
+
+/*----------------------------------------------------------------------
+
+ make()
+
+ */
+
+#ifdef _PROTOTYPES_
+static void makloc(Aword loc, Aword atr, Aword val)
+#else
+static void makloc(loc, atr, val)
+ Aword loc, atr, val;
+#endif
+{
+ setatr(locs[loc-LOCMIN].atrs, atr, val);
+}
+
+#ifdef _PROTOTYPES_
+static void makobj(Aword obj, Aword atr, Aword val)
+#else
+static void makobj(obj, atr, val)
+ Aword obj, atr, val;
+#endif
+{
+ setatr(objs[obj-OBJMIN].atrs, atr, val);
+}
+
+#ifdef _PROTOTYPES_
+static void makact(Aword act, Aword atr, Aword val)
+#else
+static void makact(act, atr, val)
+ Aword act, atr, val;
+#endif
+{
+ setatr(acts[act-ACTMIN].atrs, atr, val);
+}
+
+
+#ifdef _PROTOTYPES_
+void make(Aword id, Aword atr, Aword val)
+#else
+void make(id, atr, val)
+ Aword id, atr, val;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ makobj(id, atr, val);
+ else if (isLoc(id))
+ makloc(id, atr, val);
+ else if (isAct(id))
+ makact(id, atr, val);
+ else {
+ sprintf(str, "Can't MAKE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+}
+
+
+/*----------------------------------------------------------------------------
+
+ set()
+
+ */
+
+#ifdef _PROTOTYPES_
+static void setloc(Aword loc, Aword atr, Aword val)
+#else
+static void setloc(loc, atr, val)
+ Aword loc, atr, val;
+#endif
+{
+ setatr(locs[loc-LOCMIN].atrs, atr, val);
+ locs[loc-LOCMIN].describe = 0;
+}
+
+
+#ifdef _PROTOTYPES_
+static void setobj(Aword obj, Aword atr, Aword val)
+#else
+static void setobj(obj, atr, val)
+ Aword obj, atr, val;
+#endif
+{
+ setatr(objs[obj-OBJMIN].atrs, atr, val);
+}
+
+#ifdef _PROTOTYPES_
+static void setact(Aword act, Aword atr, Aword val)
+#else
+static void setact(act, atr, val)
+ Aword act, atr, val;
+#endif
+{
+ setatr(acts[act-ACTMIN].atrs, atr, val);
+}
+
+
+#ifdef _PROTOTYPES_
+void set(Aword id, Aword atr, Aword val)
+#else
+void set(id, atr, val)
+ Aword id, atr, val;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ setobj(id, atr, val);
+ else if (isLoc(id))
+ setloc(id, atr, val);
+ else if (isAct(id))
+ setact(id, atr, val);
+ else {
+ sprintf(str, "Can't SET item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void setstr(Aword id, Aword atr, Aword str)
+#else
+void setstr(id, atr, str)
+ Aword id, atr, str;
+#endif
+{
+ free((char *)attribute(id, atr));
+ set(id, atr, str);
+}
+
+
+
+/*-----------------------------------------------------------------------------
+
+ incr/decr
+
+ */
+
+/*----------------------------------------------------------------------
+
+ incratr()
+
+ Increment a particular attribute by a value.
+
+ */
+#ifdef _PROTOTYPES_
+static void incratr(
+ Aaddr atradr, /* IN - ACODE address to attribute table */
+ Aword atr, /* IN - attribute code */
+ Aword step /* IN - step to increment by */
+)
+#else
+static void incratr(atradr, atr, step)
+ Aaddr atradr, atr, step;
+#endif
+{
+ AtrElem *at;
+
+ at = (AtrElem *) addrTo(atradr);
+ at[atr-1].val += step;
+}
+
+
+#ifdef _PROTOTYPES_
+static void incrloc(Aword loc, Aword atr, Aword step)
+#else
+static void incrloc(loc, atr, step)
+ Aword loc, atr, step;
+#endif
+{
+ incratr(locs[loc-LOCMIN].atrs, atr, step);
+ locs[loc-LOCMIN].describe = 0;
+}
+
+
+#ifdef _PROTOTYPES_
+static void incrobj(Aword obj, Aword atr, Aword step)
+#else
+static void incrobj(obj, atr, step)
+ Aword obj, atr, step;
+#endif
+{
+ incratr(objs[obj-OBJMIN].atrs, atr, step);
+}
+
+#ifdef _PROTOTYPES_
+static void incract(Aword act, Aword atr, Aword step)
+#else
+static void incract(act, atr, step)
+ Aword act, atr, step;
+#endif
+{
+ incratr(acts[act-ACTMIN].atrs, atr, step);
+}
+
+
+#ifdef _PROTOTYPES_
+void incr(Aword id, Aword atr, Aword step)
+#else
+void incr(id, atr, step)
+ Aword id, atr, step;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ incrobj(id, atr, step);
+ else if (isLoc(id))
+ incrloc(id, atr, step);
+ else if (isAct(id))
+ incract(id, atr, step);
+ else {
+ sprintf(str, "Can't INCR item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+}
+
+#ifdef _PROTOTYPES_
+void decr(Aword id, Aword atr, Aword step)
+#else
+void decr(id, atr, step)
+ Aword id, atr, step;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ incrobj(id, atr, -step);
+ else if (isLoc(id))
+ incrloc(id, atr, -step);
+ else if (isAct(id))
+ incract(id, atr, -step);
+ else {
+ sprintf(str, "Can't DECR item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ attribute()
+
+ */
+
+#ifdef _PROTOTYPES_
+static Aptr locatr(Aword loc, Aword atr)
+#else
+static Aptr locatr(loc, atr)
+ Aword loc, atr;
+#endif
+{
+ return getatr(locs[loc-LOCMIN].atrs, atr);
+}
+
+
+
+#ifdef _PROTOTYPES_
+static Aptr objatr(Aword obj, Aword atr)
+#else
+static Aptr objatr(obj, atr)
+ Aword obj, atr;
+#endif
+{
+ return getatr(objs[obj-OBJMIN].atrs, atr);
+}
+
+#ifdef _PROTOTYPES_
+static Aptr actatr(Aword act, Aword atr)
+#else
+static Aptr actatr(act, atr)
+ Aword act, atr;
+#endif
+{
+ return getatr(acts[act-ACTMIN].atrs, atr);
+}
+
+#ifdef _PROTOTYPES_
+static Aptr litatr(Aword lit, Aword atr)
+#else
+static Aptr litatr(lit, atr)
+ Aword lit, atr;
+#endif
+{
+ char str[80];
+
+ if (atr == 1)
+ return litValues[lit-LITMIN].value;
+ else {
+ sprintf(str, "Unknown attribute for literal (%ld).", (unsigned long) atr);
+ syserr(str);
+ }
+ return (Aptr)EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+Aptr attribute(Aword id, Aword atr)
+#else
+Aptr attribute(id, atr)
+ Aword id, atr;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ return objatr(id, atr);
+ else if (isLoc(id))
+ return locatr(id, atr);
+ else if (isAct(id))
+ return actatr(id, atr);
+ else if (isLit(id))
+ return litatr(id, atr);
+ else {
+ sprintf(str, "Can't ATTRIBUTE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+ return (Aptr)EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+Aptr strattr(Aword id, Aword atr)
+#else
+Aptr strattr(id, atr)
+ Aword id, atr;
+#endif
+{
+ return (Aptr) strdup((char *)attribute(id, atr));
+}
+
+
+/*----------------------------------------------------------------------
+
+ where()
+
+ */
+
+#ifdef _PROTOTYPES_
+static Aword objloc(Aword obj)
+#else
+static Aword objloc(obj)
+ Aword obj;
+#endif
+{
+ if (isCnt(objs[obj-OBJMIN].loc)) /* In something ? */
+ if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc))
+ return(where(objs[obj-OBJMIN].loc));
+ else /* Containers not anywhere is where the hero is! */
+ return(where(HERO));
+ else
+ return(objs[obj-OBJMIN].loc);
+}
+
+
+#ifdef _PROTOTYPES_
+static Aword actloc(Aword act)
+#else
+static Aword actloc(act)
+ Aword act;
+#endif
+{
+ return(acts[act-ACTMIN].loc);
+}
+
+
+#ifdef _PROTOTYPES_
+Aword where(Aword id)
+#else
+Aword where(id)
+ Aword id;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ return objloc(id);
+ else if (isAct(id))
+ return actloc(id);
+ else {
+ sprintf(str, "Can't WHERE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+ return (Aptr)EOF;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ aggregates
+
+ */
+
+#ifdef _PROTOTYPES_
+Aint agrmax(Aword atr, Aword whr)
+#else
+Aint agrmax(atr, whr)
+ Aword atr, whr;
+#endif
+{
+ Aword i;
+ Aint max = 0;
+
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ if (isLoc(whr)) {
+ if (where(i) == whr && attribute(i, atr) > max)
+ max = attribute(i, atr);
+ } else if (objs[i-OBJMIN].loc == whr && attribute(i, atr) > max)
+ max = attribute(i, atr);
+ }
+ return(max);
+}
+
+#ifdef _PROTOTYPES_
+Aint agrsum(Aword atr, Aword whr)
+#else
+Aint agrsum(atr, whr)
+ Aword atr, whr;
+#endif
+{
+ Aword i;
+ Aint sum = 0;
+
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ if (isLoc(whr)) {
+ if (where(i) == whr)
+ sum += attribute(i, atr);
+ } else if (objs[i-OBJMIN].loc == whr)
+ sum += attribute(i, atr);
+ }
+ return(sum);
+}
+
+
+#ifdef _PROTOTYPES_
+Aint agrcount(Aword whr)
+#else
+Aint agrcount(whr)
+ Aword whr;
+#endif
+{
+ Aword i;
+ Aword count = 0;
+
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ if (isLoc(whr)) {
+ if (where(i) == whr)
+ count++;
+ } else if (objs[i-OBJMIN].loc == whr)
+ count++;
+ }
+ return(count);
+}
+
+
+/*----------------------------------------------------------------------
+
+ locate()
+
+ */
+
+#ifdef _PROTOTYPES_
+static void locobj(Aword obj, Aword whr)
+#else
+static void locobj(obj, whr)
+ Aword obj, whr;
+#endif
+{
+ if (isCnt(whr)) { /* Into a container */
+ if (whr == obj)
+ syserr("Locating something inside itself.");
+ if (checklim(whr, obj))
+ return;
+ else
+ objs[obj-OBJMIN].loc = whr;
+ } else {
+ objs[obj-OBJMIN].loc = whr;
+ /* Make sure the location is described since it's changed */
+ locs[whr-LOCMIN].describe = 0;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void locact(Aword act, Aword whr)
+#else
+static void locact(act, whr)
+ Aword act, whr;
+#endif
+{
+ Aword prevact = cur.act;
+ Aword prevloc = cur.loc;
+
+ cur.loc = whr;
+ acts[act-ACTMIN].loc = whr;
+ if (act == HERO) {
+ if (locs[acts[act-ACTMIN].loc-LOCMIN].describe % (cur.visits+1) == 0)
+ look();
+ else {
+ if (anyOutput)
+ para();
+ say(where(HERO));
+ prmsg(M_AGAIN);
+ newline();
+ dscrobjs();
+ dscracts();
+ }
+ locs[where(HERO)-LOCMIN].describe++;
+ locs[where(HERO)-LOCMIN].describe %= (cur.visits+1);
+ } else
+ locs[whr-LOCMIN].describe = 0;
+ if (locs[cur.loc-LOCMIN].does != 0) {
+ cur.act = act;
+ interpret(locs[cur.loc-LOCMIN].does);
+ cur.act = prevact;
+ }
+
+ if (cur.act != act)
+ cur.loc = prevloc;
+}
+
+
+#ifdef _PROTOTYPES_
+void locate(Aword id, Aword whr)
+#else
+void locate(id, whr)
+ Aword id, whr;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ locobj(id, whr);
+ else if (isAct(id))
+ locact(id, whr);
+ else {
+ sprintf(str, "Can't LOCATE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ isHere()
+
+ */
+
+#ifdef _PROTOTYPES_
+static Abool objhere(Aword obj)
+#else
+static Abool objhere(obj)
+ Aword obj;
+#endif
+{
+ if (isCnt(objs[obj-OBJMIN].loc)) { /* In something? */
+ if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc))
+ return(isHere(objs[obj-OBJMIN].loc));
+ else /* If the container wasn't anywhere, assume where HERO is! */
+ return(where(HERO) == cur.loc);
+ } else
+ return(objs[obj-OBJMIN].loc == cur.loc);
+}
+
+
+#ifdef _PROTOTYPES_
+static Aword acthere(Aword act)
+#else
+static Aword acthere(act)
+ Aword act;
+#endif
+{
+ return(acts[act-ACTMIN].loc == cur.loc);
+}
+
+
+#ifdef _PROTOTYPES_
+Abool isHere(Aword id)
+#else
+Abool isHere(id)
+ Aword id;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ return objhere(id);
+ else if (isAct(id))
+ return acthere(id);
+ else {
+ sprintf(str, "Can't HERE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+ return (Abool)EOF;
+}
+
+/*----------------------------------------------------------------------
+
+ isNear()
+
+ */
+
+#ifdef _PROTOTYPES_
+static Aword objnear(Aword obj)
+#else
+static Aword objnear(obj)
+ Aword obj;
+#endif
+{
+ if (isCnt(objs[obj-OBJMIN].loc)) { /* In something? */
+ if (isObj(objs[obj-OBJMIN].loc) || isAct(objs[obj-OBJMIN].loc))
+ return(isNear(objs[obj-OBJMIN].loc));
+ else /* If the container wasn't anywhere, assume here, so not nearby! */
+ return(FALSE);
+ } else
+ return(exitto(where(obj), cur.loc));
+}
+
+
+#ifdef _PROTOTYPES_
+static Aword actnear(Aword act)
+#else
+static Aword actnear(act)
+ Aword act;
+#endif
+{
+ return(exitto(where(act), cur.loc));
+}
+
+
+#ifdef _PROTOTYPES_
+Abool isNear(Aword id)
+#else
+Abool isNear(id)
+ Aword id;
+#endif
+{
+ char str[80];
+
+ if (isObj(id))
+ return objnear(id);
+ else if (isAct(id))
+ return actnear(id);
+ else {
+ sprintf(str, "Can't NEAR item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+ return (Abool)EOF;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ in()
+
+ */
+
+#ifdef _PROTOTYPES_
+Abool in(Aword obj, Aword cnt)
+#else
+Abool in(obj, cnt)
+ Aword obj;
+ Aword cnt;
+#endif
+{
+ if (!isObj(obj))
+ return(FALSE);
+ if (!isCnt(cnt))
+ syserr("IN in a non-container.");
+
+ return(objs[obj-OBJMIN].loc == cnt);
+}
+
+
+/*----------------------------------------------------------------------
+
+ say()
+
+ */
+
+#ifdef _PROTOTYPES_
+static void sayloc(Aword loc)
+#else
+static void sayloc(loc)
+ Aword loc;
+#endif
+{
+ interpret(locs[loc-LOCMIN].nams);
+}
+
+
+#ifdef _PROTOTYPES_
+static void sayobj(Aword obj)
+#else
+static void sayobj(obj)
+ Aword obj;
+#endif
+{
+ interpret(objs[obj-OBJMIN].dscr2);
+}
+
+#ifdef _PROTOTYPES_
+static void sayact(Aword act)
+#else
+static void sayact(act)
+ Aword act;
+#endif
+{
+ interpret(acts[act-ACTMIN].nam);
+}
+
+
+#ifdef _PROTOTYPES_
+void sayint(Aword val)
+#else
+void sayint(val)
+ Aword val;
+#endif
+{
+ char buf[25];
+
+ if (isHere(HERO)) {
+ sprintf(buf, "%ld", (unsigned long) val);
+ output(buf);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void saystr(char *str)
+#else
+void saystr(str)
+ char *str;
+#endif
+{
+ if (isHere(HERO))
+ output(str);
+ free(str);
+}
+
+
+#ifdef _PROTOTYPES_
+static void saylit(Aword lit)
+#else
+static void saylit(lit)
+ Aword lit;
+#endif
+{
+ char *str;
+
+ if (isNum(lit))
+ sayint(litValues[lit-LITMIN].value);
+ else {
+ str = (char *)strdup((char *)litValues[lit-LITMIN].value);
+ saystr(str);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void sayarticle(Aword id)
+#else
+void sayarticle(id)
+ Aword id;
+#endif
+{
+ if (!isObj(id))
+ syserr("Trying to say article of something *not* an object.");
+ if (objs[id-OBJMIN].art != 0)
+ interpret(objs[id-OBJMIN].art);
+ else
+ prmsg(M_ARTICLE);
+}
+
+
+#ifdef _PROTOTYPES_
+void say(Aword id)
+#else
+void say(id)
+ Aword id;
+#endif
+{
+ char str[80];
+
+ if (isHere(HERO)) {
+ if (isObj(id))
+ sayobj(id);
+ else if (isLoc(id))
+ sayloc(id);
+ else if (isAct(id))
+ sayact(id);
+ else if (isLit(id))
+ saylit(id);
+ else {
+ sprintf(str, "Can't SAY item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ describe()
+
+ */
+
+#ifdef _PROTOTYPES_
+static void dscrloc(Aword loc)
+#else
+static void dscrloc(loc)
+ Aword loc;
+#endif
+{
+ if (locs[loc-LOCMIN].dscr != 0)
+ interpret(locs[loc-LOCMIN].dscr);
+}
+
+
+#ifdef _PROTOTYPES_
+static void dscrobj(Aword obj)
+#else
+static void dscrobj(obj)
+ Aword obj;
+#endif
+{
+ objs[obj-OBJMIN].describe = FALSE;
+ if (objs[obj-OBJMIN].dscr1 != 0)
+ interpret(objs[obj-OBJMIN].dscr1);
+ else {
+ prmsg(M_SEEOBJ1);
+ sayarticle(obj);
+ say(obj);
+ prmsg(M_SEEOBJ4);
+ if (objs[obj-OBJMIN].cont != 0)
+ list(obj);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void dscract(Aword act)
+#else
+static void dscract(act)
+ Aword act;
+#endif
+{
+ ScrElem *scr = NULL;
+
+ if (acts[act-ACTMIN].script != 0) {
+ for (scr = (ScrElem *) addrTo(acts[act-ACTMIN].scradr); !endOfTable(scr); scr++)
+ if (scr->code == acts[act-ACTMIN].script)
+ break;
+ if (endOfTable(scr)) scr = NULL;
+ }
+ if (scr != NULL && scr->dscr != 0)
+ interpret(scr->dscr);
+ else if (acts[act-ACTMIN].dscr != 0)
+ interpret(acts[act-ACTMIN].dscr);
+ else {
+ interpret(acts[act-ACTMIN].nam);
+ prmsg(M_SEEACT);
+ }
+ acts[act-ACTMIN].describe = FALSE;
+}
+
+
+static Aword dscrstk[255];
+
+#ifdef _PROTOTYPES_
+void describe(Aword id)
+#else
+void describe(id)
+ Aword id;
+#endif
+{
+ int i;
+ char str[80];
+
+ for (i = 0; i < dscrstkp; i++)
+ if (dscrstk[i] == id)
+ syserr("Recursive DESCRIBE.");
+ dscrstk[dscrstkp++] = id;
+
+ if (isObj(id))
+ dscrobj(id);
+ else if (isLoc(id))
+ dscrloc(id);
+ else if (isAct(id))
+ dscract(id);
+ else {
+ sprintf(str, "Can't DESCRIBE item (%ld).", (unsigned long) id);
+ syserr(str);
+ }
+
+ dscrstkp--;
+}
+
+
+/*----------------------------------------------------------------------
+
+ use()
+
+ */
+
+#ifdef _PROTOTYPES_
+void use(Aword act, Aword scr)
+#else
+void use(act, scr)
+ Aword act, scr;
+#endif
+{
+ char str[80];
+
+ if (!isAct(act)) {
+ sprintf(str, "Item is not an Actor (%ld).", (unsigned long) act);
+ syserr(str);
+ }
+
+ acts[act-ACTMIN].script = scr;
+ acts[act-ACTMIN].step = 0;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ list()
+
+ */
+
+#ifdef _PROTOTYPES_
+void list(Aword cnt)
+#else
+void list(cnt)
+ Aword cnt;
+#endif
+{
+ int i;
+ Aword props;
+ Aword prevobj;
+ Boolean found = FALSE;
+ Boolean multiple = FALSE;
+
+ /* Find container properties */
+ if (isObj(cnt))
+ props = objs[cnt-OBJMIN].cont;
+ else if (isAct(cnt))
+ props = acts[cnt-ACTMIN].cont;
+ else
+ props = cnt;
+
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ if (in(i, cnt)) { /* Yes, it's in this container */
+ if (!found) {
+ found = TRUE;
+ if (cnts[props-CNTMIN].header != 0)
+ interpret(cnts[props-CNTMIN].header);
+ else {
+ prmsg(M_CONTAINS1);
+ if (cnts[props-CNTMIN].nam != 0) /* It has it's own name */
+ interpret(cnts[props-CNTMIN].nam);
+ else
+ say(cnts[props-CNTMIN].parent); /* It is actually an object or actor */
+ prmsg(M_CONTAINS2);
+ }
+ } else {
+ if (multiple) {
+ needsp = FALSE;
+ prmsg(M_CONTAINS3);
+ }
+ multiple = TRUE;
+ sayarticle(prevobj);
+ say(prevobj);
+ }
+ prevobj = i;
+ }
+ }
+
+ if (found) {
+ if (multiple)
+ prmsg(M_CONTAINS4);
+ sayarticle(prevobj);
+ say(prevobj);
+ prmsg(M_CONTAINS5);
+ } else {
+ if (cnts[props-CNTMIN].empty != 0)
+ interpret(cnts[props-CNTMIN].empty);
+ else {
+ prmsg(M_EMPTY1);
+ if (cnts[props-CNTMIN].nam != 0) /* It has it's own name */
+ interpret(cnts[props-CNTMIN].nam);
+ else
+ say(cnts[props-CNTMIN].parent); /* It is actually an actor or object */
+ prmsg(M_EMPTY2);
+ }
+ }
+ needsp = TRUE;
+}
+
+
+/*----------------------------------------------------------------------
+
+ empty()
+
+ */
+
+#ifdef _PROTOTYPES_
+void empty(Aword cnt, Aword whr)
+#else
+void empty(cnt, whr)
+ Aword cnt;
+ Aword whr;
+#endif
+{
+ int i;
+
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ if (in(i, cnt))
+ locate(i, whr);
+}
+
+
+
+/*----------------------------------------------------------------------*\
+
+ Description of current location
+
+ dscrobjs()
+ dscracts()
+ look()
+
+\*----------------------------------------------------------------------*/
+
+#ifdef _PROTOTYPES_
+void dscrobjs(void)
+#else
+void dscrobjs()
+#endif
+{
+ int i;
+ int prevobj;
+ Boolean found = FALSE;
+ Boolean multiple = FALSE;
+
+ /* First describe everything here with its own description */
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ if (objs[i-OBJMIN].loc == cur.loc &&
+ objs[i-OBJMIN].describe &&
+ objs[i-OBJMIN].dscr1)
+ describe(i);
+
+ /* Then list everything else here */
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ if (objs[i-OBJMIN].loc == cur.loc &&
+ objs[i-OBJMIN].describe) {
+ if (!found) {
+ prmsg(M_SEEOBJ1);
+ sayarticle(i);
+ say(i);
+ found = TRUE;
+ } else {
+ if (multiple) {
+ needsp = FALSE;
+ prmsg(M_SEEOBJ2);
+ sayarticle(prevobj);
+ say(prevobj);
+ }
+ multiple = TRUE;
+ }
+ prevobj = i;
+ }
+
+ if (found) {
+ if (multiple) {
+ prmsg(M_SEEOBJ3);
+ sayarticle(prevobj);
+ say(prevobj);
+ }
+ prmsg(M_SEEOBJ4);
+ }
+
+ /* Set describe flag for all objects */
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ objs[i-OBJMIN].describe = TRUE;
+}
+
+
+#ifdef _PROTOTYPES_
+void dscracts(void)
+#else
+void dscracts()
+#endif
+{
+ int i;
+
+ for (i = HERO+1; i <= ACTMAX; i++)
+ if (acts[i-ACTMIN].loc == cur.loc &&
+ acts[i-ACTMIN].describe)
+ describe(i);
+
+ /* Set describe flag for all actors */
+ for (i = HERO; i <= ACTMAX; i++)
+ acts[i-ACTMIN].describe = TRUE;
+}
+
+
+#ifdef _PROTOTYPES_
+void look(void)
+#else
+void look()
+#endif
+{
+ int i;
+
+ if (looking)
+ syserr("Recursive LOOK.");
+
+ looking = TRUE;
+ /* Set describe flag for all objects and actors */
+ for (i = OBJMIN; i <= OBJMAX; i++)
+ objs[i-OBJMIN].describe = TRUE;
+ for (i = ACTMIN; i <= ACTMAX; i++)
+ acts[i-ACTMIN].describe = TRUE;
+
+ if (anyOutput)
+ para();
+
+g_vm->glk_set_style(style_Subheader);
+needsp = FALSE;
+ say(cur.loc);
+ needsp = FALSE;
+ output(".");
+g_vm->glk_set_style(style_Normal);
+ newline();
+needsp = FALSE;
+ describe(cur.loc);
+ dscrobjs();
+ dscracts();
+ looking = FALSE;
+}
+
+
+
+static char savfnm[256];
+
+
+/*----------------------------------------------------------------------
+
+ save()
+
+ */
+
+#ifdef GARGLK
+void save() {
+ g_vm->saveGame();
+}
+
+#else
+
+#ifdef _PROTOTYPES_
+void save(void)
+#else
+void save()
+#endif
+{
+ int i;
+ char str[256];
+ AtrElem *atr;
+ FILE *savfil;
+
+ /* First save ? */
+ if (savfnm[0] == '\0') {
+ strcpy(savfnm, advnam);
+ strcat(savfnm, ".sav");
+ }
+ prmsg(M_SAVEWHERE);
+ sprintf(str, "(%s) : ", savfnm);
+ output(str);
+
+#ifdef USE_READLINE
+ readline(str);
+#else
+ gets(str);
+#endif
+
+frefid_t fref;
+fref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame, filemode_Write, 0);
+if (fref == NULL)
+ error(M_SAVEFAILED);
+strcpy(str, g_vm->garglk_fileref_get_name(fref));
+g_vm->glk_fileref_destroy(fref);
+
+ if (str[0] == '\0')
+ strcpy(str, savfnm);
+ col = 1;
+ if ((savfil = fopen(str, READ_MODE)) != NULL)
+ /* It already existed */
+ if (!confirm(M_SAVEOVERWRITE))
+ error(MSGMAX); /* Return to player without saying anything */
+ if ((savfil = fopen(str, WRITE_MODE)) == NULL)
+ error(M_SAVEFAILED);
+ strcpy(savfnm, str);
+
+ /* Save version of interpreter and name of game */
+ fwrite((void *)&header->vers, sizeof(Aword), 1, savfil);
+ fwrite((void *)advnam, strlen(advnam)+1, 1, savfil);
+ /* Save current values */
+ fwrite((void *)&cur, sizeof(cur), 1, savfil);
+ /* Save actors */
+ for (i = ACTMIN; i <= ACTMAX; i++) {
+ fwrite((void *)&acts[i-ACTMIN].loc, sizeof(Aword), 1, savfil);
+ fwrite((void *)&acts[i-ACTMIN].script, sizeof(Aword), 1, savfil);
+ fwrite((void *)&acts[i-ACTMIN].step, sizeof(Aword), 1, savfil);
+ fwrite((void *)&acts[i-ACTMIN].count, sizeof(Aword), 1, savfil);
+ if (acts[i-ACTMIN].atrs)
+ for (atr = (AtrElem *) addrTo(acts[i-ACTMIN].atrs); !endOfTable(atr); atr++)
+ fwrite((void *)&atr->val, sizeof(Aword), 1, savfil);
+ }
+
+ /* Save locations */
+ for (i = LOCMIN; i <= LOCMAX; i++) {
+ fwrite((void *)&locs[i-LOCMIN].describe, sizeof(Aword), 1, savfil);
+ if (locs[i-LOCMIN].atrs)
+ for (atr = (AtrElem *) addrTo(locs[i-LOCMIN].atrs); !endOfTable(atr); atr++)
+ fwrite((void *)&atr->val, sizeof(Aword), 1, savfil);
+ }
+
+ /* Save objects */
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ fwrite((void *)&objs[i-OBJMIN].loc, sizeof(Aword), 1, savfil);
+ if (objs[i-OBJMIN].atrs)
+ for (atr = (AtrElem *) addrTo(objs[i-OBJMIN].atrs); !endOfTable(atr); atr++)
+ fwrite((void *)&atr->val, sizeof(atr->val), 1, savfil);
+ }
+
+ /* Save the event queue */
+ eventq[etop].time = 0; /* Mark the top */
+ fwrite((void *)&eventq[0], sizeof(eventq[0]), etop+1, savfil);
+
+ /* Save scores */
+ for (i = 0; scores[i] != EOF; i++)
+ fwrite((void *)&scores[i], sizeof(Aword), 1, savfil);
+
+ fclose(savfil);
+}
+#endif
+
+/*----------------------------------------------------------------------
+
+ restore()
+
+ */
+
+#ifdef GARGLK
+void restore() {
+ g_vm->loadGame();
+}
+
+#else
+
+#ifdef _PROTOTYPES_
+void restore(void)
+#else
+void restore()
+#endif
+{
+ int i,tmp;
+ FILE *savfil;
+ char str[256];
+ AtrElem *atr;
+ char savedVersion[4];
+ char savedName[256];
+
+ /* First save ? */
+ if (savfnm[0] == '\0') {
+ strcpy(savfnm, advnam);
+ strcat(savfnm, ".sav");
+ }
+ prmsg(M_RESTOREFROM);
+ sprintf(str, "(%s) : ", savfnm);
+ output(str);
+#ifdef USE_READLINE
+ readline(str);
+#else
+ gets(str);
+#endif
+
+ if (str[0] == '\0')
+ strcpy(str, savfnm);
+ col = 1;
+ if (str[0] == '\0')
+ strcpy(str, savfnm); /* Use the name temporarily */
+ if ((savfil = fopen(str, READ_MODE)) == NULL)
+ error(M_SAVEMISSING);
+ strcpy(savfnm, str); /* Save it for future use */
+
+ tmp = fread((void *)&savedVersion, sizeof(Aword), 1, savfil);
+ /* 4f - save file version check doesn't seem to work on PC's! */
+ if (strncmp(savedVersion, header->vers, 4)) {
+ fclose(savfil);
+ error(M_SAVEVERS);
+ return;
+ }
+ i = 0;
+ while ((savedName[i++] = fgetc(savfil)) != '\0');
+ if (strcmp(savedName, advnam) != 0) {
+ fclose(savfil);
+ error(M_SAVENAME);
+ return;
+ }
+
+ /* Restore current values */
+ tmp = fread((void *)&cur, sizeof(cur), 1, savfil);
+ /* Restore actors */
+ for (i = ACTMIN; i <= ACTMAX; i++) {
+ tmp = fread((void *)&acts[i-ACTMIN].loc, sizeof(Aword), 1, savfil);
+ tmp = fread((void *)&acts[i-ACTMIN].script, sizeof(Aword), 1, savfil);
+ tmp = fread((void *)&acts[i-ACTMIN].step, sizeof(Aword), 1, savfil);
+ tmp = fread((void *)&acts[i-ACTMIN].count, sizeof(Aword), 1, savfil);
+ if (acts[i-ACTMIN].atrs)
+ for (atr = (AtrElem *) addrTo(acts[i-ACTMIN].atrs); !endOfTable(atr); atr++)
+ tmp = fread((void *)&atr->val, sizeof(Aword), 1, savfil);
+ }
+
+ /* Restore locations */
+ for (i = LOCMIN; i <= LOCMAX; i++) {
+ tmp = fread((void *)&locs[i-LOCMIN].describe, sizeof(Aword), 1, savfil);
+ if (locs[i-LOCMIN].atrs)
+ for (atr = (AtrElem *) addrTo(locs[i-LOCMIN].atrs); !endOfTable(atr); atr++)
+ tmp = fread((void *)&atr->val, sizeof(Aword), 1, savfil);
+ }
+
+ /* Restore objects */
+ for (i = OBJMIN; i <= OBJMAX; i++) {
+ tmp = fread((void *)&objs[i-OBJMIN].loc, sizeof(Aword), 1, savfil);
+ if (objs[i-OBJMIN].atrs)
+ for (atr = (AtrElem *) addrTo(objs[i-OBJMIN].atrs); !endOfTable(atr); atr++)
+ tmp = fread((void *)&atr->val, sizeof(atr->val), 1, savfil);
+ }
+
+ /* Restore the eventq */
+ etop = 0;
+ do {
+ tmp = fread((void *)&eventq[etop], sizeof(eventq[0]), 1, savfil);
+ etop++;
+ } while (eventq[etop-1].time != 0);
+ etop--;
+
+ /* Restore scores */
+ for (i = 0; scores[i] != EOF; i++)
+ tmp = fread((void *)&scores[i], sizeof(Aword), 1, savfil);
+
+ fclose(savfil);
+}
+
+#endif
+
+/*----------------------------------------------------------------------
+
+ rnd()
+
+ */
+
+#ifdef _PROTOTYPES_
+Aword rnd(Aword from, Aword to)
+#else
+Aword rnd(from, to)
+ Aword from, to;
+#endif
+{
+ if (to == from)
+ return to;
+ else if (to > from)
+ return (rand()/10)%(to-from+1)+from;
+ else
+ return (rand()/10)%(from-to+1)+to;
+}
+
+/*----------------------------------------------------------------------
+
+ btw()
+
+ BETWEEN
+
+ */
+
+#ifdef _PROTOTYPES_
+Abool btw(Aint val, Aint low, Aint high)
+#else
+Abool btw(val, low, high)
+ Aint val, low, high;
+#endif
+{
+ if (high > low)
+ return low <= val && val <= high;
+ else
+ return high <= val && val <= low;
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ contains()
+
+ */
+
+#ifdef _PROTOTYPES_
+Aword contains(Aptr string, Aptr substring)
+#else
+Aword contains(string, substring)
+ Aptr string, substring;;
+#endif
+{
+ Abool found;
+
+ strlow((char *)string);
+ strlow((char *)substring);
+
+ found = (strstr((char *)string, (char *)substring) != 0);
+
+ free((char *)string);
+ free((char *)substring);
+
+ return(found);
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ streq()
+
+ Compare two strings approximately, ignore case
+
+ */
+#ifdef _PROTOTYPES_
+Abool streq(char a[], char b[])
+#else
+Abool streq(a, b)
+ char a[], b[]; /* IN - Strings to compare */
+#endif
+{
+ Boolean eq;
+
+ strlow(a);
+ strlow(b);
+
+ eq = (strcmp(a, b) == 0);
+
+ free(a);
+ free(b);
+
+ return(eq);
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/exe.h b/engines/glk/alan2/exe.h
new file mode 100644
index 0000000000..0acfdda6eb
--- /dev/null
+++ b/engines/glk/alan2/exe.h
@@ -0,0 +1,127 @@
+/* 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_ALAN2_EXE
+#define GLK_ALAN2_EXE
+
+/* Header file for instruction execution unit in Alan interpreter
+ */
+
+namespace Glk {
+namespace Alan2 {
+
+/* The event queue */
+extern EvtqElem eventq[]; /* Event queue */
+extern int etop; /* Event queue top pointer */
+extern Boolean looking; /* LOOKING? flag */
+extern int dscrstkp; /* Point into describe stack */
+
+#ifdef _PROTOTYPES_
+extern void sys(Aword fpos, Aword len);
+extern Boolean confirm(MsgKind msgno);
+extern Aptr attribute(Aword item, Aword atr);
+extern void say(Aword item);
+extern void saynum(Aword num);
+extern void saystr(char *str);
+extern Aptr strattr(Aword id, Aword atr);
+extern void setstr(Aword id, Aword atr, Aword str);
+extern void getstr(Aword fpos, Aword len);
+extern void print(Aword fpos, Aword len);
+extern void look(void);
+extern void make(Aword id, Aword atr, Aword val);
+extern void set(Aword id, Aword atr, Aword val);
+extern void incr(Aword id, Aword atr, Aword step);
+extern void decr(Aword id, Aword atr, Aword step);
+extern void use(Aword act, Aword scr);
+extern void describe(Aword id);
+extern void list(Aword cnt);
+extern void locate(Aword id, Aword whr);
+extern void empty(Aword cnt, Aword whr);
+extern void score(Aword sc);
+extern void visits(Aword v);
+extern void schedule(Aword evt, Aword whr, Aword aft);
+extern void cancl(Aword evt);
+extern void quit(void);
+extern void restart(void);
+extern void save(void);
+extern void restore(void);
+extern void say(Aword id);
+extern void sayint(Aword val);
+extern Aword rnd(Aword from, Aword to);
+extern Abool btw(Aint val, Aint from, Aint to);
+extern Aword contains(Aptr string, Aptr substring);
+extern Abool streq(char a[], char b[]);
+extern Abool in(Aword obj, Aword cnt);
+extern Aword where(Aword item);
+extern Aint agrmax(Aword atr, Aword whr);
+extern Aint agrsum(Aword atr, Aword whr);
+extern Aint agrcount(Aword whr);
+extern Abool isHere(Aword item);
+extern Abool isNear(Aword item);
+
+#else
+extern void sys();
+extern Boolean confirm();
+extern Aptr attribute();
+extern void say();
+extern void saynum();
+extern void saystr();
+extern Aptr strattr();
+extern void setstr();
+extern void getstr();
+extern void print();
+extern void look();
+extern void make();
+extern void set();
+extern void incr();
+extern void decr();
+extern void use();
+extern void describe();
+extern void list();
+extern void locate();
+extern void empty();
+extern void score();
+extern void visits();
+extern void schedule();
+extern void cancl();
+extern void quit();
+extern void restart();
+extern void save();
+extern void restore();
+extern void say();
+extern void sayint();
+extern Aword rnd();
+extern Abool btw();
+extern Aword contains()
+extern Abool streq();
+extern Abool in();
+extern Aword where();
+extern Aword agrmax();
+extern Aword agrsum();
+extern Abool isHere();
+extern Abool isNear();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/glkio.cpp b/engines/glk/alan2/glkio.cpp
new file mode 100644
index 0000000000..346413170c
--- /dev/null
+++ b/engines/glk/alan2/glkio.cpp
@@ -0,0 +1,47 @@
+/* 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/glk.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/glkio.h"
+
+namespace Glk {
+namespace Alan2 {
+
+void glkio_printf(char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ if (glkMainWin) {
+ char buf[1024]; /* FIXME: buf size should be foolproof */
+ vsprintf(buf, fmt, argp);
+ g_vm->glk_put_string(buf);
+ } else {
+ // assume stdio is available in this case only
+ Common::String str = Common::String::vformat(fmt, argp);
+ warning(fmt, argp);
+ }
+
+ va_end(argp);
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/glkio.h b/engines/glk/alan2/glkio.h
new file mode 100644
index 0000000000..7dca2cab87
--- /dev/null
+++ b/engines/glk/alan2/glkio.h
@@ -0,0 +1,48 @@
+/* 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_ALAN2_GLKIO
+#define GLK_ALAN2_GLKIO
+
+/* Header file for Glk output for Alan interpreter
+ */
+
+#include "glk/windows.h"
+
+namespace Glk {
+namespace Alan2 {
+
+winid_t glkMainWin;
+winid_t glkStatusWin;
+
+/* NB: this header must be included in any file which calls print() */
+
+#define print glkio_printf
+#undef printf
+#define printf glkio_printf
+
+void glkio_printf(char *, ...);
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/glkstart.cpp b/engines/glk/alan2/glkstart.cpp
new file mode 100644
index 0000000000..1119e18bf0
--- /dev/null
+++ b/engines/glk/alan2/glkstart.cpp
@@ -0,0 +1,65 @@
+/* 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/alan2/alan2.h"
+#include "glk/alan2/glkstart.h"
+#include "glk/alan2/glkio.h"
+#include "glk/alan2/args.h"
+
+#include "glk/alan2/alan_version.h"
+
+namespace Glk {
+namespace Alan2 {
+
+glkunix_argumentlist_t glkunix_arguments[] = {
+ { "-v", glkunix_arg_NoValue, "-v: verbose mode" },
+ { "-l", glkunix_arg_NoValue, "-l: log player command and game output" },
+ { "-i", glkunix_arg_NoValue, "-i: ignore version and checksum errors" },
+ { "-d", glkunix_arg_NoValue, "-d: enter debug mode" },
+ { "-t", glkunix_arg_NoValue, "-t: trace game execution" },
+ { "-s", glkunix_arg_NoValue, "-s: single instruction trace" },
+ { "", glkunix_arg_ValueFollows, "filename: The game file to load." },
+ { NULL, glkunix_arg_End, NULL }
+};
+
+bool glkunix_startup_code(glkunix_startup_t *data) {
+ // first, open a window for error output
+ glkMainWin = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
+ if (glkMainWin == nullptr)
+ error("FATAL ERROR: Cannot open initial window");
+
+ g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
+ glkStatusWin = g_vm->glk_window_open(glkMainWin, winmethod_Above |
+ winmethod_Fixed, 1, wintype_TextGrid, 0);
+ g_vm->glk_set_window(glkMainWin);
+
+ /* now process the command line arguments */
+ args(data->argc, data->argv);
+
+ g_vm->garglk_set_program_name(alan.shortHeader);
+ g_vm->garglk_set_program_info("Alan Interpreter 2.8.6 by Thomas Nilsson\n");
+
+ return true;
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/glkstart.h b/engines/glk/alan2/glkstart.h
new file mode 100644
index 0000000000..7e3a24b4dc
--- /dev/null
+++ b/engines/glk/alan2/glkstart.h
@@ -0,0 +1,70 @@
+/* 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_ALAN2_GLK_START
+#define GLK_ALAN2_GLK_START
+
+/* This header defines an interface that must be used by program linked
+ with the various Unix Glk libraries -- at least, the three I wrote.
+ (I encourage anyone writing a Unix Glk library to use this interface,
+ but it's not part of the Glk spec.)
+
+ Because Glk is *almost* perfectly portable, this interface *almost*
+ doesn't have to exist. In practice, it's small.
+*/
+
+namespace Glk {
+namespace Alan2 {
+
+#define glkunix_arg_End (0)
+#define glkunix_arg_ValueFollows (1)
+#define glkunix_arg_NoValue (2)
+#define glkunix_arg_ValueCanFollow (3)
+#define glkunix_arg_NumberValue (4)
+
+typedef struct glkunix_argumentlist_struct {
+ char *name;
+ int argtype;
+ char *desc;
+} glkunix_argumentlist_t;
+
+typedef struct glkunix_startup_struct {
+ int argc;
+ char **argv;
+} glkunix_startup_t;
+
+/* The list of command-line arguments; this should be defined in your code. */
+extern glkunix_argumentlist_t glkunix_arguments[];
+
+/* The external function; this should be defined in your code. */
+extern bool glkunix_startup_code(glkunix_startup_t *data);
+
+/* Some helpful utility functions which the library makes available
+ to your code. Obviously, this is nonportable; so you should
+ only call it from glkunix_startup_code().
+*/
+extern strid_t glkunix_stream_open_pathname(char *pathname, uint textmode, uint rock);
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/inter.cpp b/engines/glk/alan2/inter.cpp
new file mode 100644
index 0000000000..02b4f4819f
--- /dev/null
+++ b/engines/glk/alan2/inter.cpp
@@ -0,0 +1,893 @@
+/* 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 <string>
+#include "glk/alan2/types.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/parse.h"
+#include "glk/alan2/exe.h"
+#include "glk/alan2/stack.h"
+#include "glk/alan2/sysdep.h"
+
+#include "glk/alan2/inter.h"
+
+#ifdef GLK
+#include "glk/alan2/glkio.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+/* PRIVATE DATA */
+
+static int pc;
+
+
+#ifdef _PROTOTYPES_
+static void if_(
+ Aword v
+)
+#else
+static void if_(v)
+ Aword v;
+#endif
+{
+ int lev = 1;
+ Aword i;
+
+ if (!v) {
+ /* Skip to next ELSE or ENDIF on same level */
+ while (TRUE) {
+ i = memory[pc++];
+ if (I_CLASS(i) == (Aword)C_STMOP)
+ switch (I_OP(i)) {
+ case I_ELSE:
+ if (lev == 1) return;
+ break;
+ case I_IF:
+ lev++;
+ break;
+ case I_ENDIF:
+ lev--;
+ if (lev == 0) return;
+ break;
+ }
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void else_(void)
+#else
+static void else_()
+#endif
+{
+ int lev = 1;
+ Aword i;
+
+ while (TRUE) {
+ /* Skip to ENDIF on the same level */
+ i = memory[pc++];
+ if (I_CLASS(i) == (Aword)C_STMOP)
+ switch (I_OP(i)) {
+ case I_ENDIF:
+ lev--;
+ if (lev == 0) return;
+ break;
+ case I_IF:
+ lev++;
+ break;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void depstart(void)
+#else
+static void depstart(void)
+#endif
+{
+ /* A DEPSTART was executed so skip across the redundant DEPCASE to
+ start at the first expression */
+ pc++;
+}
+
+
+#ifdef _PROTOTYPES_
+static void swap(void)
+#else
+static void swap()
+#endif
+{
+ Aptr v1 = pop();
+ Aptr v2 = pop();
+
+ push(v1);
+ push(v2);
+}
+
+
+
+#ifdef _PROTOTYPES_
+static void depexec(
+ Aword v
+)
+#else
+static void depexec(v)
+ Aword v;
+#endif
+{
+ int lev = 1;
+ Aword i;
+
+ if (!v)
+ /* The expression was not true, skip to next CASE on the same
+ level which could be a DEPCASE or DEPELSE */
+ while (TRUE) {
+ i = memory[pc++];
+ if (I_CLASS(i) == (Aword)C_STMOP)
+ switch (I_OP(i)) {
+ case I_DEPSTART:
+ lev++;
+ break;
+ case I_DEPEND:
+ if (lev == 1) return;
+ lev--;
+ break;
+ case I_DEPCASE:
+ case I_DEPELSE:
+ if (lev == 1) return;
+ break;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void depcase(void)
+#else
+static void depcase()
+#endif
+{
+ int lev = 1;
+ Aword i;
+
+ /* Skip to end of DEPENDING block (next DEPEND on same level) because
+ we have just executed a DEPCASE/DEPELSE statement as a result of a DEPCASE
+ catching */
+
+ while (TRUE) {
+ i = memory[pc++];
+ if (I_CLASS(i) == (Aword)C_STMOP)
+ switch (I_OP(i)) {
+ case I_DEPSTART:
+ lev++;
+ break;
+ case I_DEPEND:
+ lev--;
+ if (lev == 0) return;
+ break;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void interpret(Aaddr adr)
+#else
+void interpret(adr)
+ Aaddr adr;
+#endif
+{
+ Aaddr oldpc;
+ Aword i;
+
+ if (stpflg) printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+ oldpc = pc;
+ pc = adr;
+ while(TRUE) {
+ if (stpflg) printf("\n%4x: ", pc);
+ if (pc > memTop)
+ syserr("Interpreting outside program.");
+
+ i = memory[pc++];
+
+ switch (I_CLASS(i)) {
+ case C_CONST:
+ if (stpflg) printf("PUSH \t%5ld", I_OP(i));
+ push(I_OP(i));
+ break;
+ case C_CURVAR:
+ switch (I_OP(i)) {
+ case V_PARAM:
+ if (stpflg) printf("PARAM \t%5ld\t\t(%ld)", top(), params[top()-1].code);
+ push(params[pop()-1].code);
+ break;
+ case V_CURLOC:
+ if (stpflg) printf("CURLOC \t\t\t(%d)", cur.loc);
+ push(cur.loc);
+ break;
+ case V_CURACT:
+ if (stpflg) printf("CURACT \t\t\t(%d)", cur.act);
+ push(cur.act);
+ break;
+ case V_CURVRB:
+ if (stpflg) printf("CURVRB \t\t\t(%d)", cur.vrb);
+ push(cur.vrb);
+ break;
+ case V_SCORE:
+ if (stpflg) printf("CURSCORE \t\t\t(%d)", cur.score);
+ push(cur.score);
+ break;
+ default:
+ syserr("Unknown CURVAR instruction.");
+ break;
+ }
+ break;
+
+ case C_STMOP:
+ switch (I_OP(i)) {
+ case I_PRINT: {
+ Aptr fpos, len;
+ fpos = pop();
+ len = pop();
+ if (stpflg) {
+ printf("PRINT \t%5ld, %5ld\t\"", fpos, len);
+ col = 34; /* To format it better! */
+ }
+ print((char *)fpos, len);
+ if (stpflg)
+ printf("\"");
+ break;
+ }
+ case I_SYSTEM: {
+ Aptr fpos, len;
+ fpos = pop();
+ len = pop();
+ if (stpflg) {
+ printf("SYSTEM \t%5ld, %5ld\t\"", fpos, len);
+ col = 34; /* To format it better! */
+ }
+ sys(fpos, len);
+ break;
+ }
+ case I_GETSTR: {
+ Aptr fpos, len;
+ fpos = pop();
+ len = pop();
+ if (stpflg)
+ printf("GETSTR\t%5ld, %5ld", fpos, len);
+ getstr(fpos, len);
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_QUIT: {
+ if (stpflg)
+ printf("QUIT");
+ quit();
+ break;
+ }
+ case I_LOOK: {
+ if (stpflg)
+ printf("LOOK");
+ look();
+ break;
+ }
+ case I_SAVE: {
+ if (stpflg)
+ printf("SAVE");
+ save();
+ break;
+ }
+ case I_RESTORE: {
+ if (stpflg)
+ printf("RESTORE");
+ restore();
+ break;
+ }
+ case I_RESTART: {
+ if (stpflg)
+ printf("RESTART");
+ restart();
+ break;
+ }
+ case I_LIST: {
+ Aptr cnt;
+ cnt = pop();
+ if (stpflg)
+ printf("LIST \t%5ld", cnt);
+ list(cnt);
+ break;
+ }
+ case I_EMPTY: {
+ Aptr cnt, whr;
+ cnt = pop();
+ whr = pop();
+ if (stpflg)
+ printf("EMPTY \t%5ld, %5ld", cnt, whr);
+ empty(cnt, whr);
+ break;
+ }
+ case I_SCORE: {
+ Aptr sc;
+ sc = pop();
+ if (stpflg)
+ printf("SCORE \t%5ld\t\t(%ld)", sc, scores[sc-1]);
+ score(sc);
+ break;
+ }
+ case I_VISITS: {
+ Aptr v;
+ v = pop();
+ if (stpflg)
+ printf("VISITS \t%5ld", v);
+ visits(v);
+ break;
+ }
+ case I_SCHEDULE: {
+ Aptr evt, whr, aft;
+ evt = pop();
+ whr = pop();
+ aft = pop();
+ if (stpflg)
+ printf("SCHEDULE \t%5ld, %5ld, %5ld", evt, whr, aft);
+ schedule(evt, whr, aft);
+ break;
+ }
+ case I_CANCEL: {
+ Aptr evt;
+ evt = pop();
+ if (stpflg)
+ printf("CANCEL \t%5ld", evt);
+ cancl(evt);
+ break;
+ }
+ case I_MAKE: {
+ Aptr id, atr, val;
+ id = pop();
+ atr = pop();
+ val = pop();
+ if (stpflg) {
+ printf("MAKE \t%5ld, %5ld, ", id, atr);
+ if (val) printf("TRUE"); else printf("FALSE");
+ }
+ make(id, atr, val);
+ break;
+ }
+ case I_SET: {
+ Aptr id, atr, val;
+ id = pop();
+ atr = pop();
+ val = pop();
+ if (stpflg) {
+ printf("SET \t%5ld, %5ld, %5ld", id, atr, val);
+ }
+ set(id, atr, val);
+ break;
+ }
+ case I_STRSET: {
+ Aptr id, atr, str;
+ id = pop();
+ atr = pop();
+ str = pop();
+ if (stpflg) {
+ printf("STRSET\t%5ld, %5ld, %5ld", id, atr, str);
+ }
+ setstr(id, atr, str);
+ break;
+ }
+ case I_INCR: {
+ Aptr id, atr, step;
+ id = pop();
+ atr = pop();
+ step = pop();
+ if (stpflg) {
+ printf("INCR\t%5ld, %5ld, %5ld", id, atr, step);
+ }
+ incr(id, atr, step);
+ break;
+ }
+ case I_DECR: {
+ Aptr id, atr, step;
+ id = pop();
+ atr = pop();
+ step = pop();
+ if (stpflg) {
+ printf("DECR\t%5ld, %5ld, %5ld", id, atr, step);
+ }
+ decr(id, atr, step);
+ break;
+ }
+ case I_ATTRIBUTE: {
+ Aptr id, atr;
+ id = pop();
+ atr = pop();
+ if (stpflg)
+ printf("ATTRIBUTE %5ld, %5ld", id, atr);
+ push(attribute(id, atr));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_STRATTR: {
+ Aptr id, atr;
+ id = pop();
+ atr = pop();
+ if (stpflg)
+ printf("STRATTR \t%5ld, %5ld", id, atr);
+ push(strattr(id, atr));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_LOCATE: {
+ Aptr id, whr;
+ id = pop();
+ whr = pop();
+ if (stpflg)
+ printf("LOCATE \t%5ld, %5ld", id, whr);
+ locate(id, whr);
+ break;
+ }
+ case I_WHERE: {
+ Aptr id;
+ id = pop();
+ if (stpflg)
+ printf("WHERE \t%5ld", id);
+ push(where(id));
+ if (stpflg)
+ printf("\t\t(%ld)", top());
+ break;
+ }
+ case I_HERE: {
+ Aptr id;
+ id = pop();
+ if (stpflg)
+ printf("HERE \t%5ld", id);
+ push(isHere(id));
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_NEAR: {
+ Aptr id;
+ id = pop();
+ if (stpflg)
+ printf("NEAR \t%5ld", id);
+ push(isNear(id));
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_USE: {
+ Aptr act, scr;
+ act = pop();
+ scr = pop();
+ if (stpflg)
+ printf("USE \t%5ld, %5ld", act, scr);
+ use(act, scr);
+ break;
+ }
+ case I_IN: {
+ Aptr obj, cnt;
+ obj = pop();
+ cnt = pop();
+ if (stpflg)
+ printf("IN \t%5ld, %5ld ", obj, cnt);
+ push(in(obj, cnt));
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_DESCRIBE: {
+ Aptr id;
+ id = pop();
+ if (stpflg) {
+ printf("DESCRIBE \t%5ld\t", id);
+ col = 34; /* To format it better! */
+ }
+ describe(id);
+ break;
+ }
+ case I_SAY: {
+ Aptr id;
+ id = pop();
+ if (stpflg)
+ printf("SAY \t%5ld\t\t\"", id);
+ say(id);
+ if (stpflg)
+ printf("\"");
+ break;
+ }
+ case I_SAYINT: {
+ Aptr val;
+ val = pop();
+ if (stpflg)
+ printf("SAYINT\t%5ld\t\t\"", val);
+ sayint(val);
+ if (stpflg)
+ printf("\"");
+ break;
+ }
+ case I_SAYSTR: {
+ Aptr adr;
+ adr = pop();
+ if (stpflg)
+ printf("SAYSTR\t%5ld\t\t\"", adr);
+ saystr((char *)adr);
+ if (stpflg)
+ printf("\"");
+ break;
+ }
+ case I_IF: {
+ Aptr v;
+ v = pop();
+ if (stpflg) {
+ printf("IF \t");
+ if (v) printf(" TRUE"); else printf("FALSE");
+ }
+ if_(v);
+ break;
+ }
+ case I_ELSE: {
+ if (stpflg)
+ printf("ELSE");
+ else_();
+ break;
+ }
+ case I_ENDIF: {
+ if (stpflg)
+ printf("ENDIF");
+ break;
+ }
+ case I_AND: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg) {
+ printf("AND \t");
+ if (lh) printf("TRUE, "); else printf("FALSE, ");
+ if (rh) printf("TRUE"); else printf("FALSE");
+ }
+ push(lh && rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_OR: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg) {
+ printf("OR \t");
+ if (lh) printf("TRUE, "); else printf("FALSE, ");
+ if (rh) printf("TRUE"); else printf("FALSE");
+ }
+ push(lh || rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_NE: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("NE \t%5ld, %5ld", lh, rh);
+ push(lh != rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_EQ: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("EQ \t%5ld, %5ld", lh, rh);
+ push(lh == rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_STREQ: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("STREQ \t%5ld, %5ld", lh, rh);
+ push(streq((char *)lh, (char *)rh));
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_STREXACT: {
+ Aptr lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("STREXACT \t%5ld, %5ld", lh, rh);
+ push(strcmp((char *)lh, (char *)rh) == 0);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ free((void *)lh);
+ free((void *)rh);
+ break;
+ }
+ case I_LE: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("LE \t%5ld, %5ld", lh, rh);
+ push(lh <= rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_GE: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("GE \t%5ld, %5ld", lh, rh);
+ push(lh >= rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_LT: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("LT \t%5ld, %5ld", lh, rh);
+ push((signed int)lh < (signed int)rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_GT: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("GT \t%5ld, %5ld", lh, rh);
+ push(lh > rh);
+ if (stpflg)
+ if (top()) printf("\t(TRUE)"); else printf("\t(FALSE)");
+ break;
+ }
+ case I_PLUS: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("PLUS \t%5ld, %5ld", lh, rh);
+ push(lh + rh);
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_MINUS: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("MINUS \t%5ld, %5ld", lh, rh);
+ push(lh - rh);
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_MULT: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("MULT \t%5ld, %5ld", lh, rh);
+ push(lh * rh);
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_DIV: {
+ Aint lh, rh;
+ if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
+ swap();
+ rh = pop();
+ lh = pop();
+ if (stpflg)
+ printf("DIV \t%5ld, %5ld", lh, rh);
+ push(lh / rh);
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_NOT: {
+ Aptr val;
+ val = pop();
+ if (stpflg) {
+ printf("NOT \t");
+ if (val) printf("TRUE"); else printf("FALSE");
+ }
+ push(!val);
+ if (stpflg)
+ if (top()) printf("\t\t(TRUE)"); else printf("\t\t(FALSE)");
+ break;
+ }
+ case I_MAX: {
+ Aptr atr, whr;
+ atr = pop();
+ whr = pop();
+ if (stpflg)
+ printf("MAX \t%5ld, %5ld", atr, whr);
+ push(agrmax(atr, whr));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_SUM: {
+ Aptr atr, whr;
+ atr = pop();
+ whr = pop();
+ if (stpflg)
+ printf("SUM \t%5ld, %5ld", atr, whr);
+ push(agrsum(atr, whr));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_COUNT: {
+ Aptr whr;
+ whr = pop();
+ if (stpflg)
+ printf("COUNT \t%5ld", whr);
+ push(agrcount(whr));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_RND: {
+ Aptr from, to;
+ from = pop();
+ to = pop();
+ if (stpflg)
+ printf("RANDOM \t%5ld, %5ld", from, to);
+ push(rnd(from, to));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_BTW: {
+ Aint low, high, val;
+ high = pop();
+ low = pop();
+ val = pop();
+ if (stpflg)
+ printf("BETWEEN \t%5ld, %5ld, %5ld", val, low, high);
+ push(btw(val, low, high));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+ case I_CONTAINS: {
+ Aptr string, substring;
+ substring = pop();
+ string = pop();
+ if (stpflg)
+ printf("CONTAINS \t%5ld, %5ld", string, substring);
+ push(contains(string, substring));
+ if (stpflg)
+ printf("\t(%ld)", top());
+ break;
+ }
+
+ case I_DEPSTART:
+ if (stpflg)
+ printf("DEPSTART");
+ depstart();
+ break;
+
+ case I_DEPCASE:
+ if (stpflg)
+ printf("DEPCASE");
+ depcase();
+ break;
+
+ case I_DEPEXEC: {
+ Aptr v;
+ v = pop();
+ if (stpflg) {
+ printf("DEPEXEC \t");
+ if (v) printf(" TRUE"); else printf("FALSE");
+ }
+ depexec(v);
+ break;
+ }
+
+ case I_DEPELSE:
+ if (stpflg)
+ printf("DEPELSE");
+ depcase();
+ break;
+
+ case I_DEPEND:
+ if (stpflg)
+ printf("DEPEND");
+ break;
+
+ case I_RETURN:
+ if (stpflg)
+ printf("RETURN\n--------------------------------------------------\n");
+ pc = oldpc;
+ return;
+
+ default:
+ syserr("Unknown STMOP instruction.");
+ break;
+ }
+ if (fail) {
+ pc = oldpc;
+ return;
+ }
+ break;
+
+ default:
+ syserr("Unknown instruction class.");
+ break;
+ }
+ }
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/inter.h b/engines/glk/alan2/inter.h
new file mode 100644
index 0000000000..a7fafefc59
--- /dev/null
+++ b/engines/glk/alan2/inter.h
@@ -0,0 +1,38 @@
+/* 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_ALAN2_INTER
+#define GLK_ALAN2_INTER
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+extern void interpret(Aaddr adr);
+#else
+extern void interpret();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/main.h b/engines/glk/alan2/main.h
new file mode 100644
index 0000000000..48c6d96382
--- /dev/null
+++ b/engines/glk/alan2/main.h
@@ -0,0 +1,155 @@
+/* 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_ALAN2_MAIN
+#define GLK_ALAN2_MAIN
+
+/* Header file for main unit of ARUN Alan System interpreter */
+
+#include "common/file.h"
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/* DATA */
+
+#define MEMORYSIZE 1000L
+
+extern int memTop; /* Top of memory */
+
+extern int conjWord; /* First conjunction in dictionary */
+
+/* The Amachine memory */
+extern Aword *memory;
+extern AcdHdr *header;
+
+/* Amachine variables */
+extern CurVars cur;
+
+/* Amachine data structures */
+extern WrdElem *dict; /* Dictionary pointer */
+extern ActElem *acts; /* Actor table pointer */
+extern LocElem *locs; /* Location table pointer */
+extern VrbElem *vrbs; /* Verb table pointer */
+extern StxElem *stxs; /* Syntax table pointer */
+extern ObjElem *objs; /* Object table pointer */
+extern CntElem *cnts; /* Container table pointer */
+extern RulElem *ruls; /* Rule table pointer */
+extern EvtElem *evts; /* Event table pointer */
+extern MsgElem *msgs; /* Message table pointer */
+extern Aword *scores; /* Score table pointer */
+extern Aword *freq; /* Cumulated frequencies */
+
+extern int dictsize; /* Number of entries in dictionary */
+
+/* The text and message file */
+extern Common::File *txtfil;
+extern Common::WriteStream *logfil;
+
+#undef ftell
+#undef fgetc
+#undef getc
+#undef fseek
+#undef fclose
+#define ftell(FP) FP->pos()
+#define fgetc(FP) (FP->pos() >= FP->size()) ? EOF : FP->readByte()
+#define getc(FP) (FP->pos() >= FP->size()) ? EOF : FP->readByte()
+#define fseek(FP, OFS, WHENCE) FP->seek(OFS, WHENCE)
+#define fclose(FP) delete FP
+
+
+/* File names */
+extern char *advnam;
+
+/* Screen formatting info */
+extern int col, lin;
+extern int paglen, pagwidth;
+
+/* Long jump buffer for restart */
+//extern jmp_buf restart_label;
+
+extern Boolean verbose, errflg, trcflg, dbgflg, stpflg, logflg, statusflg;
+extern Boolean fail;
+extern Boolean anyOutput;
+extern Boolean needsp;
+
+#define endOfTable(x) eot((Aword *) x)
+
+
+#ifdef _PROTOTYPES_
+extern void *allocate(unsigned long len);
+extern void terminate(int code);
+extern void usage(void);
+extern void error(MsgKind msg);
+extern void syserr(char *msg);
+extern void statusline(void);
+extern void output(char string[]);
+extern void prmsg(MsgKind msg);
+extern void para(void);
+extern void newline(void);
+
+extern Boolean checklim(Aword cnt, Aword obj);
+extern Boolean possible(void);
+extern Boolean exitto(int to, int from);
+extern void action(ParamElem *plst);
+extern void go(int dir);
+
+extern Boolean eot(Aword *adr);
+extern Boolean isObj(Aword x);
+extern Boolean isCnt(Aword x);
+extern Boolean isAct(Aword x);
+extern Boolean isLoc(Aword x);
+extern Boolean isLit(Aword x);
+extern Boolean isNum(Aword x);
+extern Boolean isStr(Aword x);
+
+/* Run the game! */
+extern void run(void);
+
+#else
+extern void *allocate();
+extern void terminate();
+extern void syserr();
+extern void usage();
+extern void error();
+extern void output();
+extern void statusline();
+extern void prmsg();
+extern void print();
+extern void para();
+extern void newline();
+extern Boolean checklim();
+extern Boolean possible();
+extern Boolean eot();
+extern Boolean isObj();
+extern Boolean isCnt();
+extern Boolean isAct();
+extern Boolean isLoc();
+extern Boolean isLit();
+extern void run();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/params.cpp b/engines/glk/alan2/params.cpp
new file mode 100644
index 0000000000..b8851035f2
--- /dev/null
+++ b/engines/glk/alan2/params.cpp
@@ -0,0 +1,159 @@
+/* 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 <stdio.h>
+#include "glk/alan2/types.h"
+#include "glk/alan2/params.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+void compact(ParamElem a[])
+#else
+void compact(a)
+ ParamElem a[];
+#endif
+{
+ int i, j;
+
+ for (i = 0, j = 0; a[j].code != (Aword)EOF; j++)
+ if (a[j].code != 0)
+ a[i++] = a[j];
+ a[i].code = (Aword)EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+int lstlen(ParamElem a[])
+#else
+int lstlen(a)
+ ParamElem a[];
+#endif
+{
+ int i = 0;
+
+ while (a[i].code != (Aword)EOF)
+ i++;
+ return (i);
+}
+
+
+#ifdef _PROTOTYPES_
+Boolean inlst(ParamElem l[], Aword e)
+#else
+Boolean inlst(l, e)
+ ParamElem l[];
+ Aword e;
+#endif
+{
+ int i;
+
+ for (i = 0; l[i].code != (Aword)EOF && l[i].code != e; i++);
+ return (l[i].code == e);
+}
+
+
+#ifdef _PROTOTYPES_
+void lstcpy(ParamElem a[], ParamElem b[])
+#else
+void lstcpy(a, b)
+ ParamElem a[], b[];
+#endif
+{
+ int i;
+
+ for (i = 0; b[i].code != (Aword)EOF; i++)
+ a[i] = b[i];
+ a[i].code = (Aword)EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+void sublst(ParamElem a[], ParamElem b[])
+#else
+void sublst(a, b)
+ ParamElem a[], b[];
+#endif
+{
+ int i;
+
+ for (i = 0; a[i].code != (Aword)EOF; i++)
+ if (inlst(b, a[i].code))
+ a[i].code = 0; /* Mark empty */
+ compact(a);
+}
+
+
+#ifdef _PROTOTYPES_
+void mrglst(ParamElem a[], ParamElem b[])
+#else
+void mrglst(a, b)
+ ParamElem a[], b[];
+#endif
+{
+ int i,last;
+
+ for (last = 0; a[last].code != (Aword)EOF; last++); /* Find end of list */
+ for (i = 0; b[i].code != (Aword)EOF; i++)
+ if (!inlst(a, b[i].code)) {
+ a[last++] = b[i];
+ a[last].code = (Aword)EOF;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+void isect(ParamElem a[], ParamElem b[])
+#else
+void isect(a, b)
+ ParamElem a[], b[];
+#endif
+{
+ int i, last = 0;
+
+ for (i = 0; a[i].code != (Aword)EOF; i++)
+ if (inlst(b, a[i].code))
+ a[last++] = a[i];
+ a[last].code = (Aword)EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+void cpyrefs(ParamElem p[], Aword r[])
+#else
+void cpyrefs(p, r)
+ ParamElem p[];
+ Aword r[];
+#endif
+{
+ int i;
+
+ for (i = 0; r[i] != (Aword)EOF; i++) {
+ p[i].code = r[i];
+ p[i].firstWord = (Aword)EOF;
+ }
+ p[i].code = (Aword)EOF;
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/params.h b/engines/glk/alan2/params.h
new file mode 100644
index 0000000000..82fa84be9c
--- /dev/null
+++ b/engines/glk/alan2/params.h
@@ -0,0 +1,66 @@
+/* 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_ALAN2_PARAMS
+#define GLK_ALAN2_PARAMS
+
+#include "glk/alan2/types.h"
+
+/* Various utility functions for handling parameters:
+ *
+ * compact() Compact a list, i.e remove any NULL elements
+ * lstlen() Count number of elements
+ * inlst() Check if an element is in the list
+ * sublst() Subract two lists
+ * lstcpy() Copy one list onto another
+ * mrglst() Merge the paramElems of one list into the first
+ * isect() Take the intersection of two lists
+ * cpyrefs() Copy the refs (in dictionary) to a paramList
+ */
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+extern void compact(ParamElem *a);
+extern int lstlen(ParamElem *a);
+extern Boolean inlst(ParamElem *l, Aword e);
+extern void lstcpy(ParamElem *a, ParamElem *b);
+extern void sublst(ParamElem *a, ParamElem *b);
+extern void mrglst(ParamElem *a, ParamElem *b);
+extern void isect(ParamElem *a, ParamElem *b);
+extern void cpyrefs(ParamElem *p, Aword *r);
+#else
+extern void compact();
+extern int lstlen();
+extern Boolean inlst();
+extern void lstcpy();
+extern void sublst();
+extern void mrglst();
+extern void isect();
+extern void cpyrefs();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp
new file mode 100644
index 0000000000..4e54c5cd6d
--- /dev/null
+++ b/engines/glk/alan2/parse.cpp
@@ -0,0 +1,846 @@
+/* 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 <string>
+#include "glk/alan2/types.h"
+
+#ifdef USE_READLINE
+#include "glk/alan2/readline.h"
+#endif
+
+#include "glk/alan2/main.h"
+#include "glk/alan2/inter.h"
+#include "glk/alan2/exe.h"
+#include "glk/alan2/term.h"
+#include "glk/alan2/debug.h"
+#include "glk/alan2/params.h"
+
+#include "glk/alan2/parse.h"
+
+#ifdef GLK
+#include "glk/alan2/glkio.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+#define LISTLEN 100
+
+
+/* PUBLIC DATA */
+
+int wrds[LISTLEN/2] = {EOF}; /* List of parsed words */
+int wrdidx; /* and an index into it */
+
+Boolean plural = FALSE;
+
+
+/* Syntax Parameters */
+int paramidx; /* Index in params */
+ParamElem *params; /* List of params */
+static ParamElem *pparams; /* Previous parameter list */
+static ParamElem *mlst; /* Multiple objects list */
+static ParamElem *pmlst; /* Previous multiple list */
+
+/* Literals */
+LitElem litValues[MAXPARAMS+1];
+int litCount;
+
+/* What did the user say? */
+int vrbwrd; /* The word he used */
+int vrbcode; /* The code for that verb */
+
+
+/*----------------------------------------------------------------------*\
+
+ SCAN DATA & PROCEDURES
+
+ All procedures for getting a command and turning it into a list of
+ dictionary entries are placed here.
+
+ buf
+ unknown()
+ lookup()
+ token
+ agetline()
+ scan()
+
+\*----------------------------------------------------------------------*/
+
+
+/* PRIVATE DATA */
+
+static char buf[LISTLEN+1]; /* The input buffer */
+static char isobuf[LISTLEN+1]; /* The input buffer in ISO */
+
+
+static Boolean eol = TRUE; /* Looking at End of line? Yes, initially */
+
+
+
+#ifdef _PROTOTYPES_
+static void unknown(
+ char token[]
+)
+#else
+static void unknown(token)
+ char token[];
+#endif
+{
+ char *str = (char *)allocate((int)strlen(token)+4);
+
+ str[0] = '\'';
+ strcpy(&str[1], token);
+ strcat(str, "'?");
+#if ISO == 0
+ fromIso(str, str);
+#endif
+ output(str);
+ free(str);
+ eol = TRUE;
+ error(M_UNKNOWN_WORD);
+}
+
+
+
+static char *token;
+
+
+#ifdef _PROTOTYPES_
+static int lookup(
+ char wrd[]
+)
+#else
+static int lookup(wrd)
+ char wrd[];
+#endif
+{
+ int i;
+
+ for (i = 0; !endOfTable(&dict[i]); i++) {
+ if (strcmp(wrd, (char *) addrTo(dict[i].wrd)) == 0)
+ return (i);
+ }
+ unknown(wrd);
+ return(EOF);
+}
+
+
+#ifdef _PROTOTYPES_
+static int number(
+ char token[] /* IN - The string to convert to a number */
+)
+#else
+static int number(token)
+ char token[]; /* IN - The string to convert to a number */
+#endif
+{
+ int i;
+
+ sscanf(token, "%d", &i);
+ return i;
+}
+
+#ifdef _PROTOTYPES_
+static char *gettoken(
+ char *buf
+)
+#else
+static char *gettoken(buf)
+ char *buf;
+#endif
+{
+ static char *marker;
+ static char oldch;
+
+ if (buf == NULL)
+ *marker = oldch;
+ else
+ marker = buf;
+ while (*marker != '\0' && isSpace(*marker) && *marker != '\n') marker++;
+ buf = marker;
+ if (isISOLetter(*marker))
+ while (*marker&&(isISOLetter(*marker)||isdigit(*marker)||*marker=='\'')) marker++;
+ else if (isdigit(*marker))
+ while (isdigit(*marker)) marker++;
+ else if (*marker == '\"') {
+ marker++;
+ while (*marker != '\"') marker++;
+ marker++;
+ } else if (*marker == '\0' || *marker == '\n')
+ return NULL;
+ else
+ marker++;
+ oldch = *marker;
+ *marker = '\0';
+ return buf;
+}
+
+
+#ifdef _PROTOTYPES_
+static void agetline(void)
+#else
+static void agetline()
+#endif
+{
+ para();
+ do {
+#if defined(HAVE_ANSI) || defined(GLK)
+ statusline();
+#endif
+ printf("> ");
+ if (logflg)
+ fprintf(logfil, "> ");
+#ifdef USE_READLINE
+ if (!readline(buf)) {
+ newline();
+ quit();
+ }
+#else
+ if (fgets(buf, LISTLEN, stdin) == NULL) {
+ newline();
+ quit();
+ }
+#endif
+ getPageSize();
+ anyOutput = FALSE;
+ if (logflg)
+#ifndef __amiga__
+ fprintf(logfil, "%s\n", buf);
+#else
+ fprintf(logfil, "%s", buf);
+#endif
+#if ISO == 0
+ toIso(isobuf, buf, NATIVECHARSET);
+#else
+ strcpy(isobuf, buf);
+#endif
+ token = gettoken(isobuf);
+ if (token != NULL && strcmp("debug", token) == 0 && header->debug) {
+ dbgflg = TRUE;
+ debug();
+ token = NULL;
+ }
+ } while (token == NULL);
+ eol = FALSE;
+ lin = 1;
+}
+
+
+#ifdef _PROTOTYPES_
+static void scan(void)
+#else
+static void scan()
+#endif
+{
+ int i;
+ int w;
+ char *str;
+
+ agetline();
+ wrds[0] = 0;
+ for (i = 0; i < litCount; i++)
+ if (litValues[i].type == TYPSTR && litValues[i].value != 0)
+ free((char *) litValues[i].value);
+ i = 0;
+ litCount = 0;
+ do {
+ if (isISOLetter(token[0])) {
+ (void) stringLower(token);
+ w = lookup(token);
+ if (!isNoise(w))
+ wrds[i++] = w;
+ } else if (isdigit(token[0])) {
+ if (litCount > MAXPARAMS)
+ syserr("Too many parameters.");
+ wrds[i++] = dictsize+litCount; /* Word outside dictionary = literal */
+ litValues[litCount].type = TYPNUM;
+ litValues[litCount++].value = number(token);
+ } else if (token[0] == '\"') {
+ if (litCount > MAXPARAMS)
+ syserr("Too many parameters.");
+ wrds[i++] = dictsize+litCount; /* Word outside dictionary = literal */
+ litValues[litCount].type = TYPSTR;
+ /* Remove the string quotes while copying */
+ str = strdup(&token[1]);
+ str[strlen(token)-2] = '\0';
+ litValues[litCount++].value = (Aptr) str;
+ } else if (token[0] == ',') {
+ wrds[i++] = conjWord;
+ } else
+ unknown(token);
+ wrds[i] = EOF;
+ eol = (token = gettoken(NULL)) == NULL;
+ } while (!eol);
+}
+
+
+
+/*----------------------------------------------------------------------*\
+
+ PARSE DATA & PROCEDURES
+
+ All procedures and data for getting a command and parsing it
+
+ nonverb() - search for a non-verb command
+ buildall() - build a list of objects matching 'all'
+ unambig() - match an unambigous object reference
+ simple() - match a simple verb command
+ complex() - match a complex -"-
+ tryMatch()- to match a verb command
+ match() - find the verb class (not used currently) and 'tryMatch()'
+
+\*---------------------------------------------------------------------- */
+
+static int allLength; /* No. of objects matching 'all' */
+
+
+#ifdef _PROTOTYPES_
+static void nonverb(void)
+#else
+static void nonverb()
+#endif
+{
+ if (isDir(wrds[wrdidx])) {
+ wrdidx++;
+ if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx]))
+ error(M_WHAT);
+ else
+ go(dict[wrds[wrdidx-1]].code);
+ if (wrds[wrdidx] != EOF)
+ wrdidx++;
+ } else
+ error(M_WHAT);
+}
+
+
+#ifdef _PROTOTYPES_
+static void buildall(
+ ParamElem list[]
+)
+#else
+static void buildall(list)
+ ParamElem list[];
+#endif
+{
+ int o, i = 0;
+ Boolean found = FALSE;
+
+ for (o = OBJMIN; o <= OBJMAX; o++)
+ if (isHere(o)) {
+ found = TRUE;
+ list[i].code = o;
+ list[i++].firstWord = EOF;
+ }
+ if (!found)
+ error(M_WHAT_ALL);
+ else
+ list[i].code = EOF;
+}
+
+
+#ifdef _PROTOTYPES_
+static void unambig(
+ ParamElem plst[]
+)
+#else
+static void unambig(plst)
+ ParamElem plst[];
+#endif
+{
+ int i;
+ Boolean found = FALSE; /* Adjective or noun found ? */
+ static ParamElem *refs; /* Entities referenced by word */
+ static ParamElem *savlst; /* Saved list for backup at EOF */
+ int firstWord, lastWord; /* The words the player used */
+
+ if (refs == NULL)
+ refs = (ParamElem *)allocate((MAXENTITY+1)*sizeof(ParamElem));
+
+ if (savlst == NULL)
+ savlst = (ParamElem *)allocate((MAXENTITY+1)*sizeof(ParamElem));
+
+ if (isLiteral(wrds[wrdidx])) {
+ /* Transform the word into a reference to the literal value */
+ plst[0].code = wrds[wrdidx++]-dictsize+LITMIN;
+ plst[0].firstWord = EOF; /* No words used! */
+ plst[1].code = EOF;
+ return;
+ }
+
+ plst[0].code = EOF; /* Make empty */
+ if (isIt(wrds[wrdidx])) {
+ wrdidx++;
+ /* Use last object in previous command! */
+ for (i = lstlen(pparams)-1; i >= 0 && (pparams[i].code == 0 || pparams[i].code >= LITMIN); i--);
+ if (i < 0)
+ error(M_WHAT_IT);
+ if (!isHere(pparams[i].code)) {
+ params[0].code = pparams[i].code;
+ params[0].firstWord = EOF;
+ params[1].code = EOF;
+ error(M_NO_SUCH);
+ }
+ plst[0] = pparams[i];
+ plst[0].firstWord = EOF; /* No words used! */
+ plst[1].code = EOF;
+ return;
+ }
+
+ firstWord = wrdidx;
+ while (wrds[wrdidx] != EOF && isAdj(wrds[wrdidx])) {
+ /* If this word can be a noun and there is no noun following break loop */
+ if (isNoun(wrds[wrdidx]) && (wrds[wrdidx+1] == EOF || !isNoun(wrds[wrdidx+1])))
+ break;
+ cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx]].adjrefs));
+ lstcpy(savlst, plst); /* To save it for backtracking */
+ if (found)
+ isect(plst, refs);
+ else {
+ lstcpy(plst, refs);
+ found = TRUE;
+ }
+ wrdidx++;
+ }
+ if (wrds[wrdidx] != EOF) {
+ if (isNoun(wrds[wrdidx])) {
+ cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx]].nounrefs));
+ if (found)
+ isect(plst, refs);
+ else {
+ lstcpy(plst, refs);
+ found = TRUE;
+ }
+ wrdidx++;
+ } else
+ error(M_NOUN);
+ } else if (found) {
+ if (isNoun(wrds[wrdidx-1])) {
+ /* Perhaps the last word was also a noun? */
+ lstcpy(plst, savlst); /* Restore to before last adjective */
+ cpyrefs(refs, (Aword *)addrTo(dict[wrds[wrdidx-1]].nounrefs));
+ if (plst[0].code == EOF)
+ lstcpy(plst, refs);
+ else
+ isect(plst, refs);
+ } else
+ error(M_NOUN);
+ }
+ lastWord = wrdidx-1;
+
+ /* Allow remote objects, but resolve ambiguities by presence */
+ if (lstlen(plst) > 1) {
+ for (i=0; plst[i].code != EOF; i++)
+ if (!isHere(plst[i].code))
+ plst[i].code = 0;
+ compact(plst);
+ }
+
+ if (lstlen(plst) > 1 || (found && lstlen(plst) == 0)) {
+ params[0].code = 0; /* Just make it anything != EOF */
+ params[0].firstWord = firstWord; /* Remember words for errors below */
+ params[0].lastWord = lastWord;
+ params[1].code = EOF; /* But be sure to terminate */
+ if (lstlen(plst) > 1)
+ error(M_WHICH_ONE);
+ else if (found && lstlen(plst) == 0)
+ error(M_NO_SUCH);
+ } else {
+ plst[0].firstWord = firstWord;
+ plst[0].lastWord = lastWord;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void simple(
+ ParamElem olst[]
+)
+#else
+static void simple(olst)
+ ParamElem olst[];
+#endif
+{
+ static ParamElem *tlst = NULL;
+ int savidx = wrdidx;
+ Boolean savplur = FALSE;
+ int i;
+
+ if (tlst == NULL)
+ tlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1));
+ tlst[0].code = EOF;
+
+ for (;;) {
+ if (isThem(wrds[wrdidx])) {
+ plural = TRUE;
+ for (i = 0; pmlst[i].code != EOF; i++)
+ if (!isHere(pmlst[i].code))
+ pmlst[i].code = 0;
+ compact(pmlst);
+ if (lstlen(pmlst) == 0)
+ error(M_WHAT_THEM);
+ lstcpy(olst, pmlst);
+ olst[0].firstWord = EOF; /* No words used */
+ wrdidx++;
+ } else {
+ unambig(olst); /* Look for unambigous noun phrase */
+ if (lstlen(olst) == 0) { /* Failed! */
+ lstcpy(olst, tlst);
+ wrdidx = savidx;
+ plural = savplur;
+ return;
+ }
+ }
+ mrglst(tlst, olst);
+ if (wrds[wrdidx] != EOF
+ && (isConj(wrds[wrdidx]) &&
+ (isAdj(wrds[wrdidx+1]) || isNoun(wrds[wrdidx+1])))) {
+ /* More parameters in a conjunction separated list ? */
+ savplur = plural;
+ savidx = wrdidx;
+ wrdidx++;
+ plural = TRUE;
+ } else {
+ lstcpy(olst, tlst);
+ return;
+ }
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ complex()
+
+ Above this procedure we can use the is* tests, but not below since
+ they work on words. Below all is converted to indices into the
+ entity tables. Particularly this goes for literals...
+
+*/
+#ifdef _PROTOTYPES_
+static void complex(
+ ParamElem olst[]
+)
+#else
+static void complex(olst)
+ ParamElem olst[];
+#endif
+{
+ static ParamElem *alst = NULL;
+
+ if (alst == NULL)
+ alst = (ParamElem *) allocate((MAXENTITY+1)*sizeof(ParamElem));
+
+ if (isAll(wrds[wrdidx])) {
+ plural = TRUE;
+ buildall(alst); /* Build list of all objects */
+ wrdidx++;
+ if (wrds[wrdidx] != EOF && isBut(wrds[wrdidx])) {
+ wrdidx++;
+ simple(olst);
+ if (lstlen(olst) == 0)
+ error(M_AFTER_BUT);
+ sublst(alst, olst);
+ if (lstlen(alst) == 0)
+ error(M_NOT_MUCH);
+ }
+ lstcpy(olst, alst);
+ allLength = lstlen(olst);
+ } else
+ simple(olst); /* Look for simple noun group */
+}
+
+
+#ifdef _PROTOTYPES_
+static Boolean claCheck(
+ ClaElem *cla /* IN - The cla elem to check */
+)
+#else
+static Boolean claCheck(cla)
+ ClaElem *cla; /* IN - The cla elem to check */
+#endif
+{
+ Boolean ok = FALSE;
+
+ if ((cla->classes&(Aword)CLA_OBJ) != 0)
+ ok = ok || isObj(params[cla->code-1].code);
+ if ((cla->classes&(Aword)CLA_CNT) != 0)
+ ok = ok || isCnt(params[cla->code-1].code);
+ if ((cla->classes&(Aword)CLA_ACT) != 0)
+ ok = ok || isAct(params[cla->code-1].code);
+ if ((cla->classes&(Aword)CLA_NUM) != 0)
+ ok = ok || isNum(params[cla->code-1].code);
+ if ((cla->classes&(Aword)CLA_STR) != 0)
+ ok = ok || isStr(params[cla->code-1].code);
+ if ((cla->classes&(Aword)CLA_COBJ) != 0)
+ ok = ok || (isCnt(params[cla->code-1].code) && isObj(params[cla->code-1].code));
+ if ((cla->classes&(Aword)CLA_CACT) != 0)
+ ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code));
+ return ok;
+}
+
+
+/*----------------------------------------------------------------------
+
+ resolve()
+
+ In case the syntax did not indicate omnipotent powers (allowed
+ access to remote object), we need to remove non-present parameters
+
+*/
+static void resolve(ParamElem plst[])
+{
+ int i;
+
+ if (allLength > 0) return; /* ALL has already done this */
+
+ /* Resolve ambiguities by presence */
+ for (i=0; plst[i].code != EOF; i++)
+ if (plst[i].code < LITMIN) /* Literals are always 'here' */
+ if (!isHere(plst[i].code)) {
+ params[0] = plst[i]; /* Copy error param as first one for message */
+ params[1].code = EOF; /* But be sure to terminate */
+ error(M_NO_SUCH);
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void tryMatch(
+ ParamElem mlst[] /* OUT - List of params allowed by multiple */
+)
+#else
+static void tryMatch(mlst)
+ ParamElem mlst[]; /* OUT - List of params allowed by multiple */
+#endif
+{
+ ElmElem *elms; /* Pointer to element list */
+ StxElem *stx; /* Pointer to syntax list */
+ ClaElem *cla; /* Pointer to class definitions */
+ Boolean anyPlural = FALSE; /* Any parameter that was plural? */
+ int i, p;
+ static ParamElem *tlst = NULL; /* List of params found by complex() */
+ static Boolean *checked = NULL; /* Corresponding parameter checked? */
+
+ if (tlst == NULL) {
+ tlst = (ParamElem *) allocate((MAXENTITY+1)*sizeof(ParamElem));
+ checked = (Boolean *) allocate((MAXENTITY+1)*sizeof(Boolean));
+ }
+
+ for (stx = stxs; !endOfTable(stx); stx++)
+ if (stx->code == vrbcode)
+ break;
+ if (endOfTable(stx))
+ error(M_WHAT);
+
+ elms = (ElmElem *) addrTo(stx->elms);
+
+ while (TRUE) {
+ /* End of input? */
+ if (wrds[wrdidx] == EOF || isConj(wrds[wrdidx])) {
+ while (!endOfTable(elms) && elms->code != EOS)
+ elms++;
+ if (endOfTable(elms))
+ error(M_WHAT);
+ else
+ break;
+ } else {
+ /* A preposition? */
+ if (isPrep(wrds[wrdidx])) {
+ while (!endOfTable(elms) && elms->code != dict[wrds[wrdidx]].code)
+ elms++;
+ if (endOfTable(elms))
+ error(M_WHAT);
+ else
+ wrdidx++;
+ } else {
+ /* Must be a parameter! */
+ while (!endOfTable(elms) && elms->code != 0)
+ elms++;
+ if (endOfTable(elms))
+ error(M_WHAT);
+ /* Get it! */
+ plural = FALSE;
+ complex(tlst);
+ if (lstlen(tlst) == 0) /* No object!? */
+ error(M_WHAT);
+ if ((elms->flags & OMNIBIT) == 0) /* Omnipotent parameter? */
+ /* If its not an omnipotent parameter, resolve by presence */
+ resolve(tlst);
+ if (plural) {
+ if ((elms->flags & MULTIPLEBIT) == 0) /* Allowed multiple? */
+ error(M_MULTIPLE);
+ else {
+ /*
+ Mark this as the multiple position in which to insert
+ actual parameter values later
+ */
+ params[paramidx++].code = 0;
+ lstcpy(mlst, tlst);
+ anyPlural = TRUE;
+ }
+ } else
+ params[paramidx++] = tlst[0];
+ params[paramidx].code = EOF;
+ }
+ elms = (ElmElem *) addrTo(elms->next);
+ }
+ }
+
+ /* Now perform class checks */
+ if (elms->next == 0) /* No verb code, verb not declared! */
+ error(M_CANT0);
+
+ for (p = 0; params[p].code != EOF; p++) /* Mark all parameters unchecked */
+ checked[p] = FALSE;
+ for (cla = (ClaElem *) addrTo(elms->next); !endOfTable(cla); cla++) {
+ if (params[cla->code-1].code == 0) {
+ /* This was a multiple parameter, so check all and remove failing */
+ for (i = 0; mlst[i].code != EOF; i++) {
+ params[cla->code-1] = mlst[i];
+ if (!claCheck(cla)) {
+ /* Multiple could be both an explicit list of params and an ALL */
+ if (allLength == 0) {
+ char marker[80];
+ /*
+ It wasn't ALL, we need to say something about it, so
+ prepare a printout with $1/2/3
+ */
+ sprintf(marker, "($%ld)", (unsigned long) cla->code);
+ output(marker);
+ interpret(cla->stms);
+ para();
+ }
+ mlst[i].code = 0; /* In any case remove it from the list */
+ }
+ }
+ params[cla->code-1].code = 0;
+ } else {
+ if (!claCheck(cla)) {
+ interpret(cla->stms);
+ error(MSGMAX); /* Return to player without saying anything */
+ }
+ }
+ checked[cla->code-1] = TRUE; /* Remember that it's already checked */
+ }
+ /* Now check the rest of the parameters, must be objects */
+ for (p = 0; params[p].code != EOF; p++)
+ if (!checked[p]) {
+ if (params[p].code == 0) {
+ /* This was a multiple parameter, check all and remove failing */
+ for (i = 0; mlst[i].code != EOF; i++)
+ if (mlst[i].code != 0) /* Skip any empty slots */
+ if (!isObj(mlst[i].code))
+ mlst[i].code = 0;
+ } else if (!isObj(params[p].code))
+ error(M_CANT0);
+ }
+
+ /* Set verb code */
+ cur.vrb = ((Aword *) cla)[1]; /* Take first word after end of table! */
+
+ /* Finally, if ALL was used, try to find out what was applicable */
+ if (allLength > 0) {
+ for (p = 0; params[p].code != 0; p++); /* Find multiple marker */
+ for (i = 0; i < allLength; i++) {
+ if (mlst[i].code != 0) { /* Already empty? */
+ params[p] = mlst[i];
+ if (!possible())
+ mlst[i].code = 0; /* Remove this from list */
+ }
+ }
+ params[p].code = 0; /* Restore multiple marker */
+ compact(mlst);
+ if (lstlen(mlst) == 0) {
+ params[0].code = EOF;
+ error(M_WHAT_ALL);
+ }
+ } else if (anyPlural) {
+ compact(mlst);
+ if (lstlen(mlst) == 0)
+ /* If there where multiple parameters but non left, exit without a */
+ /* word, assuming we have already said enough */
+ error(MSGMAX);
+ }
+ plural = anyPlural; /* Remember that we found plural objects */
+}
+
+
+#ifdef _PROTOTYPES_
+static void match(
+ ParamElem *mlst /* OUT - List of params allowed by multiple */
+)
+#else
+static void match(mlst)
+ ParamElem *mlst; /* OUT - List of params allowed by multiple */
+#endif
+{
+ tryMatch(mlst); /* ... to understand what he said */
+ if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx]))
+ error(M_WHAT);
+ if (wrds[wrdidx] != EOF) /* More on this line? */
+ wrdidx++; /* If so skip the AND */
+}
+
+
+#ifdef _PROTOTYPES_
+void parse(void)
+#else
+void parse()
+#endif
+{
+ if (mlst == NULL) { /* Allocate large enough paramlists */
+ mlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1));
+ mlst[0].code = EOF;
+ pmlst = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1));
+ params = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1));
+ params[0].code = EOF;
+ pparams = (ParamElem *) allocate(sizeof(ParamElem)*(MAXENTITY+1));
+ }
+
+ if (wrds[wrdidx] == EOF) {
+ wrdidx = 0;
+ scan();
+ } else if (anyOutput)
+ para();
+
+ allLength = 0;
+ paramidx = 0;
+ lstcpy(pparams, params);
+ params[0].code = EOF;
+ lstcpy(pmlst, mlst);
+ mlst[0].code = EOF;
+ if (isVerb(wrds[wrdidx])) {
+ vrbwrd = wrds[wrdidx];
+ vrbcode = dict[vrbwrd].code;
+ wrdidx++;
+ match(mlst);
+ action(mlst); /* mlst contains possible multiple params */
+ } else {
+ params[0].code = EOF;
+ pmlst[0].code = EOF;
+ nonverb();
+ }
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/parse.h b/engines/glk/alan2/parse.h
new file mode 100644
index 0000000000..067c73fb3b
--- /dev/null
+++ b/engines/glk/alan2/parse.h
@@ -0,0 +1,54 @@
+/* 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_ALAN2_PARSE
+#define GLK_ALAN2_PARSE
+
+/* Parse data for ALAN interpreter module. */
+
+namespace Glk {
+namespace Alan2 {
+
+extern int wrds[]; /* List of Parsed Word */
+extern int wrdidx; /* and an index into it */
+
+extern ParamElem *params; /* List of parameters */
+extern Boolean plural;
+
+extern LitElem litValues[];
+extern int litCount;
+
+extern int vrbwrd;
+
+#ifdef _PROTOTYPES_
+
+/* Parse a new player command */
+extern void parse(void);
+
+#else
+extern void parse();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/readline.cpp b/engines/glk/alan2/readline.cpp
new file mode 100644
index 0000000000..c96b26c13d
--- /dev/null
+++ b/engines/glk/alan2/readline.cpp
@@ -0,0 +1,560 @@
+/* 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/alan2/types.h"
+
+#ifdef GLK
+
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/readline.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/glkio.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/*======================================================================
+
+ readline()
+
+ Read a line from the user, with history and editing
+
+ */
+
+/* 4f - length of user buffer should be used */
+Boolean readline(char usrbuf[])
+{
+ event_t event;
+ g_vm->glk_request_line_event(glkMainWin, usrbuf, 255, 0);
+ /* FIXME: buffer size should be infallible: all existing calls use 256 or
+ 80 character buffers, except parse which uses LISTLEN (currently 100)
+ */
+ do
+ {
+ g_vm->glk_select(&event);
+ if (evtype_Arrange == event.type)
+ statusline();
+ } while (event.type != evtype_LineInput);
+ usrbuf[event.val1] = 0;
+ return TRUE;
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#else
+
+#include "glk/alan2/sysdep.h"
+
+#ifdef HAVE_TERMIO
+#include <termios.h>
+#endif
+
+#ifdef __PACIFIC__
+#include <unixio.h>
+#else
+//#include <unistd.h>
+#endif
+
+#include "glk/alan2/readline.h"
+
+#include "glk/alan2/main.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef HAVE_TERMIO
+/*----------------------------------------------------------------------*\
+
+ termio handling
+
+\*----------------------------------------------------------------------*/
+
+static struct termios term;
+
+static void newtermio()
+{
+ struct termios newterm;
+ tcgetattr(0, &term);
+ newterm=term;
+ newterm.c_lflag&=~(ECHO|ICANON);
+ newterm.c_cc[VMIN]=1;
+ newterm.c_cc[VTIME]=0;
+ tcsetattr(0, TCSANOW, &newterm);
+}
+
+static void restoretermio()
+{
+ tcsetattr(0, TCSANOW, &term);
+}
+
+#endif
+
+
+/*----------------------------------------------------------------------*\
+
+ Global character buffers etc.
+
+\*----------------------------------------------------------------------*/
+
+static unsigned char buffer[LINELENGTH+1];
+static int bufidx;
+
+static unsigned char *history[HISTORYLENGTH];
+static int histidx; /* Index where to store next history */
+static int histp; /* Points to the history recalled last */
+
+static unsigned char ch;
+static int endOfInput = 0;
+static Boolean change;
+static Boolean insert = TRUE;
+
+
+/*----------------------------------------------------------------------*\
+
+ Character map types and maps
+
+\*----------------------------------------------------------------------*/
+
+typedef struct {unsigned char min, max; void (*hook)(char ch);} KeyMap;
+
+/* Forward declaration of hooks */
+static void escHook(char ch);
+static void insertCh(char ch);
+static void arrowHook(char ch);
+static void upArrow(char ch);
+static void downArrow(char ch);
+static void rightArrow(char ch);
+static void leftArrow(char ch);
+static void insertToggle(char ch);
+static void newLine(char ch);
+static void delFwd(char ch);
+static void delBwd(char ch);
+
+#ifdef __XXunix__
+static KeyMap keymap[] = {
+ {0x00, 0x07, NULL},
+ {0x08, 0x08, delBwd},
+ {0x09, 0x09, NULL},
+ {0x0a, 0x0a, newLine},
+ {0x1b, 0x1b, escHook},
+ {0x1c, 0x7e, insertCh},
+ {0x7f, 0x7f, delFwd},
+ {0x80, 0xff, insertCh},
+ {0x00, 0x00, NULL}
+};
+
+/* I can't figure out what really coverns the esc-map characters... */
+#ifdef __solarisX__
+static KeyMap escmap[] = {
+ {0x00, 0x4e, NULL},
+ {0x4f, 0x4f, arrowHook},
+ {0x50, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+#else
+static KeyMap escmap[] = {
+ {0x00, 0x5a, NULL},
+ {0x5b, 0x5b, arrowHook},
+ {0x5c, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+#endif
+
+static KeyMap arrowmap[] = {
+ {0x00, 0x31, NULL},
+ {0x32, 0x32, insertToggle},
+ {0x33, 0x40, NULL},
+ {0x41, 0x41, upArrow},
+ {0x42, 0x42, downArrow},
+ {0x43, 0x43, rightArrow},
+ {0x44, 0x44, leftArrow},
+ {0x45, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+
+#endif
+
+#ifdef __win__
+static KeyMap keymap[] = {
+ {0x00, 0x01, NULL},
+ {0x02, 0x02, leftArrow},
+ {0x03, 0x05, NULL},
+ {0x06, 0x06, rightArrow},
+ {0x07, 0x07, NULL},
+ {0x08, 0x08, delBwd},
+ {0x09, 0x09, NULL},
+ {0x0a, 0x0a, newLine},
+ {0x1b, 0x1b, escHook},
+ {0x1c, 0x7e, insertCh},
+ {0x7f, 0x7f, delFwd},
+ {0x80, 0xff, insertCh},
+ {0x00, 0x00, NULL}
+};
+
+static KeyMap escmap[] = {
+ {0x00, 0x5a, NULL},
+ {0x5b, 0x5b, arrowHook},
+ {0x5c, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+
+static KeyMap arrowmap[] = {
+ {0x00, 0x31, NULL},
+ {0x32, 0x32, insertToggle},
+ {0x33, 0x40, NULL},
+ {0x41, 0x41, upArrow},
+ {0x42, 0x42, downArrow},
+ {0x43, 0x43, rightArrow},
+ {0x44, 0x44, leftArrow},
+ {0x45, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+
+#endif
+
+#ifdef __dos__
+static KeyMap keymap[] = {
+ {0x00, 0x01, NULL},
+ {0x02, 0x02, leftArrow},
+ {0x03, 0x05, NULL},
+ {0x06, 0x06, rightArrow},
+ {0x07, 0x07, NULL},
+ {0x08, 0x08, delBwd},
+ {0x09, 0x09, NULL},
+ {0x0a, 0x0a, newLine},
+ {0x1b, 0x1b, escHook},
+ {0x1c, 0x7e, insertCh},
+ {0x7f, 0x7f, delFwd},
+ {0x80, 0xff, insertCh},
+ {0x00, 0x00, NULL}
+};
+
+static KeyMap escmap[] = {
+ {0x00, 0x5a, NULL},
+ {0x5b, 0x5b, arrowHook},
+ {0x5c, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+
+static KeyMap arrowmap[] = {
+ {0x00, 0x31, NULL},
+ {0x32, 0x32, insertToggle},
+ {0x33, 0x40, NULL},
+ {0x41, 0x41, upArrow},
+ {0x42, 0x42, downArrow},
+ {0x43, 0x43, rightArrow},
+ {0x44, 0x44, leftArrow},
+ {0x45, 0xff, NULL},
+ {0x00, 0x00, NULL}
+};
+
+#endif
+
+
+static void doBeep(void)
+{
+ write(1, "\7", 1);
+}
+
+
+static void backspace(void)
+{
+ write(1, "\b", 1);
+}
+
+
+static void erase()
+{
+ int i;
+
+ for (i = 0; i < bufidx; i++) backspace(); /* Backup to beginning of text */
+ for (i = 0; i < strlen((char *)buffer); i++) write(1, " ", 1); /* Erase all text */
+ for (i = 0; i < strlen((char *)buffer); i++) backspace(); /* Backup to beginning of text */
+}
+
+/*----------------------------------------------------------------------*\
+
+ Character handling hook functions
+
+\*----------------------------------------------------------------------*/
+
+static void execute(KeyMap map[], unsigned char ch)
+{
+ int i = 0;
+
+ for (i = 0; i <= 256; i++) {
+ if (i > 0 && map[i].min == 0x00) break; /* End marker is a 0,0,NULL */
+ if (map[i].min <= ch && ch <= map[i].max) {
+ if (map[i].hook != NULL) {
+ map[i].hook(ch);
+ return;
+ } else
+ doBeep();
+ }
+ }
+ doBeep();
+}
+
+
+static void upArrow(char ch)
+{
+ /* Is there more history ? */
+ if (history[(histp+HISTORYLENGTH-1)%HISTORYLENGTH] == NULL ||
+ (histp+HISTORYLENGTH-1)%HISTORYLENGTH == histidx) {
+ write(1, "\7", 1);
+ return;
+ }
+
+ erase();
+
+ /* Backup history pointer */
+ histp = (histp+HISTORYLENGTH-1)%HISTORYLENGTH;
+
+ /* Copy the history and write it */
+ strcpy((char *)buffer, (char *)history[histp]);
+ bufidx = strlen((char *)buffer);
+ write(1, (void *)buffer, strlen((char *)buffer));
+
+}
+
+
+static void downArrow(char ch)
+{
+ /* Is there more history ? */
+ if (histp == histidx) {
+ write(1, "\7", 1);
+ return;
+ }
+
+ erase();
+
+ /* Advance history pointer */
+ histp = (histp+1)%HISTORYLENGTH;
+
+ /* If we are not at the most recent history entry, copy the history and write it */
+ if (histp != histidx) {
+ strcpy((char *)buffer, (char *)history[histp]);
+ bufidx = strlen((char *)buffer);
+ write(1, (void *)buffer, strlen((char *)buffer));
+ } else {
+ bufidx = 0;
+ buffer[0] = '\0';
+ }
+}
+
+
+static void rightArrow(char ch)
+{
+ if (bufidx > LINELENGTH || buffer[bufidx] == '\0')
+ doBeep();
+ else {
+ write(1, (void *)&buffer[bufidx], 1);
+ bufidx++;
+ }
+}
+
+
+static void leftArrow(char ch)
+{
+ if (bufidx == 0)
+ doBeep();
+ else {
+ bufidx--;
+ backspace();
+ }
+}
+
+
+static void insertToggle(char ch)
+{
+ read(0, &ch, 1);
+ if (ch != 'z')
+ doBeep();
+ else
+ insert = !insert;
+}
+
+
+static void delBwd(char ch)
+{
+ if (bufidx == 0)
+ doBeep();
+ else {
+ int i;
+
+ change = TRUE;
+ backspace();
+ bufidx--;
+ for (i = 0; i <= strlen((char *)&buffer[bufidx+1]); i++)
+ buffer[bufidx+i] = buffer[bufidx+1+i];
+ write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx]));
+ write(1, " ", 1);
+ for (i = 0; i <= strlen((char *)&buffer[bufidx]); i++) backspace();
+ }
+}
+
+static void delFwd(char ch)
+{
+ if (bufidx > LINELENGTH || buffer[bufidx] == '\0')
+ doBeep();
+ else {
+ int i;
+
+ change = TRUE;
+ strcpy((char *)&buffer[bufidx], (char *)&buffer[bufidx+1]);
+ write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx]));
+ write(1, " ", 1);
+ for (i = 0; i <= strlen((char *)&buffer[bufidx]); i++) backspace();
+ }
+}
+
+static void escHook(char ch) {
+ read(0, &ch, 1);
+ execute(escmap, ch);
+}
+
+static void arrowHook(char ch) {
+ read(0, &ch, 1);
+ execute(arrowmap, ch);
+}
+
+static void newLine(char ch)
+{
+ endOfInput = 1;
+ write(1, "\n", 1);
+
+ /* If the input is not the same as the previous, save it in the history */
+ if (change && strlen((char *)buffer) > 0) {
+ if (history[histidx] == NULL)
+ history[histidx] = (unsigned char *)allocate(LINELENGTH+1);
+ strcpy((char *)history[histidx], (char *)buffer);
+ histidx = (histidx+1)%HISTORYLENGTH;
+ }
+}
+
+
+static void insertCh(char ch) {
+ if (bufidx > LINELENGTH)
+ doBeep();
+ else {
+ /* If at end advance the NULL */
+ if (buffer[bufidx] == '\0')
+ buffer[bufidx+1] = '\0';
+ else if (insert) {
+ int i;
+
+ /* If insert mode is on, move the characters ahead */
+ for (i = strlen((char *)buffer); i >= bufidx; i--)
+ buffer[i+1] = buffer[i];
+ write(1, (void *)&buffer[bufidx], strlen((char *)&buffer[bufidx]));
+ for (i = strlen((char *)&buffer[bufidx]); i > 0; i--) backspace();
+ }
+ change = TRUE;
+ buffer[bufidx] = ch;
+ write(1, &ch, 1);
+ bufidx++;
+ }
+}
+
+
+/*----------------------------------------------------------------------
+
+ echoOff()
+
+ */
+static void echoOff()
+{
+#ifdef HAVE_TERMIO
+ newtermio();
+#else
+#ifdef __win__
+#include <windows.h>
+#include <winbase.h>
+#include <wincon.h>
+
+ DWORD handle = GetStdHandle(STD_INPUT_HANDLE);
+
+ (void) SetConsoleMode(handle, 0);
+
+#endif
+#endif
+}
+
+
+/*----------------------------------------------------------------------
+
+ echoOn()
+
+ */
+static void echoOn()
+{
+#ifdef HAVE_TERMIO
+ restoretermio();
+#else
+#ifdef __win__
+#include <windows.h>
+#include <winbase.h>
+#include <wincon.h>
+
+ DWORD handle = GetStdHandle(STD_INPUT_HANDLE);
+ (void) SetConsoleMode(handle, ENABLE_ECHO_INPUT);
+
+#endif
+#endif
+}
+
+
+/*======================================================================
+
+ readline()
+
+ Read a line from the user, with history and editing
+
+ */
+
+/* 4f - length of user buffer should be used */
+Boolean readline(char usrbuf[])
+{
+ fflush(stdout);
+ bufidx = 0;
+ histp = histidx;
+ buffer[0] = '\0';
+ change = TRUE;
+ echoOff();
+ endOfInput = 0;
+ while (!endOfInput) {
+ if (read(0, (void *)&ch, 1) != 1) {
+ echoOn();
+ return FALSE;
+ }
+ execute(keymap, ch);
+ }
+ echoOn();
+ strcpy(usrbuf, (char *)buffer);
+ return TRUE;
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/readline.h b/engines/glk/alan2/readline.h
new file mode 100644
index 0000000000..a50022415d
--- /dev/null
+++ b/engines/glk/alan2/readline.h
@@ -0,0 +1,46 @@
+/* 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_ALAN2_READLINE
+#define GLK_ALAN2_READLINE
+
+/* Header file for user input, history andediting support */
+
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#define LINELENGTH 80
+#define HISTORYLENGTH 20
+
+#ifdef _PROTOTYPES_
+extern Boolean readline(char usrbuf[]);
+
+#else
+extern Boolean readline();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/reverse.cpp b/engines/glk/alan2/reverse.cpp
new file mode 100644
index 0000000000..cf3e851226
--- /dev/null
+++ b/engines/glk/alan2/reverse.cpp
@@ -0,0 +1,552 @@
+/* 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/alan2/types.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/reverse.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/*----------------------------------------------------------------------
+
+ reversed()
+
+ Return the reversed bytes in the Aword
+
+*/
+#ifdef _PROTOTYPES_
+Aword reversed(Aword w) /* IN - The ACODE word to swap bytes of */
+#else
+Aword reversed(w)
+ Aword w; /* IN - The ACODE word to swap bytes of */
+#endif
+{
+ Aword s; /* The swapped ACODE word */
+ char *wp, *sp;
+ int i;
+
+ wp = (char *) &w;
+ sp = (char *) &s;
+
+ for (i = 0; i < sizeof(Aword); i++)
+ sp[sizeof(Aword)-1 - i] = wp[i];
+
+ return s;
+}
+
+
+#ifdef _PROTOTYPES_
+void reverse(Aword *w) /* IN - The ACODE word to reverse bytes in */
+#else
+void reverse(w)
+ Aword *w; /* IN - The ACODE word to reverse bytes in */
+#endif
+{
+ *w = reversed(*w);
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseTable(Aword adr, int len)
+#else
+static void reverseTable(adr, len)
+ Aword adr;
+ int len;
+#endif
+{
+ Aword *e = &memory[adr];
+ int i;
+
+ if (adr != 0)
+ while (!endOfTable(e)) {
+ for (i = 0; i < len/(int)sizeof(Aword); i++) {
+ reverse(e);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseStms(Aword adr)
+#else
+static void reverseStms(adr)
+ Aword adr;
+#endif
+{
+ Aword *e = &memory[adr];
+
+ if (adr != 0)
+ while (TRUE) {
+ reverse(e);
+ if (*e == ((Aword)C_STMOP<<28|(Aword)I_RETURN)) break;
+ e++;
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseMsgs(Aword adr)
+#else
+static void reverseMsgs(adr)
+ Aword adr;
+#endif
+{
+ MsgElem *e = (MsgElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(MsgElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->stms);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseWrds(Aword adr)
+#else
+static void reverseWrds(adr)
+ Aword adr;
+#endif
+{
+ WrdElem *e = (WrdElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(WrdElem));
+ while (!endOfTable(e)) {
+ if ((e->_class & (1L<<WRD_SYN)) == 0) { /* Do not do this for synonyms */
+ reverseTable(e->adjrefs, sizeof(Aword));
+ reverseTable(e->nounrefs, sizeof(Aword));
+ }
+ e++;
+ }
+ }
+}
+
+#ifdef _PROTOTYPES_
+static void reverseChks(Aword adr)
+#else
+static void reverseChks(adr)
+ Aword adr;
+#endif
+{
+ ChkElem *e = (ChkElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ChkElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->exp);
+ reverseStms(e->stms);
+ e++;
+ }
+ }
+}
+
+#ifdef _PROTOTYPES_
+static void reverseAlts(Aword adr)
+#else
+static void reverseAlts(adr)
+ Aword adr;
+#endif
+{
+ AltElem *e = (AltElem *)&memory[adr];
+
+ if (adr != 0 && !endOfTable(e) && !e->done) {
+ reverseTable(adr, sizeof(AltElem));
+ e->done = TRUE;
+ while (!endOfTable(e)) {
+ reverseChks(e->checks);
+ reverseStms(e->action);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseVrbs(Aword adr)
+#else
+static void reverseVrbs(adr)
+ Aword adr;
+#endif
+{
+ VrbElem *e = (VrbElem *)&memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(VrbElem));
+ while (!endOfTable(e)) {
+ reverseAlts(e->alts);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseSteps(Aword adr)
+#else
+static void reverseSteps(adr)
+ Aword adr;
+#endif
+{
+ StepElem *e = (StepElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(StepElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->exp);
+ reverseStms(e->stm);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseScrs(Aword adr)
+#else
+static void reverseScrs(adr)
+ Aword adr;
+#endif
+{
+ ScrElem *e = (ScrElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ScrElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->dscr);
+ reverseSteps(e->steps);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseActs(Aword adr)
+#else
+static void reverseActs(adr)
+ Aword adr;
+#endif
+{
+ ActElem *e = (ActElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ActElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->nam);
+ reverseTable(e->atrs, sizeof(AtrElem));
+ reverseScrs(e->scradr);
+ reverseVrbs(e->vrbs);
+ reverseStms(e->dscr);
+ e++;
+ }
+ }
+}
+
+#ifdef _PROTOTYPES_
+static void reverseObjs(Aword adr, Boolean v2_5)
+#else
+static void reverseObjs(adr, v2_5)
+ Aword adr;
+ Boolean v2_5; /* TRUE if it's a v2.5 format game */
+#endif
+{
+ ObjElem *e = (ObjElem *) &memory[adr];
+ ObjElem25 *e25 = (ObjElem25 *) &memory[adr];
+
+ if (v2_5) {
+ if (adr != 0 && !endOfTable(e25)) {
+ reverseTable(adr, sizeof(ObjElem25));
+ while (!endOfTable(e25)) {
+ reverseTable(e25->atrs, sizeof(AtrElem));
+ reverseVrbs(e25->vrbs);
+ reverseStms(e25->dscr1);
+ reverseStms(e25->dscr2);
+ e25++;
+ }
+ }
+ } else {
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ObjElem));
+ while (!endOfTable(e)) {
+ reverseTable(e->atrs, sizeof(AtrElem));
+ reverseVrbs(e->vrbs);
+ reverseStms(e->art);
+ reverseStms(e->dscr1);
+ reverseStms(e->dscr2);
+ e++;
+ }
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseExts(Aword adr)
+#else
+static void reverseExts(adr)
+ Aword adr;
+#endif
+{
+ ExtElem *e = (ExtElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ExtElem));
+ while (!endOfTable(e)) {
+ if (!e->done) {
+ reverseChks(e->checks);
+ reverseStms(e->action);
+ }
+ e++;
+ }
+ }
+}
+
+#ifdef _PROTOTYPES_
+static void reverseLocs(Aword adr)
+#else
+static void reverseLocs(adr)
+ Aword adr;
+#endif
+{
+ LocElem *e = (LocElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(LocElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->nams);
+ reverseStms(e->dscr);
+ reverseStms(e->does);
+ reverseTable(e->atrs, sizeof(AtrElem));
+ reverseExts(e->exts);
+ reverseVrbs(e->vrbs);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseClas(Aword adr)
+#else
+static void reverseClas(adr)
+ Aword adr;
+#endif
+{
+ ClaElem *e = (ClaElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ClaElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->stms);
+ e++;
+ }
+ }
+ if (adr)
+ reverse(&((Aword *)e)[1]); /* The verb code is stored after the table */
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseElms(Aword adr)
+#else
+static void reverseElms(adr)
+ Aword adr;
+#endif
+{
+ ElmElem *e = (ElmElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(ElmElem));
+ while (!endOfTable(e)) {
+ if (e->code == EOS) reverseClas(e->next);
+ else reverseElms(e->next);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseStxs(Aword adr)
+#else
+static void reverseStxs(adr)
+ Aword adr;
+#endif
+{
+ StxElem *e = (StxElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(StxElem));
+ while (!endOfTable(e)) {
+ reverseElms(e->elms);
+ e++;
+ }
+ }
+}
+
+#ifdef _PROTOTYPES_
+static void reverseEvts(Aword adr)
+#else
+static void reverseEvts(adr)
+ Aword adr;
+#endif
+{
+ EvtElem *e = (EvtElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(EvtElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->code);
+ e++;
+ }
+ }
+}
+
+
+
+#ifdef _PROTOTYPES_
+static void reverseLims(Aword adr)
+#else
+static void reverseLims(adr)
+ Aword adr;
+#endif
+{
+ LimElem *e = (LimElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(LimElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->stms);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseCnts(Aword adr)
+#else
+static void reverseCnts(adr)
+ Aword adr;
+#endif
+{
+ CntElem *e = (CntElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(CntElem));
+ while (!endOfTable(e)) {
+ reverseLims(e->lims);
+ reverseStms(e->header);
+ reverseStms(e->empty);
+ reverseStms(e->nam);
+ e++;
+ }
+ }
+}
+
+
+#ifdef _PROTOTYPES_
+static void reverseRuls(Aword adr)
+#else
+static void reverseRuls(adr)
+ Aword adr;
+#endif
+{
+ RulElem *e = (RulElem *) &memory[adr];
+
+ if (adr != 0 && !endOfTable(e)) {
+ reverseTable(adr, sizeof(RulElem));
+ while (!endOfTable(e)) {
+ reverseStms(e->exp);
+ reverseStms(e->stms);
+ e++;
+ }
+ }
+}
+
+
+
+/*----------------------------------------------------------------------
+
+ reverseHdr()
+
+ Reverse the header structure.
+
+*/
+#ifdef _PROTOTYPES_
+void reverseHdr(AcdHdr *hdr)
+#else
+void reverseHdr(hdr)
+ AcdHdr *hdr;
+#endif
+{
+ int i;
+
+ /* Reverse all words in the header except the first (version marking) */
+ for (i = 1; i < sizeof(AcdHdr)/sizeof(Aword); i++)
+ reverse(&((Aword *)hdr)[i]);
+}
+
+/*----------------------------------------------------------------------
+
+ reverseACD()
+
+ Traverse all the data structures and reverse all integers.
+ Only performed in architectures with reversed byte ordering, which
+ makes the .ACD files fully compatible across architectures
+
+ */
+#ifdef _PROTOTYPES_
+void reverseACD(Boolean v2_5)
+#else
+void reverseACD(v2_5)
+ Boolean v2_5;
+#endif
+{
+ reverseHdr(header);
+ reverseWrds(header->dict);
+ reverseTable(header->oatrs, sizeof(AtrElem));
+ reverseTable(header->latrs, sizeof(AtrElem));
+ reverseTable(header->aatrs, sizeof(AtrElem));
+ reverseActs(header->acts);
+ reverseObjs(header->objs, v2_5);
+ reverseLocs(header->locs);
+ reverseStxs(header->stxs);
+ reverseVrbs(header->vrbs);
+ reverseEvts(header->evts);
+ reverseCnts(header->cnts);
+ reverseRuls(header->ruls);
+ reverseTable(header->init, sizeof(IniElem));
+ reverseStms(header->start);
+ reverseMsgs(header->msgs);
+
+ reverseTable(header->scores, sizeof(Aword));
+ reverseTable(header->freq, sizeof(Aword));
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/reverse.h b/engines/glk/alan2/reverse.h
new file mode 100644
index 0000000000..40807ce403
--- /dev/null
+++ b/engines/glk/alan2/reverse.h
@@ -0,0 +1,46 @@
+/* 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_ALAN2_REVERSE
+#define GLK_ALAN2_REVERSE
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+
+extern void reverseHdr(AcdHdr *hdr);
+extern void reverseACD(Boolean v25);
+extern void reverse(Aword *word);
+extern Aword reversed(Aword word);
+
+#else
+extern void reverseHdr();
+extern void reverseACD();
+extern void reverse();
+extern Aword reversed();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/rules.cpp b/engines/glk/alan2/rules.cpp
new file mode 100644
index 0000000000..d00d1f3955
--- /dev/null
+++ b/engines/glk/alan2/rules.cpp
@@ -0,0 +1,83 @@
+/* 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/alan2/types.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/inter.h"
+#include "glk/alan2/debug.h"
+#include "glk/alan2/exe.h"
+#include "glk/alan2/stack.h"
+
+#include "glk/alan2/rules.h"
+
+#ifdef GLK
+#include "glk/alan2/glkio.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+void rules(void)
+#else
+void rules()
+#endif
+{
+ Boolean change = TRUE;
+ int i;
+
+ for (i = 1; !endOfTable(&ruls[i-1]); i++)
+ ruls[i-1].run = FALSE;
+
+ while (change) {
+ change = FALSE;
+ for (i = 1; !endOfTable(&ruls[i-1]); i++)
+ if (!ruls[i-1].run) {
+ if (trcflg) {
+ printf("\n<RULE %d (at ", i);
+ debugsay(cur.loc);
+ if (!stpflg)
+ printf("), Evaluating");
+ else
+ printf("), Evaluating:>\n");
+ }
+ interpret(ruls[i-1].exp);
+ if (pop()) {
+ change = TRUE;
+ ruls[i-1].run = TRUE;
+ if (trcflg)
+ if (!stpflg)
+ printf(", Executing:>\n");
+ else {
+ printf("\nRULE %d (at ", i);
+ debugsay(cur.loc);
+ printf("), Executing:>\n");
+ }
+ interpret(ruls[i-1].stms);
+ } else if (trcflg && !stpflg)
+ printf(":>\n");
+ }
+ }
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/rules.h b/engines/glk/alan2/rules.h
new file mode 100644
index 0000000000..1cc0b909e3
--- /dev/null
+++ b/engines/glk/alan2/rules.h
@@ -0,0 +1,44 @@
+/* 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_ALAN2_RULES
+#define GLK_ALAN2_RULES
+
+/* Header file for rules handler in Alan interpreter */
+
+namespace Glk {
+namespace Alan2 {
+
+/* TYPES */
+
+#ifdef _PROTOTYPES_
+
+extern void rules(void);
+
+#else
+extern void rules();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/stack.cpp b/engines/glk/alan2/stack.cpp
new file mode 100644
index 0000000000..ccce1475d1
--- /dev/null
+++ b/engines/glk/alan2/stack.cpp
@@ -0,0 +1,74 @@
+/* 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/alan2/types.h"
+#include "glk/alan2/main.h"
+#include "glk/alan2/stack.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/* PRIVATE DATA */
+
+#define STACKSIZE 100
+
+/* The AMACHINE STACK */
+static Aptr stack[STACKSIZE];
+static int stackp = 0;
+
+
+#ifdef _PROTOTYPES_
+void push(Aptr i)
+#else
+void push(i)
+ Aptr i;
+#endif
+{
+ if (stackp == STACKSIZE)
+ syserr("Out of stack space.");
+ stack[stackp++] = i;
+}
+
+
+#ifdef _PROTOTYPES_
+Aptr pop(void)
+#else
+Aptr pop()
+#endif
+{
+ if (stackp == 0)
+ syserr("Stack underflow.");
+ return(stack[--stackp]);
+}
+
+
+#ifdef _PROTOTYPES_
+Aptr top(void)
+#else
+Aptr top()
+#endif
+{
+ return(stack[stackp-1]);
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/stack.h b/engines/glk/alan2/stack.h
new file mode 100644
index 0000000000..7f10c080b6
--- /dev/null
+++ b/engines/glk/alan2/stack.h
@@ -0,0 +1,48 @@
+/* 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_ALAN2_STACK
+#define GLK_ALAN2_STACK
+
+/* Header file for stack handler in Alan interpreter */
+
+namespace Glk {
+namespace Alan2 {
+
+/* TYPES */
+
+#ifdef _PROTOTYPES_
+
+extern Aptr pop(void);
+extern void push(Aptr item);
+extern Aptr top(void);
+
+#else
+extern Aptr pop();
+extern void push();
+extern Aptr top();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/sysdep.cpp b/engines/glk/alan2/sysdep.cpp
new file mode 100644
index 0000000000..daa0417569
--- /dev/null
+++ b/engines/glk/alan2/sysdep.cpp
@@ -0,0 +1,493 @@
+/* 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 <string.h>
+#include "glk/alan2/sysdep.h"
+
+#ifdef GLK
+#include "glk/alan2/alan2.h"
+#endif
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+extern void syserr(char str[]);
+#endif
+
+#ifdef __vms__
+
+char *strdup(char str[]) /* IN - String to duplicate */
+{
+ char *new = (char *) malloc(strlen(str)+1);
+
+ if (!new)
+ syserr("Out of memory");
+ strcpy(new, str);
+ return new;
+}
+
+#endif
+
+
+#ifdef __mac__
+
+char *strdup(char str[]) /* IN - String to duplicate */
+{
+ char *new = (char *) malloc((size_t)((int)strlen(str)+1));
+
+ if (!new)
+ syserr("Out of memory");
+ strcpy(new, str);
+ return new;
+}
+
+#endif
+
+
+#ifdef __vms__
+
+/* Cheat implementation of strftime */
+size_t strftime (
+ char *outbuf,
+ size_t len,
+ const char *format,
+ const struct tm *t)
+{
+ char buf[100];
+ time_t ticks;
+
+ time(&ticks);
+ strcpy(buf, ctime(&ticks));
+ buf[strlen(buf)-1] = '\0';
+ strcpy(outbuf, &buf[4]);
+}
+
+#endif
+
+#ifdef __dos__
+#endif
+
+#ifdef GLK
+
+/* Note to Glk maintainers: 'native' characters are used for output, in this
+ case, Glk's Latin-1. ISO characters are Alan's internal representation,
+ stored in the .DAT file, and must be converted to native before printing.
+ Glk could just use the ISO routines directly, but its safer to maintain
+ its own tables to guard against future changes in either Alan or Glk (ie. a
+ move to Unicode).
+ */
+
+static char spcChrs[] =
+{
+ '\x0A', /* linefeed */
+ '\x20', /* space */
+ '\xA0', /* non-breaking space */
+ '\x00'
+};
+
+static char lowChrs[] =
+{
+ '\x61', /* a */ '\x62', /* b */ '\x63', /* c */ '\x64', /* d */
+ '\x65', /* e */ '\x66', /* f */ '\x67', /* g */ '\x68', /* h */
+ '\x69', /* i */ '\x6A', /* j */ '\x6B', /* k */ '\x6C', /* l */
+ '\x6D', /* m */ '\x6E', /* n */ '\x6F', /* o */ '\x70', /* p */
+ '\x71', /* q */ '\x72', /* r */ '\x73', /* s */ '\x74', /* t */
+ '\x75', /* u */ '\x76', /* v */ '\x77', /* w */ '\x78', /* x */
+ '\x79', /* y */ '\x7A', /* z */ '\xDF', /* ss <small sharp s> */
+ '\xE0', /* a grave */ '\xE1', /* a acute */
+ '\xE2', /* a circumflex */ '\xE3', /* a tilde */
+ '\xE4', /* a diaeresis */ '\xE5', /* a ring */
+ '\xE6', /* ae */ '\xE7', /* c cedilla */
+ '\xE8', /* e grave */ '\xE9', /* e acute */
+ '\xEA', /* e circumflex */ '\xEB', /* e diaeresis */
+ '\xEC', /* i grave */ '\xED', /* i acute */
+ '\xEE', /* i circumflex */ '\xEF', /* i diaeresis */
+ '\xF0', /* <small eth> */ '\xF1', /* n tilde */
+ '\xF2', /* o grave */ '\xF3', /* o acute */
+ '\xF4', /* o circumflex */ '\xF5', /* o tilde */
+ '\xF6', /* o diaeresis */ '\xF8', /* o slash */
+ '\xF9', /* u grave */ '\xFA', /* u acute */
+ '\xFB', /* u circumflex */ '\xFC', /* u diaeresis */
+ '\xFD', /* y acute */ '\xFE', /* <small thorn> */
+ '\xFF', /* y diaeresis */ '\x00'
+};
+
+/* FIXME: ss <small sharp s> and y diaeresis have no UC analogues
+ Are they really considered LC?
+ */
+
+static char uppChrs[] =
+{
+ '\x41', /* A */ '\x42', /* B */ '\x43', /* C */ '\x44', /* D */
+ '\x45', /* E */ '\x46', /* F */ '\x47', /* G */ '\x48', /* H */
+ '\x49', /* I */ '\x4A', /* J */ '\x4B', /* K */ '\x4C', /* L */
+ '\x4D', /* M */ '\x4E', /* N */ '\x4F', /* O */ '\x50', /* P */
+ '\x51', /* Q */ '\x52', /* R */ '\x53', /* S */ '\x54', /* T */
+ '\x55', /* U */ '\x56', /* V */ '\x57', /* W */ '\x58', /* X */
+ '\x59', /* Y */ '\x5A', /* Z */
+ '\xC0', /* A grave */ '\xC1', /* A acute */
+ '\xC2', /* A circumflex */ '\xC3', /* A tilde */
+ '\xC4', /* A diaeresis */ '\xC5', /* A ring */
+ '\xC6', /* AE */ '\xC7', /* C cedilla */
+ '\xC8', /* E grave */ '\xC9', /* E acute */
+ '\xCA', /* E circumflex */ '\xCB', /* E diaeresis */
+ '\xCC', /* I grave */ '\xCD', /* I acute */
+ '\xCE', /* I circumflex */ '\xCF', /* I diaeresis */
+ '\xD0', /* <capital eth> */ '\xD1', /* N tilde */
+ '\xD2', /* O grave */ '\xD3', /* O acute */
+ '\xD4', /* O circumflex */ '\xD5', /* O tilde */
+ '\xD6', /* O diaeresis */ '\xD8', /* O slash */
+ '\xD9', /* U grave */ '\xDA', /* U acute */
+ '\xDB', /* U circumflex */ '\xDC', /* U diaeresis */
+ '\xDD', /* Y acute */ '\xDE', /* <capital thorn> */
+ '\x00'
+};
+
+#else
+
+/* Theses work on native character sets */
+
+static char spcChrs[] = " \t\n";
+
+#ifdef __amiga__
+
+/* Which can't read 8-bit chars but is ISO */
+static char lowChrs[] = "abcdefghijklmnopqrstuvwxyz\340\341\342\343\344\345\346\347\351\352\353\354\355\356\357\360\361\362\363\364\365\366\370\371\372\373\374\375\376\377";
+
+static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337";
+
+#else
+
+/* Use native characters */
+static char lowChrs[] = "abcdefghijklmnopqrstuvwxyzàáâãäåæçéêëìíîïðñòóôõöøùúûüýþÿ";
+
+static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÛÝÞß";
+
+#endif
+#endif
+
+int isSpace(int c) /* IN - Native character to test */
+{
+ return (c != '\0' && strchr(spcChrs, c) != 0);
+}
+
+
+int isLower(int c) /* IN - Native character to test */
+{
+ return (c != '\0' && strchr(lowChrs, c) != 0);
+}
+
+
+int isUpper(int c) /* IN - Native character to test */
+{
+ return (c != '\0' && strchr(uppChrs, c) != 0);
+}
+
+int isLetter(int c) /* IN - Native character to test */
+{
+ return(c != '\0' && (isLower(c)? !0: isUpper(c)));
+}
+
+
+int toLower(int c) /* IN - Native character to convert */
+{
+#ifdef GLK
+ return g_vm->glk_char_to_lower(c);
+#else
+#ifdef __dos__
+ char *cp;
+
+ if ((cp = strchr(uppChrs, c)) != 0)
+ return(lowChrs[cp-uppChrs]);
+ else
+ return c;
+#else
+#ifdef __mac__
+ char *cp;
+
+ if ((cp = strchr(uppChrs, c)) != 0)
+ return(lowChrs[cp-uppChrs]);
+ else
+ return c;
+#else
+ return (isUpper(c)? c + ('a' - 'A'): c);
+#endif
+#endif
+#endif
+}
+
+int toUpper(int c) /* IN - Native character to convert */
+{
+#ifdef GLK
+ return g_vm->glk_char_to_upper(c);
+#else
+#ifdef __dos__
+ char *cp;
+
+ if ((cp = strchr(lowChrs, c)) != 0)
+ return(uppChrs[cp-lowChrs]);
+ else
+ return c;
+#else
+#ifdef __mac__
+ char *cp;
+
+ if ((cp = strchr(lowChrs, c)) != 0)
+ return(uppChrs[cp-lowChrs]);
+ else
+ return c;
+#else
+ return (isLower(c)? c - ('a' - 'A'): c);
+#endif
+#endif
+#endif
+}
+
+char *strlow(char str[]) /* INOUT - Native string to convert */
+{
+ char *s;
+
+ for (s = str; *s; s++)
+ *s = toLower(*s);
+ return(str);
+}
+
+
+char *strupp(char str[]) /* INOUT - Native string to convert */
+{
+ char *s;
+
+ for (s = str; *s; s++)
+ *s = toUpper(*s);
+ return(str);
+}
+
+
+/* The following work on ISO characters */
+
+int isLowerCase(int c) /* IN - ISO character to test */
+{
+ static char lowChrs[] = "abcdefghijklmnopqrstuvwxyz\340\341\342\343\344\345\346\347\351\352\353\354\355\356\357\360\361\362\363\364\365\366\370\371\372\373\374\375\376\377";
+ return (c != '\0' && strchr(lowChrs, c) != 0);
+}
+
+
+int isUpperCase(int c) /* IN - ISO character to test */
+{
+ static char uppChrs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337";
+ return (c != '\0' && strchr(uppChrs, c) != 0);
+}
+
+
+int isISOLetter(int c) /* IN - ISO character to test */
+{
+ return (isLowerCase(c) || isUpperCase(c));
+}
+
+
+char toLowerCase(int c) /* IN - ISO character to convert */
+{
+ return (isUpperCase(c)? c + ('a' - 'A'): c);
+}
+
+
+char toUpperCase(int c) /* IN - ISO character to convert */
+{
+ return (isLowerCase(c)? c - ('a' - 'A'): c);
+}
+
+
+char *stringLower(char str[]) /* INOUT - ISO string to convert */
+{
+ char *s;
+
+ for (s = str; *s; s++)
+ *s = toLowerCase(*s);
+ return(str);
+}
+
+
+char *stringUpper(char str[]) /* INOUT - ISO string to convert */
+{
+ char *s;
+
+ for (s = str; *s; s++)
+ *s = toUpperCase(*s);
+ return(str);
+}
+
+
+/*----------------------------------------------------------------------
+ toIso
+
+ Converts the incoming string to ISO character set. The original is
+ in the current character set which in the case of the compiler might
+ be other than the native.
+
+ */
+void toIso(char copy[], /* OUT - Mapped string */
+ char original[], /* IN - string to convert */
+ int charset) /* IN - the current character set */
+{
+static unsigned char macMap[256]
+= {
+0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0A,0x0E,0x0F,
+0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+0xC4,0xC5,0xC7,0xC9,0xD1,0xD6,0xDC,0xE1,0xE0,0xE2,0xE4,0xE3,0xE5,0xE7,0xE9,0xE8,
+0xEA,0xEB,0xED,0xEC,0xEE,0xEF,0xF1,0xF3,0xF2,0xF4,0xF6,0xF5,0xFA,0xF9,0xFB,0xFC,
+0xB9,0xB0,0xA2,0xA3,0xA7,0xB7,0xB6,0xDF,0xAE,0xA9,0xB2,0xB4,0xA8,0xD7,0xC6,0xD8,
+0xA4,0xB1,0xCD,0xCC,0xA5,0xB5,0xF0,0xCA,0xDE,0xFE,0xA6,0xAA,0xBA,0xD4,0xE6,0xF8,
+0xBF,0xA1,0xAC,0xCE,0xCF,0xC8,0xD0,0xAB,0xBB,0xCB,0xA0,0xC0,0xC3,0xD5,0xDD,0xFD,
+0xAD,0xAF,0xDA,0xD9,0xB8,0xB3,0xF7,0xC2,0xFF,0xBC,0xBD,0xBE,0xC1,0xD2,0xD3,0xDB,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F};
+
+static unsigned char dosMap[256]
+= {
+0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0A,0x0E,0x0F,
+0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+0xC7,0xFC,0xE9,0xE2,0xE4,0xE0,0xE5,0xE7,0xEA,0xEB,0xE8,0xEF,0xEE,0xEC,0xC4,0xC5,
+0xC9,0xE6,0xC6,0xF4,0xF6,0xF2,0xFB,0xF9,0xFF,0xD6,0xDC,0xA2,0xA3,0xA5,0xDE,0xA6,
+0xE1,0xED,0xF3,0xFA,0xF1,0xD1,0xAA,0xBA,0xBF,0xC0,0xC1,0xBD,0xBC,0xCF,0xAB,0xBB,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+0xA1,0xA7,0xAD,0xB3,0xB8,0xB9,0xC3,0xCE,0xD2,0xD3,0xDB,0xDD,0xE3,0xF5,0xF8,0xFD,
+0xA9,0xDF,0xC8,0xB6,0xCA,0xA4,0xB5,0xAE,0xD5,0xD0,0xD4,0xF0,0xD7,0xD8,0xCB,0xC2,
+0xBE,0xB1,0xD9,0xDA,0xCD,0xCC,0xF7,0xA8,0xB0,0xB7,0xAF,0xAC,0xFE,0xB2,0xB4,0xA0};
+ unsigned char *o, *c;
+
+ switch (charset) {
+ case 0: /* ISO */
+ if (copy != original)
+ (void)strcpy(copy, original);
+ break;
+ case 1: /* Mac */
+ for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++)
+ *c = macMap[*o];
+ *c = '\0';
+ break;
+
+ case 2: /* Dos */
+ for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++)
+ *c = dosMap[*o];
+ *c = '\0';
+ break;
+ }
+}
+
+/*----------------------------------------------------------------------
+
+ fromIso
+
+ Converts a string from global Iso format to native. Only used in
+ interpreter so character set is known at compile time.
+
+ */
+void fromIso(char copy[], /* OUT - Mapped string */
+ char original[]) /* IN - string to convert */
+{
+#if ISO == 0
+ static unsigned char map[256]
+#if defined __mac__
+ = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
+ 0xCA,0xC1,0xA2,0xA3,0xB0,0xB4,0xBA,0xA4,0xAC,0xA9,0xBB,0xC7,0xC2,0xD0,0xA8,0xD1,
+ 0xA1,0xB1,0xAA,0xD5,0xAB,0xB5,0xA6,0xA5,0xD4,0xA0,0xBC,0xC8,0xD9,0xDA,0xDB,0xC0,
+ 0xCB,0xDC,0xD7,0xCC,0x80,0x81,0xAE,0x82,0xC5,0x83,0xB7,0xC9,0xB3,0xB2,0xC3,0xC4,
+ 0xC6,0x84,0xDD,0xDE,0xBD,0xCD,0x85,0xAD,0xAF,0xD3,0xD2,0xDF,0x86,0xCE,0xB8,0xA7,
+ 0x88,0x87,0x89,0x8B,0x8A,0x8C,0xBE,0x8D,0x8F,0x8E,0x90,0x91,0x93,0x92,0x94,0x95,
+ 0xB6,0x96,0x98,0x97,0x99,0x9B,0x9A,0xD6,0xBF,0x9D,0x9C,0x9E,0x9F,0xCF,0xB9,0xD8}
+#else
+#if defined __dos__
+ = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xFF,0xD0,0x9B,0x9C,0xE5,0x9D,0x9F,0xD1,0xF7,0xE0,0xA6,0xAE,0xFB,0xD2,0xE7,0xFA,
+ 0xF8,0xF1,0xFD,0xD3,0xFE,0xE6,0xE3,0xF9,0xD4,0xD5,0xA7,0xAF,0xAC,0xAB,0xF0,0xA8,
+ 0xA9,0xAA,0xEF,0xD6,0x8E,0x8F,0x92,0x80,0xE2,0x90,0xE4,0xEE,0xF5,0xF4,0xD7,0xAD,
+ 0xE9,0xA5,0xD8,0xD9,0xEA,0xE8,0x99,0xEC,0xED,0xF2,0xF3,0xDA,0x9A,0xDB,0x9E,0xE1,
+ 0x85,0xA0,0x83,0xDC,0x84,0x86,0x91,0x87,0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
+ 0xEB,0xA4,0x95,0xA2,0x93,0xDD,0x94,0xF6,0xDE,0x97,0xA3,0x96,0x81,0xDF,0xFC,0x98}
+#endif
+ ;
+#endif
+ unsigned char *o, *c;
+
+ for (o = (unsigned char *)original, c = (unsigned char *)copy; *o; o++, c++)
+ *c = map[*o];
+ *c = '\0';
+#else
+ if (copy != original)
+ (void)strcpy(copy, original);
+#endif
+}
+
+
+/*----------------------------------------------------------------------
+ toNative
+
+ Converts the incoming string to the native character set from any of
+ the others. The original is in the current character set which in
+ the case of the compiler might be other than the native.
+
+ */
+void toNative(char copy[], /* OUT - Mapped string */
+ char original[], /* IN - string to convert */
+ int charset) /* IN - the current character set */
+{
+ toIso(copy, original, charset);
+ if (NATIVECHARSET != 0)
+ fromIso(copy, copy);
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/sysdep.h b/engines/glk/alan2/sysdep.h
new file mode 100644
index 0000000000..72769cb271
--- /dev/null
+++ b/engines/glk/alan2/sysdep.h
@@ -0,0 +1,409 @@
+/* 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_ALAN2_SYSDEP
+#define GLK_ALAN2_SYSDEP
+
+/* System dependencies file for Alan Adventure Language system
+ *
+ * N.B.The test for symbols used here should really be of three types
+ * - processor name(like PC, x86, ...)
+ * - os name(DOS, WIN32, Solaris2, ...)
+ * - compiler name andversion(DJGPP, CYGWIN, GCC271, THINK-C, ...)
+ *
+ * The set symbols should indicate if a feature is on or off like the GNU
+ * AUTOCONFIG package does.
+ *
+ * This is not completely done yet!
+ */
+
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#define GLK
+#define _PROTOTYPES_
+#define __win__
+
+#ifdef GLK
+#undef isdigit
+#define isdigit Common::isDigit
+#undef stricmp
+#define stricmp scumm_stricmp
+#undef strdup
+#define strdup scumm_strdup
+#undef rand
+#define rand() g_vm->getRandomNumber(0x7fffffff)
+#undef fprintf
+#define fprintf(FP, STR) FP->write(STR, strlen(STR) + 1)
+#endif
+
+/* Place definitions of OS and compiler here if necessary */
+#ifdef AZTEC_C
+#define __amiga__
+#endif
+
+#ifndef __sun__
+#ifdef sun
+#define __sun__
+#endif
+#endif
+
+#ifdef _INCLUDE_HPUX_SOURCE
+#define __hp__
+#endif
+
+#ifndef __unix__
+#ifdef unix
+#define __unix__
+#endif
+#endif
+
+#ifdef vax
+#define __vms__
+#endif
+
+#ifdef THINK_C
+#define __mac__
+#endif
+
+#ifdef __MWERKS__
+#ifdef macintosh
+#define __mac__
+#else
+#define __dos__
+#endif
+#endif
+
+#ifdef DOS
+#define __dos__
+#endif
+
+#ifdef __BORLANDC__
+#define __dos__
+#endif
+
+#ifdef __CYGWIN__
+#define __win__
+#endif
+
+#ifdef __MINGW32__
+#define __win__
+#endif
+
+#ifdef __PACIFIC__
+#define __dos__
+#define HAVE_SHORT_FILENAMES
+#endif
+
+
+/*----------------------------------------------------------------------
+
+ Below follows OS and compiler dependent settings. They should not be
+ changed except for introducing new sections when porting to new
+ environments.
+
+ */
+
+/************/
+/* Includes */
+/************/
+
+#ifndef GLK
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+#ifdef __STDC__
+#define _PROTOTYPES_
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#ifdef __vms__
+/* Our VAXC doesn't define __STDC__ */
+#define _PROTOTYPES_
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+
+#ifdef __mac__
+#define _PROTOTYPES_
+#include <stdlib.h>
+#include <string.h>
+#include <unix.h>
+#endif
+
+#ifdef __MWERKS__
+#define strdup _strdup
+#endif
+
+/***********************/
+/* ISO character sets? */
+/***********************/
+
+/* Common case first */
+#define ISO 1
+#define NATIVECHARSET 0
+
+#ifdef GLK
+#undef ISO
+#define ISO 1
+#undef NATIVECHARSET
+#define NATIVECHARSET 0
+#else /* Glk is ISO, no matter what the OS */
+
+#ifdef __dos__
+#undef ISO
+#define ISO 0
+#undef NATIVECHARSET
+#define NATIVECHARSET 2
+#endif
+
+#ifdef __win__
+#undef ISO
+#define ISO 1
+#undef NATIVECHARSET
+#define NATIVECHARSET 2
+#endif
+
+#ifdef __mac__
+#undef ISO
+#define ISO 0
+#undef NATIVECHARSET
+#define NATIVECHARSET 1
+#endif
+
+#endif
+
+/**************************/
+/* Strings for file modes */
+/**************************/
+#define READ_MODE "r"
+#define WRITE_MODE "w"
+
+#ifdef __mac__
+/* File open mode (binary) */
+#undef READ_MODE
+#define READ_MODE "rb"
+#undef WRITE_MODE
+#define WRITE_MODE "wb"
+#endif
+
+#ifdef __dos__
+/* File open mode (binary) */
+#undef READ_MODE
+#define READ_MODE "rb"
+#undef WRITE_MODE
+#define WRITE_MODE "wb"
+#endif
+
+#ifdef __win__
+/* File open mode (binary) */
+#undef READ_MODE
+#define READ_MODE "rb"
+#undef WRITE_MODE
+#define WRITE_MODE "wb"
+#endif
+
+/*****************/
+/* Byte ordering */
+/*****************/
+
+#ifdef __dos__
+#define REVERSED
+#endif
+
+#ifdef __vms__
+#define REVERSED
+#endif
+
+#ifdef __win__
+#ifndef REVERSED
+#define REVERSED
+#endif
+#endif
+
+
+/****************************/
+/* Allocates cleared bytes? */
+/****************************/
+
+#ifdef __CYGWIN__
+#define NOTCALLOC
+#endif
+
+#ifdef __MINGW32__
+#define NOTCALLOC
+#endif
+
+#ifdef __unix__
+#define NOTCALLOC
+#endif
+
+
+/****************/
+/* Have termio? */
+/****************/
+
+#ifdef GLK
+/* don't need TERMIO */
+#else
+
+#ifdef __CYGWIN__
+#define HAVE_TERMIO
+#endif
+
+#ifdef __unix__
+#define HAVE_TERMIO
+#endif
+
+#endif
+
+/*******************************/
+/* Is ANSI control available? */
+/*******************************/
+
+#ifdef GLK
+/* don't need ANSI */
+#else
+
+#ifdef __CYGWIN__
+#define HAVE_ANSI
+#endif
+
+#endif
+
+/******************************/
+/* Use the READLINE function? */
+/******************************/
+
+#ifdef GLK
+/* Glk always uses readline(), no matter what the OS */
+#define USE_READLINE
+#else
+
+#ifdef __unix__
+#define USE_READLINE
+#endif
+
+#ifdef x__dos__
+#define USE_READLINE
+#endif
+
+#ifdef __win__
+#define USE_READLINE
+#endif
+
+#endif
+
+/* Special cases and definition overrides */
+#ifdef __unix__
+#define MULTI
+#endif
+
+
+
+
+#ifdef __vms__
+
+#define MULTI
+
+extern char *strdup(char str[]);
+
+/* Cheat implementation of strftime */
+extern size_t strftime (char *, size_t, const char *, const struct tm *);
+
+#endif
+
+#ifdef __mac__
+
+extern char *strdup(char *str);
+
+#endif
+
+
+#ifdef __dos__
+
+/* Return codes */
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+#endif
+
+
+#ifdef _PROTOTYPES_
+
+/* Native character functions */
+extern int isSpace(int c); /* IN - Native character to test */
+extern int isLower(int c); /* IN - Native character to test */
+extern int isUpper(int c); /* IN - Native character to test */
+extern int isLetter(int c); /* IN - Native character to test */
+extern int toLower(int c); /* IN - Native character to convert */
+extern int toUpper(int c); /* IN - Native character to convert */
+extern char *strlow(char str[]); /* INOUT - Native string to convert */
+extern char *strupp(char str[]); /* INOUT - Native string to convert */
+
+/* ISO character functions */
+extern int isISOLetter(int c); /* IN - ISO character to test */
+extern char toLowerCase(int c); /* IN - ISO character to convert */
+extern char toUpperCase(int c); /* IN - ISO character to convert */
+extern char *stringLower(char str[]); /* INOUT - ISO string to convert */
+extern char *stringUpper(char str[]); /* INOUT - ISO string to convert */
+
+/* ISO string conversion functions */
+extern void toIso(char copy[], /* OUT - Mapped string */
+ char original[], /* IN - string to convert */
+ int charset); /* IN - The current character set */
+
+extern void fromIso(char copy[], /* OUT - Mapped string */
+ char original[]); /* IN - string to convert */
+
+extern void toNative(char copy[], /* OUT - Mapped string */
+ char original[], /* IN - string to convert */
+ int charset); /* IN - current character set */
+#else
+extern int isSpace();
+extern int isLower();
+extern int isUpper();
+extern int isLetter();
+extern int toLower();
+extern int toUpper();
+extern char *strlow();
+extern char *strupp();
+
+extern int isISOLetter();
+extern char toLowerCase();
+extern char toUpperCase();
+extern char *stringLower();
+extern char *stringUpper();
+
+extern void toIso();
+extern void fromIso();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/term.cpp b/engines/glk/alan2/term.cpp
new file mode 100644
index 0000000000..cf60fc5bbe
--- /dev/null
+++ b/engines/glk/alan2/term.cpp
@@ -0,0 +1,123 @@
+/* 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/alan2/main.h"
+#include "glk/alan2/term.h"
+
+namespace Glk {
+namespace Alan2 {
+
+/*======================================================================
+
+ getPageSize()
+
+ Try to get the current page size from the system, else use the ones
+ from the header.
+
+ */
+#ifdef _PROTOTYPES_
+void getPageSize(void)
+#else
+void getPageSize()
+#endif
+{
+#ifdef GLK
+ paglen = 0;
+ pagwidth = 0;
+
+#else
+#ifdef HAVE_TERMIO
+
+#include <sys/termios.h>
+
+ extern int ioctl();
+
+ struct winsize win;
+ int ecode;
+
+ ecode = ioctl(1, TIOCGWINSZ, &win);
+
+ if (ecode != 0 || win.ws_row == 0)
+ paglen = header->paglen;
+ else
+ paglen = win.ws_row;
+
+ if (ecode != 0 || win.ws_col == 0)
+ pagwidth = header->pagwidth;
+ else
+ pagwidth = win.ws_col;
+
+#else
+#ifdef __amiga__
+#include <libraries/dosextens.h>
+#include <intuition/intuition.h>
+#include <graphics/text.h>
+#include <clib/exec_protos.h>
+
+ struct Process * proc;
+ struct InfoData *id;
+ struct Window *win;
+ struct TextFont *textFont;
+ struct StandardPacket *packet;
+
+ proc = (struct Process *) FindTask(0L);
+
+ id = (struct InfoData *) allocate(sizeof(struct InfoData));
+
+ if (proc->pr_ConsoleTask) {
+ packet = (struct StandardPacket *) allocate(sizeof(struct StandardPacket));
+ packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
+ packet->sp_Pkt.dp_Link = & packet->sp_Msg;
+ packet->sp_Pkt.dp_Port = & proc->pr_MsgPort;
+ packet->sp_Pkt.dp_Type = ACTION_DISK_INFO;
+
+ packet->sp_Pkt.dp_Arg1 = ((LONG) id) >> 2;
+
+ PutMsg ((struct MsgPort *) proc->pr_ConsoleTask, & packet->sp_Msg);
+ WaitPort(&proc->pr_MsgPort);
+ GetMsg(&proc->pr_MsgPort);
+ free((char *)packet);
+
+ win = (struct Window *) id->id_VolumeNode;
+ free(id);
+
+ /* Calculate number of characters and lines w.r.t font size and borders */
+ textFont = win->IFont;
+ paglen = win->Height/textFont->tf_YSize-2;
+ pagwidth = win->Width/textFont->tf_XSize-3;
+ } else {
+ paglen = header->paglen;
+ pagwidth = header->pagwidth;
+ }
+
+#else
+
+ paglen = header->paglen;
+ pagwidth = header->pagwidth;
+
+#endif
+#endif
+#endif
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/term.h b/engines/glk/alan2/term.h
new file mode 100644
index 0000000000..339a3b5e82
--- /dev/null
+++ b/engines/glk/alan2/term.h
@@ -0,0 +1,42 @@
+/* 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_ALAN2_TERM
+#define GLK_ALAN2_TERM
+
+/* Header file for terminal functions in ARUN, the Alan interpreter */
+
+namespace Glk {
+namespace Alan2 {
+
+#ifdef _PROTOTYPES_
+
+extern void getPageSize(void);
+
+#else
+extern void getPageSize();
+#endif
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/types.h b/engines/glk/alan2/types.h
index 7da9e1dc58..2de31c06bf 100644
--- a/engines/glk/alan2/types.h
+++ b/engines/glk/alan2/types.h
@@ -23,248 +23,261 @@
#ifndef GLK_ALAN2_TYPES
#define GLK_ALAN2_TYPES
+#include "glk/alan2/sysdep.h"
#include "glk/alan2/acode.h"
namespace Glk {
namespace Alan2 {
-// CONSTANTS
-
-#define ACTMIN (_vm->header->actmin)
-#define ACTMAX (_vm->header->actmax)
-#define OBJMIN (_vm->header->objmin)
-#define OBJMAX (_vm->header->objmax)
-#define LOCMIN (_vm->header->locmin)
-#define LOCMAX (_vm->header->locmax)
-#define CNTMIN (_vm->header->cntmin)
-#define CNTMAX (_vm->header->cntmax)
-#define LITMIN (_vm->header->locmax + 1)
-#define LITMAX (_vm->header->locmax + 1 + litCount)
-#define EVTMIN (_vm->header->evtmin)
-#define EVTMAX (_vm->header->evtmax)
+/* CONSTANTS */
+
+#ifndef __mac__
+#ifndef TRUE
+#define TRUE (0==0)
+#endif
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif
+#endif
+
+#define ACTMIN (header->actmin)
+#define ACTMAX (header->actmax)
+#define OBJMIN (header->objmin)
+#define OBJMAX (header->objmax)
+#define LOCMIN (header->locmin)
+#define LOCMAX (header->locmax)
+#define CNTMIN (header->cntmin)
+#define CNTMAX (header->cntmax)
+#define LITMIN (header->locmax+1)
+#define LITMAX (header->locmax+1+litCount)
+#define EVTMIN (header->evtmin)
+#define EVTMAX (header->evtmax)
#define HERO ACTMIN
-#define addrTo(x) (&_vm->memory[x])
-
-// The word classes are represented as numbers but in the dictonary they are generated as bits
-#define isVerb(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_VRB))!=0)
-#define isConj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_CONJ))!=0)
-#define isBut(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_BUT))!=0)
-#define isThem(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_THEM))!=0)
-#define isIt(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_IT))!=0)
-#define isNoun(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOUN))!=0)
-#define isAdj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ADJ))!=0)
-#define isPrep(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_PREP))!=0)
-#define isAll(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ALL))!=0)
-#define isDir(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_DIR))!=0)
-#define isNoise(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOISE))!=0)
+#define addrTo(x) (&memory[x])
+
+/* The word classes are represented as numbers but in the dictonary they are generated as bits */
+#define isVerb(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_VRB))!=0)
+#define isConj(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_CONJ))!=0)
+#define isBut(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_BUT))!=0)
+#define isThem(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_THEM))!=0)
+#define isIt(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_IT))!=0)
+#define isNoun(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOUN))!=0)
+#define isAdj(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ADJ))!=0)
+#define isPrep(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_PREP))!=0)
+#define isAll(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_ALL))!=0)
+#define isDir(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_DIR))!=0)
+#define isNoise(word) (word < dictsize && (dict[word]._class&((Aword)1L<<WRD_NOISE))!=0)
#define isLiteral(word) (word >= dictsize)
-// TYPES
-
-// Amachine variables
-struct CurVars {
- int vrb;
- int obj;
- int loc;
- int act;
- int tick;
- int score;
- int visits;
-};
-
-// The various tables
-struct WrdElem { // Dictionary
- Aaddr wrd; // ACODE address to string
- Aword wordClass; // Word class
- Aword code;
- Aaddr adjrefs; // Address to reference list
- Aaddr nounrefs; // Address to reference list
-};
-
-struct ActElem { // ACTOR TABLE
- Aword loc; // Location
- Abool describe; // Description flag
- Aaddr nam; // Address to name printing code
- Aaddr atrs; // Address to attribute list
- Aword cont; // Code for the container props if any
- Aword script; // Which script is he using
- Aaddr scradr; // Address to script table
- Aword step;
- Aword count;
- Aaddr vrbs;
- Aaddr dscr; // Address of description code
-};
-
-struct ScrElem { // SCRIPT TABLE
- Aword code; // Script number
- Aaddr dscr; // Optional description statements
- Aaddr steps; // Address to steps
-};
-
-struct StepElem { // STEP TABLE
- Aword after; // After how many ticks?
- Aaddr exp; // Address to expression saying when
- Aaddr stm; // Address to the actual code
-};
-
-struct LocElem { // LOCATION TABLE
- Aaddr nams; // Address of name printing code
- Aaddr dscr; // Address of description code
- Aaddr does; // Address of does code
- Aword describe; // Description flag & counter
- Aaddr atrs; // Address of attribute list
- Aaddr exts; // Address of exit list
- Aaddr vrbs; // Address of local verb list
-};
-
-struct ExtElem { // EXIT TABLE structure
- Abool done; // Flag for reverse/convert process
- Aword code; // Direction code
- Aaddr checks; // Address of check table
- Aaddr action; // Address of action code
- Aword next; // Number of next location
-};
-
-struct ChkElem { // CHECK TABLE
- Aaddr exp; // ACODE address to expression code
- Aaddr stms; // ACODE address to statement code
-};
-
-struct VrbElem { // VERB TABLE
- Aword code; // Code for the verb
- Aaddr alts; // Address to alternatives
-};
-
-struct StxElem { // SYNTAX TABLE
- Aword code; // Code for verb word
- Aaddr elms; // Address to element tables
-};
-
-struct ElmElem26 { // ELEMENT TABLES
- Aword code; // Code for this element, 0 -> parameter
- Abool multiple; // May be multiple (if parameter)
- Aaddr next; // Address to next element table ...
- // ... or class check if EOS
-};
-
-struct ElmElem { // ELEMENT TABLES
- Aword code; // Code for this element, 0 -> parameter
- Aword flags; // Flags for multiple/omni (if parameter)
- // CHANGED: v2.7 from Abool for multiple
- Aaddr next; // Address to next element table ...
- // ... or class check if EOS
-};
-
-struct ClaElem { // CLASS DEFINITION TABLE
- Aword code; // Parameter number
- Aword classes; // Parameter classes
- Aaddr stms; // Exception statements
-};
-
-struct AltElem { // VERB ALTERNATIVE TABLE
- Abool done; // Flag for patching (reverse/convert) process
- Aword param; // Parameter number
- Aword qual; // Verb execution qualifier
- Aaddr checks; // Address of the check table
- Aaddr action; // Address of the action code
-};
-
-struct AtrElem { // ATTRIBUTE LIST
- Aword val; // Its value
- Aaddr stradr; // Address to the name
-};
-
-struct ObjElem25 { // OBJECT TABLE of 2.5 format
- Aword loc; // Current location
- Abool describe; // Describe flag
- Aaddr atrs; // Address of attribute list
- Aword cont; // Index to container properties if any
- Aaddr vrbs; // Address to local verb table
- Aaddr dscr1; // Address to Aword description code
- Aaddr dscr2; // Address to short description code
-};
-
-struct ObjElem { // OBJECT TABLE
- Aword loc; // Current location
- Abool describe; // Describe flag
- Aaddr atrs; // Address of attribute list
- Aword cont; // Index to container properties if any
- Aaddr vrbs; // Address to local verb table
- Aaddr dscr1; // Address to Aword description code
- Aaddr art; // Article printing code? Else use default
- // INTRODUCED: v2.6
- Aaddr dscr2; // Address to short description code
-};
-
-struct CntElem { // CONTAINER TABLE
- Aaddr lims; // Address to limit check code
- Aaddr header; // Address to header code
- Aaddr empty; // Address to empty code
- Aword parent; // Object or actor index
- Aaddr nam; // Address to statement printing name
-};
-
-struct LimElem { // LIMIT Type
- Aword atr; // Attribute that limits
- Aword val; // And the limiting value
- Aaddr stms; // Statements if fail
-};
-
-struct RulElem { // RULE TABLE
- Abool run; // Is rule already run?
- Aaddr exp; // Address to expression code
- Aaddr stms; // Address to run
-};
-
-struct EvtElem { // EVENT TABLE
- Aaddr stradr; // Address to name string
- Aaddr code; // Address of code to run
-};
-
-struct EvtqElem { // EVENT QUEUE ELEMENT
- int time;
- int event;
- int where;
-};
-
-struct IniElem { // STRING INITIALISATION TABLE
- Aword fpos; // File position
- Aword len; // Length
- Aword adr; // Where to store the string
-};
-
-struct MsgElem26 { // MESSAGE TABLE
- Aword fpos; // File position
- Aword len; // Length of message
-};
-
-struct MsgElem { // MESSAGE TABLE
- Aaddr stms; // Address to statements
- // Changed v2.7 from fpos+len in .dat
-};
-
-struct ParamElem { // PARAMETER
- Aword code; // Code for this parameter (0=multiple)
- Aword firstWord; // Index to first word used by player
- Aword lastWord; // d:o to last
-};
-
-enum Type {
- TYPNUM,
- TYPSTR
-};
-
-struct LitElem { // LITERAL
- Type type;
- Aptr value;
-};
+/* TYPES */
+
+#ifndef __mac__
+typedef int Boolean; /* Boolean values within interpreter */
+#endif
+
+/* Amachine variables */
+typedef struct CurVars {
+ int
+ vrb,
+ obj,
+ loc,
+ act,
+ tick,
+ score,
+ visits;
+} CurVars;
+
+/* The various tables */
+typedef struct WrdElem { /* Dictionary */
+ Aaddr wrd; /* ACODE address to string */
+ Aword _class; /* Word class */
+ Aword code;
+ Aaddr adjrefs; /* Address to reference list */
+ Aaddr nounrefs; /* Address to reference list */
+} WrdElem;
+
+typedef struct ActElem { /* ACTOR TABLE */
+ Aword loc; /* Location */
+ Abool describe; /* Description flag */
+ Aaddr nam; /* Address to name printing code */
+ Aaddr atrs; /* Address to attribute list */
+ Aword cont; /* Code for the container props if any */
+ Aword script; /* Which script is he using */
+ Aaddr scradr; /* Address to script table */
+ Aword step;
+ Aword count;
+ Aaddr vrbs;
+ Aaddr dscr; /* Address of description code */
+} ActElem;
+
+typedef struct ScrElem { /* SCRIPT TABLE */
+ Aword code; /* Script number */
+ Aaddr dscr; /* Optional description statements */
+ Aaddr steps; /* Address to steps */
+} ScrElem;
+
+typedef struct StepElem { /* STEP TABLE */
+ Aword after; /* After how many ticks? */
+ Aaddr exp; /* Address to expression saying when */
+ Aaddr stm; /* Address to the actual code */
+} StepElem;
+
+typedef struct LocElem { /* LOCATION TABLE */
+ Aaddr nams; /* Address of name printing code */
+ Aaddr dscr; /* Address of description code */
+ Aaddr does; /* Address of does code */
+ Aword describe; /* Description flag & counter */
+ Aaddr atrs; /* Address of attribute list */
+ Aaddr exts; /* Address of exit list */
+ Aaddr vrbs; /* Address of local verb list */
+} LocElem;
+
+typedef struct ExtElem { /* EXIT TABLE structure */
+ Abool done; /* Flag for reverse/convert process */
+ Aword code; /* Direction code */
+ Aaddr checks; /* Address of check table */
+ Aaddr action; /* Address of action code */
+ Aword next; /* Number of next location */
+} ExtElem;
+
+typedef struct ChkElem { /* CHECK TABLE */
+ Aaddr exp; /* ACODE address to expression code */
+ Aaddr stms; /* ACODE address to statement code */
+} ChkElem;
+
+typedef struct VrbElem { /* VERB TABLE */
+ Aword code; /* Code for the verb */
+ Aaddr alts; /* Address to alternatives */
+} VrbElem;
+
+typedef struct StxElem { /* SYNTAX TABLE */
+ Aword code; /* Code for verb word */
+ Aaddr elms; /* Address to element tables */
+} StxElem;
+
+typedef struct ElmElem26 { /* ELEMENT TABLES */
+ Aword code; /* Code for this element, 0 -> parameter */
+ Abool multiple; /* May be multiple (if parameter) */
+ Aaddr next; /* Address to next element table ... */
+ /* ... or class check if EOS */
+} ElmElem26;
+
+typedef struct ElmElem { /* ELEMENT TABLES */
+ Aword code; /* Code for this element, 0 -> parameter */
+ Aword flags; /* Flags for multiple/omni (if parameter) */
+ /* CHANGED: v2.7 from Abool for multiple */
+ Aaddr next; /* Address to next element table ... */
+ /* ... or class check if EOS */
+} ElmElem;
+
+typedef struct ClaElem { /* CLASS DEFINITION TABLE */
+ Aword code; /* Parameter number */
+ Aword classes; /* Parameter classes */
+ Aaddr stms; /* Exception statements */
+} ClaElem;
+
+typedef struct AltElem { /* VERB ALTERNATIVE TABLE */
+ Abool done; /* Flag for patching (reverse/convert) process */
+ Aword param; /* Parameter number */
+ Aword qual; /* Verb execution qualifier */
+ Aaddr checks; /* Address of the check table */
+ Aaddr action; /* Address of the action code */
+} AltElem;
+
+typedef struct AtrElem { /* ATTRIBUTE LIST */
+ Aword val; /* Its value */
+ Aaddr stradr; /* Address to the name */
+} AtrElem;
+
+typedef struct ObjElem25 { /* OBJECT TABLE of 2.5 format*/
+ Aword loc; /* Current location */
+ Abool describe; /* Describe flag */
+ Aaddr atrs; /* Address of attribute list */
+ Aword cont; /* Index to container properties if any */
+ Aaddr vrbs; /* Address to local verb table */
+ Aaddr dscr1; /* Address to Aword description code */
+ Aaddr dscr2; /* Address to short description code */
+} ObjElem25;
+
+typedef struct ObjElem { /* OBJECT TABLE */
+ Aword loc; /* Current location */
+ Abool describe; /* Describe flag */
+ Aaddr atrs; /* Address of attribute list */
+ Aword cont; /* Index to container properties if any */
+ Aaddr vrbs; /* Address to local verb table */
+ Aaddr dscr1; /* Address to Aword description code */
+ Aaddr art; /* Article printing code? Else use default */
+ /* INTRODUCED: v2.6 */
+ Aaddr dscr2; /* Address to short description code */
+} ObjElem;
+
+typedef struct CntElem { /* CONTAINER TABLE */
+ Aaddr lims; /* Address to limit check code */
+ Aaddr header; /* Address to header code */
+ Aaddr empty; /* Address to empty code */
+ Aword parent; /* Object or actor index */
+ Aaddr nam; /* Address to statement printing name */
+} CntElem;
+
+typedef struct LimElem { /* LIMIT Type */
+ Aword atr; /* Attribute that limits */
+ Aword val; /* And the limiting value */
+ Aaddr stms; /* Statements if fail */
+} LimElem;
+
+typedef struct RulElem { /* RULE TABLE */
+ Abool run; /* Is rule already run? */
+ Aaddr exp; /* Address to expression code */
+ Aaddr stms; /* Address to run */
+} RulElem;
+
+typedef struct EvtElem { /* EVENT TABLE */
+ Aaddr stradr; /* Address to name string */
+ Aaddr code; /* Address of code to run */
+} EvtElem;
+
+typedef struct EvtqElem { /* EVENT QUEUE ELEMENT */
+ int time;
+ int event;
+ int where;
+} EvtqElem;
+
+typedef struct IniElem { /* STRING INITIALISATION TABLE */
+ Aword fpos; /* File position */
+ Aword len; /* Length */
+ Aword adr; /* Where to store the string */
+} IniElem;
+
+typedef struct MsgElem26 { /* MESSAGE TABLE */
+ Aword fpos; /* File position */
+ Aword len; /* Length of message */
+} MsgElem26;
+
+typedef struct MsgElem { /* MESSAGE TABLE */
+ Aaddr stms; /* Address to statements*/
+ /* Changed v2.7 from fpos+len in .dat */
+} MsgElem;
+
+
+typedef struct ParamElem { /* PARAMETER */
+ Aword code; /* Code for this parameter (0=multiple) */
+ Aword firstWord; /* Index to first word used by player */
+ Aword lastWord; /* d:o to last */
+} ParamElem;
+
+typedef enum Type {TYPNUM, TYPSTR} Type;
+
+typedef struct LitElem { /* LITERAL */
+ Type type;
+ Aptr value;
+} LitElem;
#define MAXPARAMS 9
-#define MAXENTITY (_vm->header->actmax)
+#define MAXENTITY (header->actmax)
} // End of namespace Alan2
} // End of namespace Glk
diff --git a/engines/glk/alan2/util.h b/engines/glk/alan2/util.h
index 5ea14106bd..21993eb80d 100644
--- a/engines/glk/alan2/util.h
+++ b/engines/glk/alan2/util.h
@@ -23,65 +23,11 @@
#ifndef GLK_ALAN2_UTIL
#define GLK_ALAN2_UTIL
-#include "glk/alan2/acode.h"
-#include "glk/alan2/alan2.h"
#include "glk/alan2/types.h"
namespace Glk {
namespace Alan2 {
-// TODO: Move these
-extern LitElem *litValues;
-extern uint32 litCount; // for LITMAX - defined in parse.cpp
-extern ActElem *acts; // Actor table pointer
-extern ObjElem *objs; // Object table pointer
-
-// Type checks
-inline bool isObj(Aword x) {
- return x >= OBJMIN && x <= OBJMAX;
-}
-
-inline bool isAct(Aword x) {
- return x >= ACTMIN && x <= ACTMAX;
-}
-
-inline bool isCnt(Aword x) {
- return (x >= CNTMIN && x <= CNTMAX) ||
- (isObj(x) && objs[x - OBJMIN].cont != 0) ||
- (isAct(x) && acts[x - ACTMIN].cont != 0);
-}
-
-inline bool isLoc(Aword x) {
- return x >= LOCMIN && x <= LOCMAX;
-}
-
-inline bool isNum(Aword x) {
- return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPNUM;
-}
-
-inline bool isStr(Aword x) {
- return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPSTR;
-}
-
-inline bool isLit(Aword x) {
- return x >= LITMIN && x <= LITMAX;
-}
-
-inline bool endOfTable(LimElem *addr) {
- Aword *x = (Aword *)addr;
- return *x == (Aword)EOF;
-}
-
-inline bool endOfTable(ScrElem *addr) {
- Aword *x = (Aword *)addr;
- return *x == (Aword)EOF;
-}
-
-inline bool endOfTable(ExtElem *addr) {
- Aword *x = (Aword *)addr;
- return *x == (Aword)EOF;
-}
-
} // End of namespace Alan2
} // End of namespace Glk
diff --git a/engines/glk/alan2/version.h b/engines/glk/alan2/version.h
new file mode 100644
index 0000000000..3bb90ad066
--- /dev/null
+++ b/engines/glk/alan2/version.h
@@ -0,0 +1,59 @@
+/* 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_ALAN2_VERSION
+#define GLK_ALAN2_VERSION
+
+#include "common/system.h"
+
+namespace Glk {
+namespace Alan2 {
+
+typedef int64 Time;
+
+struct Version {
+ char* string;
+ int version;
+ int revision;
+ int correction;
+ Time time;
+ char *state;
+};
+
+struct Product {
+ char* name;
+ char* slogan;
+ char* shortHeader;
+ char* longHeader;
+ char* date;
+ char* time;
+ char* user;
+ char* host;
+ char* ostype;
+ Version version;
+};
+
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index bfda72d34a..b87fea9311 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -33,6 +33,22 @@ MODULE_OBJS := \
advsys/vm.o \
alan2/alan2.o \
alan2/detection.o \
+ alan2/alan_version.o \
+ alan2/args.o \
+ alan2/debug.o \
+ alan2/decode.o \
+ alan2/exe.o \
+ alan2/glkio.o \
+ alan2/glkstart.o \
+ alan2/inter.o \
+ alan2/params.o \
+ alan2/parse.o \
+ alan2/readline.o \
+ alan2/reverse.o \
+ alan2/rules.o \
+ alan2/stack.o \
+ alan2/sysdep.o \
+ alan2/term.o \
frotz/bitmap_font.o \
frotz/config.o \
frotz/detection.o \