[Scummvm-git-logs] scummvm master -> b37201ef76c1de4bffcf1b45ffad42d2183afca7
dreammaster
paulfgilbert at gmail.com
Tue Oct 8 04:15:20 CEST 2019
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3653e83dc9 GLK: JACL: Skeleton subengine commit
a00ed41679 GLK: JACL: Adding subengine files
af4f390ab2 GLK: JACL: Adding subengine files
66468fa2fe GLK: JACL: gcc compilation fixes
fecf1b3834 GLK: JACL: Cleanup of loader code
1a78b67d08 GLK: JACL: Graceful exit when error occurs
2d2a6746f1 GLK: JACL: Fix game script execution
1342fce6f6 GLK: JACL: Hooking up savegame code to GMM
7327144857 GLK: JACL: Standardizing on calls to get stream line
b37201ef76 GLK: JACL: Fix exiting game when game window is closed
Commit: 3653e83dc9f4f3d97e548ce98616ea41c291d803
https://github.com/scummvm/scummvm/commit/3653e83dc9f4f3d97e548ce98616ea41c291d803
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:51-07:00
Commit Message:
GLK: JACL: Skeleton subengine commit
Changed paths:
A engines/glk/jacl/detection.cpp
A engines/glk/jacl/detection.h
A engines/glk/jacl/detection_tables.h
A engines/glk/jacl/jacl.cpp
A engines/glk/jacl/jacl.h
engines/glk/detection.cpp
engines/glk/module.mk
diff --git a/engines/glk/detection.cpp b/engines/glk/detection.cpp
index f653172..08dd7d0 100644
--- a/engines/glk/detection.cpp
+++ b/engines/glk/detection.cpp
@@ -37,6 +37,8 @@
#include "glk/glulxe/glulxe.h"
#include "glk/hugo/detection.h"
#include "glk/hugo/hugo.h"
+#include "glk/jacl/detection.h"
+#include "glk/jacl/jacl.h"
#include "glk/magnetic/detection.h"
#include "glk/magnetic/magnetic.h"
#include "glk/quest/detection.h"
@@ -168,6 +170,7 @@ Common::Error GlkMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
else if ((*engine = create<Glk::Quest::QuestMetaEngine, Glk::Quest::Quest>(syst, gameDesc)) != nullptr) {}
else if ((*engine = create<Glk::Scott::ScottMetaEngine, Glk::Scott::Scott>(syst, gameDesc)) != nullptr) {}
#ifndef RELEASE_BUILD
+ else if ((*engine = create<Glk::JACL::JACLMetaEngine, Glk::JACL::JACL>(syst, gameDesc)) != nullptr) {}
else if ((*engine = create<Glk::Magnetic::MagneticMetaEngine, Glk::Magnetic::Magnetic>(syst, gameDesc)) != nullptr) {}
else if ((td = Glk::TADS::TADSMetaEngine::findGame(gameDesc._gameId.c_str()))._description) {
if (td._options & Glk::TADS::OPTION_TADS3)
@@ -217,6 +220,7 @@ PlainGameList GlkMetaEngine::getSupportedGames() const {
Glk::Quest::QuestMetaEngine::getSupportedGames(list);
Glk::Scott::ScottMetaEngine::getSupportedGames(list);
#ifndef RELEASE_BUILD
+ Glk::JACL::JACLMetaEngine::getSupportedGames(list);
Glk::Magnetic::MagneticMetaEngine::getSupportedGames(list);
Glk::TADS::TADSMetaEngine::getSupportedGames(list);
#endif
@@ -253,6 +257,9 @@ PlainGameDescriptor GlkMetaEngine::findGame(const char *gameId) const {
if (gd._description) return gd;
#ifndef RELEASE_BUILD
+ gd = Glk::JACL::JACLMetaEngine::findGame(gameId);
+ if (gd._description) return gd;
+
gd = Glk::Magnetic::MagneticMetaEngine::findGame(gameId);
if (gd._description) return gd;
@@ -278,6 +285,7 @@ DetectedGames GlkMetaEngine::detectGames(const Common::FSList &fslist) const {
Glk::Scott::ScottMetaEngine::detectGames(fslist, detectedGames);
#ifndef RELEASE_BUILD
+ Glk::JACL::JACLMetaEngine::detectGames(fslist, detectedGames);
Glk::Magnetic::MagneticMetaEngine::detectGames(fslist, detectedGames);
Glk::TADS::TADSMetaEngine::detectGames(fslist, detectedGames);
#endif
@@ -298,6 +306,7 @@ void GlkMetaEngine::detectClashes() const {
Glk::Scott::ScottMetaEngine::detectClashes(map);
#ifndef RELEASE_BUILD
+ Glk::JACL::JACLMetaEngine::detectClashes(map);
Glk::Magnetic::MagneticMetaEngine::detectClashes(map);
Glk::TADS::TADSMetaEngine::detectClashes(map);
#endif
diff --git a/engines/glk/jacl/detection.cpp b/engines/glk/jacl/detection.cpp
new file mode 100644
index 0000000..63d0485
--- /dev/null
+++ b/engines/glk/jacl/detection.cpp
@@ -0,0 +1,93 @@
+/* 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/jacl/detection.h"
+#include "glk/jacl/detection_tables.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/md5.h"
+#include "engines/game.h"
+
+namespace Glk {
+namespace JACL {
+
+void JACLMetaEngine::getSupportedGames(PlainGameList &games) {
+ for (const PlainGameDescriptor *pd = JACL_GAME_LIST; pd->gameId; ++pd)
+ games.push_back(*pd);
+}
+
+GameDescriptor JACLMetaEngine::findGame(const char *gameId) {
+ for (const PlainGameDescriptor *pd = JACL_GAME_LIST; pd->gameId; ++pd) {
+ if (!strcmp(gameId, pd->gameId))
+ return *pd;
+ }
+
+ return GameDescriptor::empty();
+}
+
+bool JACLMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
+ // Loop through the files of the folder
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ // Check for a recognised filename
+ if (file->isDirectory())
+ continue;
+
+ Common::String filename = file->getName();
+ if (!filename.hasSuffixIgnoreCase(".j2"))
+ continue;
+
+ Common::File gameFile;
+ if (!gameFile.open(*file))
+ continue;
+
+ gameFile.seek(0);
+ Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
+ uint32 filesize = gameFile.size();
+
+ // Scan through the JACL game list for a match
+ const GlkDetectionEntry *p = JACL_GAMES;
+ while (p->_md5 && p->_filesize != filesize && md5 != p->_md5)
+ ++p;
+
+ if (!p->_gameId) {
+ const PlainGameDescriptor &desc = JACL_GAME_LIST[0];
+ gameList.push_back(GlkDetectedGame(desc.gameId, desc.description, filename, md5, filesize));
+ } else {
+ // Found a match
+ PlainGameDescriptor gameDesc = findGame(p->_gameId);
+ gameList.push_back(GlkDetectedGame(p->_gameId, gameDesc.description, filename));
+ }
+ }
+
+ return !gameList.empty();
+}
+
+void JACLMetaEngine::detectClashes(Common::StringMap &map) {
+ for (const PlainGameDescriptor *pd = JACL_GAME_LIST; pd->gameId; ++pd) {
+ if (map.contains(pd->gameId))
+ error("Duplicate game Id found - %s", pd->gameId);
+ map[pd->gameId] = "";
+ }
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/detection.h b/engines/glk/jacl/detection.h
new file mode 100644
index 0000000..f576b66
--- /dev/null
+++ b/engines/glk/jacl/detection.h
@@ -0,0 +1,60 @@
+/* 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 JACL_DETECTION
+#define JACL_DETECTION
+
+#include "common/fs.h"
+#include "common/hash-str.h"
+#include "engines/game.h"
+#include "glk/detection.h"
+
+namespace Glk {
+namespace JACL {
+
+class JACLMetaEngine {
+public:
+ /**
+ * Get a list of supported games
+ */
+ static void getSupportedGames(PlainGameList &games);
+
+ /**
+ * Returns a game description for the given game Id, if it's supported
+ */
+ static GameDescriptor findGame(const char *gameId);
+
+ /**
+ * Detect supported games
+ */
+ static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
+
+ /**
+ * Check for game Id clashes with other sub-engines
+ */
+ static void detectClashes(Common::StringMap &map);
+};
+
+} // End of namespace JACL
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/jacl/detection_tables.h b/engines/glk/jacl/detection_tables.h
new file mode 100644
index 0000000..a5d7b03
--- /dev/null
+++ b/engines/glk/jacl/detection_tables.h
@@ -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 "engines/game.h"
+#include "common/gui_options.h"
+#include "common/language.h"
+
+namespace Glk {
+namespace JACL {
+
+const PlainGameDescriptor JACL_GAME_LIST[] = {
+ { "prisonbreak", "Prisoner Break" },
+ { "unholygrail", "The Unholy Grail" },
+
+ { nullptr, nullptr }
+};
+
+const GlkDetectionEntry JACL_GAMES[] = {
+ DT_ENTRY0("prisonbreak", "e2e85c5e60a63575bf0cd0481f0f3958", 199403),
+ DT_ENTRY0("unholygrail", "7d40e485c8cf8c9d5c4958a79337d6c7", 447833),
+
+ DT_END_MARKER
+};
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
new file mode 100644
index 0000000..998a3fc
--- /dev/null
+++ b/engines/glk/jacl/jacl.cpp
@@ -0,0 +1,58 @@
+/* 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/jacl/jacl.h"
+#include "common/config-manager.h"
+
+namespace Glk {
+namespace JACL {
+
+JACL *g_vm;
+
+JACL::JACL(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
+ _saveSlot(-1) {
+ g_vm = this;
+}
+
+void JACL::runGame() {
+ // Check for savegame
+ _saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+
+}
+
+bool JACL::initialize() {
+ return true;
+}
+
+void JACL::deinitialize() {
+}
+
+Common::Error JACL::readSaveData(Common::SeekableReadStream *rs) {
+ return Common::kNoError;
+}
+
+Common::Error JACL::writeGameData(Common::WriteStream *ws) {
+ return Common::kNoError;
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/jacl.h b/engines/glk/jacl/jacl.h
new file mode 100644
index 0000000..49def8f
--- /dev/null
+++ b/engines/glk/jacl/jacl.h
@@ -0,0 +1,86 @@
+/* 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 JACL_JACL
+#define JACL_JACL
+
+#include "glk/glk_api.h"
+
+namespace Glk {
+namespace JACL {
+
+/**
+ * JACL game interpreter
+ */
+class JACL : public GlkAPI {
+private:
+ int _saveSlot;
+private:
+ /**
+ * Engine initialization
+ */
+ bool initialize();
+
+ /**
+ * Engine cleanup
+ */
+ void deinitialize();
+public:
+ /**
+ * Constructor
+ */
+ JACL(OSystem *syst, const GlkGameDescription &gameDesc);
+
+ /**
+ * Run the game
+ */
+ virtual void runGame() override;
+
+ /**
+ * Returns the running interpreter type
+ */
+ virtual InterpreterType getInterpreterType() const override {
+ return INTERPRETER_JACL;
+ }
+
+ /**
+ * Savegames aren't supported for JACL games
+ */
+ virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override;
+
+ /**
+ * Savegames aren't supported for JACL games
+ */
+ virtual Common::Error writeGameData(Common::WriteStream *ws) override;
+
+ /**
+ * Returns true if a savegame is being loaded directly from the ScummVM launcher
+ */
+ bool loadingSavegame() const { return _saveSlot != -1; }
+};
+
+extern JACL *g_vm;
+
+} // End of namespace JACL
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 8dfb249..0082631 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -177,6 +177,8 @@ MODULE_OBJS := \
hugo/htokens.o \
hugo/hugo.o \
hugo/stringfn.o \
+ jacl/detection.o \
+ jacl/jacl.o \
magnetic/detection.o \
magnetic/emu.o \
magnetic/graphics.o \
Commit: a00ed41679b9cdc6a4f2ede5c500a658f600103c
https://github.com/scummvm/scummvm/commit/a00ed41679b9cdc6a4f2ede5c500a658f600103c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:51-07:00
Commit Message:
GLK: JACL: Adding subengine files
Changed paths:
engines/glk/jacl/detection.cpp
engines/glk/jacl/detection.h
engines/glk/jacl/detection_tables.h
engines/glk/jacl/jacl.cpp
engines/glk/jacl/jacl.h
engines/glk/module.mk
diff --git a/engines/glk/jacl/detection.cpp b/engines/glk/jacl/detection.cpp
index 63d0485..d0e6f34 100644
--- a/engines/glk/jacl/detection.cpp
+++ b/engines/glk/jacl/detection.cpp
@@ -22,10 +22,10 @@
#include "glk/jacl/detection.h"
#include "glk/jacl/detection_tables.h"
-#include "common/debug.h"
-#include "common/file.h"
-#include "common/md5.h"
-#include "engines/game.h"
+#include "glk/jacl/common/debug.h"
+#include "glk/jacl/common/file.h"
+#include "glk/jacl/common/md5.h"
+#include "glk/jacl/engines/game.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/detection.h b/engines/glk/jacl/detection.h
index f576b66..b93ea36 100644
--- a/engines/glk/jacl/detection.h
+++ b/engines/glk/jacl/detection.h
@@ -23,10 +23,10 @@
#ifndef JACL_DETECTION
#define JACL_DETECTION
-#include "common/fs.h"
-#include "common/hash-str.h"
-#include "engines/game.h"
-#include "glk/detection.h"
+#include "glk/jacl/common/fs.h"
+#include "glk/jacl/common/hash-str.h"
+#include "glk/jacl/engines/game.h"
+#include "glk/jacl/glk/detection.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/detection_tables.h b/engines/glk/jacl/detection_tables.h
index a5d7b03..d5f86c8 100644
--- a/engines/glk/jacl/detection_tables.h
+++ b/engines/glk/jacl/detection_tables.h
@@ -20,9 +20,9 @@
*
*/
-#include "engines/game.h"
-#include "common/gui_options.h"
-#include "common/language.h"
+#include "glk/jacl/engines/game.h"
+#include "glk/jacl/common/gui_options.h"
+#include "glk/jacl/common/language.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
index 998a3fc..0178b1c 100644
--- a/engines/glk/jacl/jacl.cpp
+++ b/engines/glk/jacl/jacl.cpp
@@ -21,7 +21,7 @@
*/
#include "glk/jacl/jacl.h"
-#include "common/config-manager.h"
+#include "glk/jacl/common/config-manager.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/jacl.h b/engines/glk/jacl/jacl.h
index 49def8f..ce04c89 100644
--- a/engines/glk/jacl/jacl.h
+++ b/engines/glk/jacl/jacl.h
@@ -28,6 +28,8 @@
namespace Glk {
namespace JACL {
+#define GLK
+
/**
* JACL game interpreter
*/
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 0082631..5cdb9b1 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -178,7 +178,20 @@ MODULE_OBJS := \
hugo/hugo.o \
hugo/stringfn.o \
jacl/detection.o \
- jacl/jacl.o \
+ jacl/display.o \
+ jacl/encapsulate.o \
+ jacl/errors.o \
+ jacl/findroute.o \
+ jacl/glk_saver.o \
+ jacl/glk_startup.o \
+ jacl/interpreter.o \
+ jacl/jpp.o \
+ jacl/libcsv.o \
+ jacl/loader.o \
+ jacl/logging.o \
+ jacl/parser.o \
+ jacl/resolvers.o \
+ jacl/utils.o \
magnetic/detection.o \
magnetic/emu.o \
magnetic/graphics.o \
Commit: af4f390ab26c2a181b3dc69dfd93e8fcf5bc30a0
https://github.com/scummvm/scummvm/commit/af4f390ab26c2a181b3dc69dfd93e8fcf5bc30a0
Author: dreammaster (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:51-07:00
Commit Message:
GLK: JACL: Adding subengine files
Changed paths:
A engines/glk/jacl/constants.h
A engines/glk/jacl/csv.h
A engines/glk/jacl/display.cpp
A engines/glk/jacl/encapsulate.cpp
A engines/glk/jacl/errors.cpp
A engines/glk/jacl/findroute.cpp
A engines/glk/jacl/glk_saver.cpp
A engines/glk/jacl/glk_startup.cpp
A engines/glk/jacl/interpreter.cpp
A engines/glk/jacl/jacl_main.cpp
A engines/glk/jacl/jpp.cpp
A engines/glk/jacl/language.h
A engines/glk/jacl/libcsv.cpp
A engines/glk/jacl/loader.cpp
A engines/glk/jacl/logging.cpp
A engines/glk/jacl/parser.cpp
A engines/glk/jacl/prototypes.h
A engines/glk/jacl/resolvers.cpp
A engines/glk/jacl/types.h
A engines/glk/jacl/utils.cpp
A engines/glk/jacl/version.h
engines/glk/jacl/detection.cpp
engines/glk/jacl/detection.h
engines/glk/jacl/detection_tables.h
engines/glk/jacl/jacl.cpp
engines/glk/jacl/jacl.h
engines/glk/module.mk
diff --git a/engines/glk/jacl/constants.h b/engines/glk/jacl/constants.h
new file mode 100644
index 0000000..f7c00d1
--- /dev/null
+++ b/engines/glk/jacl/constants.h
@@ -0,0 +1,184 @@
+/* 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.
+ *
+ */
+
+namespace Glk {
+namespace JACL {
+
+#define MAX_WORDS 20
+#define STACK_SIZE 20
+#define MAX_UNDO 100
+#define MAX_OBJECTS 1000
+
+/* LOCATION ATTRIBUTE VALUES */
+
+#define VISITED 1
+#define DARK 2
+#define ON_WATER 4
+#define UNDER_WATER 8
+#define WITHOUT_AIR 16
+#define OUTDOORS 32
+#define MID_AIR 64
+#define TIGHT_ROPE 128
+#define POLLUTED 256
+#define SOLVED 512
+#define MID_WATER 1024
+#define DARKNESS 2048
+#define MAPPED 4096
+#define KNOWN 8192
+
+/* OBJECT ATTRIBUTE VALUES */
+
+#define CLOSED 1
+#define LOCKED 2
+#define DEAD 4
+#define IGNITABLE 8
+#define WORN 16
+#define CONCEALING 32
+#define LUMINOUS 64
+#define WEARABLE 128
+#define CLOSABLE 256
+#define LOCKABLE 512
+#define ANIMATE 1024
+#define LIQUID 2048
+#define CONTAINER 4096
+#define SURFACE 8192
+#define PLURAL 16384
+#define FLAMMABLE 32768
+#define BURNING 65536
+#define LOCATION 131072
+#define ON 262144
+#define DAMAGED 524288
+#define FEMALE 1048576
+#define POSSESSIVE 2097152
+#define OUT_OF_REACH 4194304
+#define TOUCHED 8388608
+#define SCORED 16777216
+#define SITTING 33554432
+#define NPC 67108864
+#define DONE 134217728
+#define GAS 268435456
+#define NO_TAB 536870912
+#define NOT_IMPORTANT 1073741824
+
+/* LOCATION INTEGER ARRAY INDEXES */
+
+#define NORTH_DIR 0
+#define SOUTH_DIR 1
+#define EAST_DIR 2
+#define WEST_DIR 3
+#define NORTHEAST_DIR 4
+#define NORTHWEST_DIR 5
+#define SOUTHEAST_DIR 6
+#define SOUTHWEST_DIR 7
+#define UP_DIR 8
+#define DOWN_DIR 9
+#define IN_DIR 10
+#define OUT_DIR 11
+
+/* ALL UP, THERE ARE 16 OBJECT ELEMENTS, THESE 6
+ ARE THE ONLY ONES ACCESSED BY THE INTERPRETER */
+
+#define PARENT integer[0]
+#define QUANTITY integer[1]
+#define MASS integer[2]
+#define BEARING integer[3]
+#define VELOCITY integer[4]
+#define X integer[14]
+#define Y integer[15]
+
+/* SYSTEM VARIABLES */
+
+#define COMPASS integer_resolve("compass")
+#define DESTINATION integer_resolve("destination")
+#define TOTAL_MOVES integer_resolve("total_moves")
+#define TIME integer_resolve("time")
+#define SCORE integer_resolve("score")
+#define INTERNAL_VERSION integer_resolve("internal_version")
+#define DISPLAY_MODE integer_resolve("display_mode")
+#define MAX_RAND integer_resolve("max_rand")
+#define INTERRUPTED integer_resolve("interrupted")
+#define SOUND_ENABLED integer_resolve("sound_enabled")
+#define GRAPHICS_ENABLED integer_resolve("graphics_enabled")
+#define TIMER_ENABLED integer_resolve("timer_enabled")
+#define MULTI_PREFIX integer_resolve("multi_prefix")
+#define NOTIFY integer_resolve("notify")
+#define DEBUG integer_resolve("debug")
+
+/* SYSTEM INTEGER CONSTANTS */
+
+#define SOUND_SUPPORTED cinteger_resolve("sound_supported")
+#define GRAPHICS_SUPPORTED cinteger_resolve("graphics_supported")
+#define TIMER_SUPPORTED cinteger_resolve("timer_supported")
+
+/* ABBREVIATIONS */
+
+#define HELD player
+#define HERE get_here()
+
+/* CONSTANTS */
+
+#define SYSTEM_ATTRIBUTE 0
+#define USER_ATTRIBUTE 1
+
+#define FALSE 0
+#define TRUE 1
+
+#define UNRESTRICT 0
+#define RESTRICT 1
+
+#define SEEK_SET 0
+
+#define SEEK_END 2
+
+#define SCENERY 100
+#define HEAVY 99
+#define NOWHERE 0
+
+#define LOG_ONLY 0
+#define PLUS_STDOUT 1
+#define PLUS_STDERR 2
+#define ONLY_STDERR 3
+#define ONLY_STDOUT 4
+
+#define INT_TYPE 1
+#define STR_TYPE 2
+#define CINT_TYPE 3
+#define CSTR_TYPE 4
+#define ATT_TYPE 5
+#define OBJ_TYPE 6
+
+#define CRI_NONE 0
+#define CRI_ATTRIBUTE 1
+#define CRI_USER_ATTRIBUTE 2
+#define CRI_PARENT 3
+#define CRI_SCOPE 4
+
+#define BOLD 1
+#define NOTE 2
+#define INPUT 3
+#define HEADER 4
+#define SUBHEADER 5
+#define REVERSE 6
+#define PRE 7
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/csv.h b/engines/glk/jacl/csv.h
new file mode 100644
index 0000000..f979f00
--- /dev/null
+++ b/engines/glk/jacl/csv.h
@@ -0,0 +1,106 @@
+/* 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 JACL_CSV
+#define JACL_CSV
+
+#include "common/stream.h"
+
+namespace Glk {
+namespace JACL {
+
+#define CSV_MAJOR 3
+#define CSV_MINOR 0
+#define CSV_RELEASE 0
+
+/* Error Codes */
+#define CSV_SUCCESS 0
+#define CSV_EPARSE 1 /* Parse error in strict mode */
+#define CSV_ENOMEM 2 /* Out of memory while increasing buffer size */
+#define CSV_ETOOBIG 3 /* Buffer larger than SIZE_MAX needed */
+#define CSV_EINVALID 4 /* Invalid code,should never be received from csv_error*/
+
+
+/* parser options */
+#define CSV_STRICT 1 /* enable strict mode */
+#define CSV_REPALL_NL 2 /* report all unquoted carriage returns and linefeeds */
+#define CSV_STRICT_FINI 4 /* causes csv_fini to return CSV_EPARSE if last
+ field is quoted and doesn't containg ending
+ quote */
+#define CSV_APPEND_NULL 8 /* Ensure that all fields are null-ternimated */
+
+
+/* Character values */
+#define CSV_TAB 0x09
+#define CSV_SPACE 0x20
+#define CSV_CR 0x0d
+#define CSV_LF 0x0a
+#define CSV_COMMA 0x2c
+#define CSV_QUOTE 0x22
+
+struct csv_parser {
+ int pstate; /* Parser state */
+ int quoted; /* Is the current field a quoted field? */
+ size_t spaces; /* Number of continious spaces after quote or in a non-quoted field */
+ unsigned char *entry_buf; /* Entry buffer */
+ size_t entry_pos; /* Current position in entry_buf (and current size of entry) */
+ size_t entry_size; /* Size of entry buffer */
+ int status; /* Operation status */
+ unsigned char options;
+ unsigned char quote_char;
+ unsigned char delim_char;
+ int (*is_space)(unsigned char);
+ int (*is_term)(unsigned char);
+ size_t blk_size;
+ void *(*malloc_func)(size_t);
+ void *(*realloc_func)(void *, size_t);
+ void (*free_func)(void *);
+};
+
+/* Function Prototypes */
+int csv_init(struct csv_parser *p, unsigned char options);
+int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
+void csv_free(struct csv_parser *p);
+int csv_error(struct csv_parser *p);
+char *csv_strerror(int error);
+size_t csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
+size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size);
+int csv_fwrite(Common::WriteStream *fp, const void *src, size_t src_size);
+size_t csv_write2(void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote);
+int csv_fwrite2(Common::WriteStream *fp, const void *src, size_t src_size, unsigned char quote);
+int csv_get_opts(struct csv_parser *p);
+int csv_set_opts(struct csv_parser *p, unsigned char options);
+void csv_set_delim(struct csv_parser *p, unsigned char c);
+void csv_set_quote(struct csv_parser *p, unsigned char c);
+unsigned char csv_get_delim(struct csv_parser *p);
+unsigned char csv_get_quote(struct csv_parser *p);
+void csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char));
+void csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char));
+void csv_set_realloc_func(struct csv_parser *p, void *(*)(void *, size_t));
+void csv_set_free_func(struct csv_parser *p, void (*)(void *));
+void csv_set_blk_size(struct csv_parser *p, size_t);
+size_t csv_get_buffer_size(struct csv_parser *p);
+
+} // End of namespace JACL
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/jacl/detection.cpp b/engines/glk/jacl/detection.cpp
index d0e6f34..63d0485 100644
--- a/engines/glk/jacl/detection.cpp
+++ b/engines/glk/jacl/detection.cpp
@@ -22,10 +22,10 @@
#include "glk/jacl/detection.h"
#include "glk/jacl/detection_tables.h"
-#include "glk/jacl/common/debug.h"
-#include "glk/jacl/common/file.h"
-#include "glk/jacl/common/md5.h"
-#include "glk/jacl/engines/game.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/md5.h"
+#include "engines/game.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/detection.h b/engines/glk/jacl/detection.h
index b93ea36..f576b66 100644
--- a/engines/glk/jacl/detection.h
+++ b/engines/glk/jacl/detection.h
@@ -23,10 +23,10 @@
#ifndef JACL_DETECTION
#define JACL_DETECTION
-#include "glk/jacl/common/fs.h"
-#include "glk/jacl/common/hash-str.h"
-#include "glk/jacl/engines/game.h"
-#include "glk/jacl/glk/detection.h"
+#include "common/fs.h"
+#include "common/hash-str.h"
+#include "engines/game.h"
+#include "glk/detection.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/detection_tables.h b/engines/glk/jacl/detection_tables.h
index d5f86c8..a5d7b03 100644
--- a/engines/glk/jacl/detection_tables.h
+++ b/engines/glk/jacl/detection_tables.h
@@ -20,9 +20,9 @@
*
*/
-#include "glk/jacl/engines/game.h"
-#include "glk/jacl/common/gui_options.h"
-#include "glk/jacl/common/language.h"
+#include "engines/game.h"
+#include "common/gui_options.h"
+#include "common/language.h"
namespace Glk {
namespace JACL {
diff --git a/engines/glk/jacl/display.cpp b/engines/glk/jacl/display.cpp
new file mode 100644
index 0000000..db59efb
--- /dev/null
+++ b/engines/glk/jacl/display.cpp
@@ -0,0 +1,265 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+
+namespace Glk {
+namespace JACL {
+
+extern char temp_buffer[];
+extern char function_name[];
+
+extern struct object_type *object[];
+extern struct variable_type *variable[];
+
+extern char *word[];
+
+extern int player;
+extern int wp;
+extern int objects;
+extern int custom_error;
+
+extern int spaced;
+
+int check_light(int where) {
+ int index;
+
+ if ((object[where]->attributes & DARK) == FALSE)
+ return (TRUE);
+ else {
+ for (index = 1; index <= objects; index++) {
+ if ((object[index]->attributes & LUMINOUS)
+ && scope(index, "*present"))
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+char *sentence_output(int index, int capital) {
+ if (!strcmp(object[index]->article, "name")) {
+ strcpy(temp_buffer, object[index]->inventory);
+ } else {
+ strcpy(temp_buffer, object[index]->definite);
+ strcat(temp_buffer, " ");
+ strcat(temp_buffer, object[index]->inventory);
+ }
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return (temp_buffer);
+}
+
+char *isnt_output(int index, bool) {
+ if (object[index]->attributes & PLURAL)
+ return (cstring_resolve("ARENT")->value);
+ else
+ return (cstring_resolve("ISNT")->value);
+}
+
+char *is_output(int index, bool) {
+ if (object[index]->attributes & PLURAL)
+ return (cstring_resolve("ARE")->value);
+ else
+ return (cstring_resolve("IS")->value);
+}
+
+char *sub_output(int index, int capital) {
+ if (object[index]->attributes & PLURAL) {
+ strcpy(temp_buffer, cstring_resolve("THEY_WORD")->value);
+ } else {
+ if (index == player) {
+ strcpy(temp_buffer, cstring_resolve("YOU_WORD")->value);
+ } else if (object[index]->attributes & ANIMATE) {
+ if (object[index]->attributes & FEMALE) {
+ strcpy(temp_buffer, cstring_resolve("SHE_WORD")->value);
+ } else {
+ strcpy(temp_buffer, cstring_resolve("HE_WORD")->value);
+ }
+ } else {
+ strcpy(temp_buffer, cstring_resolve("IT_WORD")->value);
+ }
+ }
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return temp_buffer;
+}
+
+char *obj_output(int index, int capital) {
+ if (object[index]->attributes & PLURAL) {
+ strcpy(temp_buffer, cstring_resolve("THEM_WORD")->value);
+ } else {
+ if (index == player) {
+ strcpy(temp_buffer, cstring_resolve("YOURSELF_WORD")->value);
+ } else if (object[index]->attributes & ANIMATE) {
+ if (object[index]->attributes & FEMALE) {
+ strcpy(temp_buffer, cstring_resolve("HER_WORD")->value);
+ } else {
+ strcpy(temp_buffer, cstring_resolve("HIM_WORD")->value);
+ }
+ } else {
+ strcpy(temp_buffer, cstring_resolve("IT_WORD")->value);
+ }
+ }
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return temp_buffer;
+}
+
+char *it_output(int index, bool) {
+ if (object[index]->attributes & ANIMATE) {
+ return sentence_output(index, FALSE);
+ } else {
+ if (object[index]->attributes & PLURAL) {
+ return (cstring_resolve("THEM_WORD")->value);
+ } else {
+ return (cstring_resolve("IT_WORD")->value);
+ }
+ }
+}
+
+char *that_output(int index, int capital) {
+ if (object[index]->attributes & PLURAL) {
+ strcpy(temp_buffer, cstring_resolve("THOSE_WORD")->value);
+ } else {
+ strcpy(temp_buffer, cstring_resolve("THAT_WORD")->value);
+ }
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return temp_buffer;
+}
+
+char *doesnt_output(int index, bool) {
+ if (object[index]->attributes & PLURAL)
+ return (cstring_resolve("DONT")->value);
+ else
+ return (cstring_resolve("DOESNT")->value);
+}
+
+char *does_output(int index, bool) {
+ if (object[index]->attributes & PLURAL)
+ return (cstring_resolve("DO")->value);
+ else
+ return (cstring_resolve("DOES")->value);
+}
+
+char *list_output(int index, int capital) {
+ if (!strcmp(object[index]->article, "name")) {
+ strcpy(temp_buffer, object[index]->inventory);
+ } else {
+ strcpy(temp_buffer, object[index]->article);
+ strcat(temp_buffer, " ");
+ strcat(temp_buffer, object[index]->inventory);
+ }
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return (temp_buffer);
+}
+
+char *plain_output(int index, int capital) {
+ strcpy(temp_buffer, object[index]->inventory);
+
+ if (capital)
+ temp_buffer[0] = toupper(temp_buffer[0]);
+
+ return (temp_buffer);
+}
+
+char *long_output(int index) {
+ if (!strcmp(object[index]->described, "function")) {
+ strcpy(function_name, "long_");
+ strcat(function_name, object[index]->label);
+ if (execute(function_name) == FALSE) {
+ unkfunrun(function_name);
+ }
+
+ // THE BUFFER IS RETURNED EMPTY AS THE TEXT IS OUTPUT BY
+ // WRITE STATEMENTS IN THE FUNCTION CALLED
+ temp_buffer[0] = 0;
+ return (temp_buffer);
+ } else {
+ return (object[index]->described);
+ }
+}
+
+void no_it() {
+ write_text(cstring_resolve("NO_IT")->value);
+ write_text(word[wp]);
+ write_text(cstring_resolve("NO_IT_END")->value);
+ custom_error = TRUE;
+}
+
+void look_around() {
+ /* THIS FUNCTION DISPLAYS THE DESCRIPTION OF THE CURRENT LOCATION ALONG
+ * WITH ANY OBJECTS CURRENTLY IN IT */
+
+ if (!check_light(HERE)) {
+ /* THE CURRENT LOCATION HAS 'DARK' AND NO SOURCE OF LIGHT IS
+ * CURRENTLY PRESENT */
+ execute("+dark_description");
+ return;
+ }
+
+ if (execute("+before_look") != FALSE)
+ return;
+
+ execute("+title");
+
+ if (DISPLAY_MODE->value) {
+ /* THE INTERPRETER IS IN VERBOSE MODE SO TEMPORARILY TAKE AWAYS THE
+ * 'VISITED' ATTRIBUTE */
+ object[HERE]->attributes &= ~1L;
+ }
+
+ strcpy(function_name, "look_");
+ strcat(function_name, object[HERE]->label);
+ execute(function_name);
+
+ /* GIVE THE LOCATION THE ATTRIBUTES 'VISITED', 'KNOWN', AND 'MAPPED' NOW
+ * THAT THE LOOK FUNCTION HAS RUN */
+ object[HERE]->attributes = object[HERE]->attributes | KNOWN;
+ object[HERE]->attributes = object[HERE]->attributes | VISITED;
+ object[HERE]->attributes = object[HERE]->attributes | MAPPED;
+
+ execute("+object_descriptions");
+
+ strcpy(function_name, "after_look_");
+ strcat(function_name, object[HERE]->label);
+ execute(function_name);
+
+ execute("+after_look");
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/encapsulate.cpp b/engines/glk/jacl/encapsulate.cpp
new file mode 100644
index 0000000..8e65ba3
--- /dev/null
+++ b/engines/glk/jacl/encapsulate.cpp
@@ -0,0 +1,279 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+
+namespace Glk {
+namespace JACL {
+
+extern struct synonym_type *synonym_table;
+extern struct filter_type *filter_table;
+
+char text_buffer[1024];
+
+/* THIS IS A STRING CONSTANT TO POINT TO WHENEVER A COMMA IS
+ * USED IN THE PLAYER'S INPUT */
+char *comma = "comma\0";
+char *then = "then\0";
+char *word[MAX_WORDS];
+int quoted[MAX_WORDS];
+int percented[MAX_WORDS];
+int wp;
+
+void
+encapsulate() {
+ int index,
+ length;
+ int position = 0;
+ int new_word = TRUE;
+
+ length = strlen(text_buffer);
+
+ /* QUOTED IS USED TO STORE WHETHER EACH WORD WAS ENCLOSED IN QUOTES
+ * IN THE PLAYERS COMMAND - RESET EACH WORD TO NO */
+ for (index = 0; index < MAX_WORDS; index++) {
+ quoted[index] = 0;
+ percented[index] = 0;
+ }
+
+ for (index = 0; index < length; index++) {
+
+ switch (text_buffer[index]) {
+ case ':':
+ case '\t':
+ case ' ':
+ case ',':
+ text_buffer[index] = 0;
+ new_word = TRUE;
+ break;
+ case ';':
+ case '#':
+ case '\r':
+ case '\n':
+ /* TERMINATE THE WHOLE COMMAND ON HITTING A NEWLINE CHARACTER, A
+ * SEMICOLON OR A HASH */
+ text_buffer[index] = 0;
+ index = length;
+ break;
+ case '"':
+ index++;
+ /* NEED TO REMEMBER THAT THIS WORD WAS ENCLOSED IN QUOTES FOR
+ * THE COMMAND 'write'*/
+ quoted[position] = 1;
+
+ word[position] = &text_buffer[index];
+
+ if (position < MAX_WORDS)
+ position++;
+
+ /* IF A WORD IS ENCLOSED IN QUOTES, KEEP GOING UNTIL THE END
+ * OF THE LINE OR A CLOSING QUOTE IS FOUND, NOT BREAKING AT
+ * WHITESPACE AS USUAL */
+ for (; index < length; index++) {
+ if (text_buffer[index] == '"') {
+ text_buffer[index] = 0;
+ new_word = TRUE;
+ break;
+ } else if (text_buffer[index] == '\r' || text_buffer[index] == '\n') {
+ text_buffer[index] = 0;
+ index = length;
+ break;
+ }
+ }
+ break;
+ default:
+ if (new_word) {
+ if (text_buffer[index] == '%' && text_buffer[index + 1] != ' ' && text_buffer[index + 1] != '\t') {
+ percented[position]++;
+ break;
+ }
+ word[position] = &text_buffer[index];
+ new_word = FALSE;
+ if (position < MAX_WORDS)
+ position++;
+ }
+ break;
+ }
+
+ }
+
+ /* NULL OUT ALL THE WORD POINTERS BEYOND THE LAST WORD */
+ for (index = position; index < MAX_WORDS; index++)
+ word[index] = NULL;
+
+ wp = 0;
+}
+
+// THIS VERSION OF ENCAPSULATE DOESN'T LOOK FOR CERTAIN SPECIAL CHARACTERS
+void
+command_encapsulate() {
+ int index,
+ length;
+ int position = 0;
+ int new_word = TRUE;
+
+ length = strlen(text_buffer);
+
+ // QUOTED IS USED TO STORE WHETHER EACH WORD WAS ENCLOSED IN QUOTES
+ // IN THE PLAYERS COMMAND - RESET EACH WORD TO NO
+ for (index = 0; index < MAX_WORDS; index++) {
+ quoted[index] = 0;
+ }
+
+ for (index = 0; index < length; index++) {
+
+ // REDUSE EVERYTHING TO LOWER CASE EXCEPT TEXT ENCLOSED IN QUOTES
+ text_buffer[index] = tolower((int) text_buffer[index]);
+
+ switch (text_buffer[index]) {
+ case ':':
+ case '\t':
+ case ' ':
+ text_buffer[index] = 0;
+ new_word = TRUE;
+ break;
+ case ',':
+ text_buffer[index] = 0;
+ // SET THIS WORD TO POINT TO A STRING CONSTANT OF 'comma' AS THE
+ // COMMA ITSELF WILL BE NULLED OUT TO TERMINATE THE PRECEEDING
+ // WORD IN THE COMMAND.
+ word[position] = comma;
+ if (position < MAX_WORDS)
+ position++;
+ new_word = TRUE;
+ break;
+ case '.':
+ text_buffer[index] = 0;
+ // SET THIS WORD TO POINT TO A STRING CONSTANT OF 'comma' AS THE
+ // COMMA ITSELF WILL BE NULLED OUT TO TERMINATE THE PRECEEDING
+ // WORD IN THE COMMAND
+ word[position] = then;
+ if (position < MAX_WORDS)
+ position++;
+ new_word = TRUE;
+ break;
+ case ';':
+ case '\r':
+ case '\n':
+ // TERMINATE THE WHOLE COMMAND ON HITTING A NEWLINE CHARACTER, A
+ // SEMICOLON OR A HASH
+ text_buffer[index] = 0;
+ index = length;
+ break;
+ case '"':
+ index++;
+ // NEED TO REMEMBER THAT THIS WORD WAS ENCLOSED IN QUOTES FOR
+ // THE COMMAND 'write'
+ quoted[position] = 1;
+
+ word[position] = &text_buffer[index];
+
+ if (position < MAX_WORDS)
+ position++;
+
+ // IF A WORD IS ENCLOSED IN QUOTES, KEEP GOING UNTIL THE END
+ // OF THE LINE OR A CLOSING QUOTE IS FOUND, NOT BREAKING AT
+ // WHITESPACE AS USUAL
+ for (; index < length; index++) {
+ if (text_buffer[index] == '"') {
+ text_buffer[index] = 0;
+ new_word = TRUE;
+ break;
+ } else if (text_buffer[index] == '\r' || text_buffer[index] == '\n') {
+ text_buffer[index] = 0;
+ index = length;
+ break;
+ }
+ }
+ break;
+ default:
+ if (new_word) {
+ word[position] = &text_buffer[index];
+ new_word = FALSE;
+ if (position < MAX_WORDS)
+ position++;
+ }
+ break;
+ }
+
+ }
+
+ // NULL OUT ALL THE WORD POINTERS BEYOND THE LAST WORD
+ for (index = position; index < MAX_WORDS; index++) {
+ word[index] = NULL;
+ }
+
+ wp = 0;
+}
+
+void
+jacl_truncate() {
+ int index,
+ counter,
+ match;
+ int position = 0;
+
+ struct synonym_type *synonym;
+ struct filter_type *filter = filter_table;
+
+ // REMOVE ALL THE DEFINED 'filter's FROM THE PLAYER'S COMMAND
+ if (filter != NULL) {
+ while (word[position] != NULL) {
+ match = FALSE;
+ do {
+ if (!strcmp(word[position], filter->word)) {
+ for (index = position; word[index + 1] != NULL;
+ index++)
+ word[index] = word[index + 1];
+ word[index] = NULL;
+ match = TRUE;
+ }
+ filter = filter->next_filter;
+ } while (filter != NULL && !match);
+ filter = filter_table;
+ if (!match)
+ position++;
+ };
+ }
+
+ // SUBTITUTE ALL THE DEFINED 'synonym's IN THE PLAYER'S COMMAND
+ if (synonym_table != NULL) {
+ for (counter = 0; word[counter] != NULL; counter++) {
+ synonym = synonym_table;
+ do {
+ if (!strcmp(word[counter], synonym->original)) {
+ word[counter] = synonym->standard;
+ break;
+ }
+ if (synonym->next_synonym != NULL)
+ synonym = synonym->next_synonym;
+ else
+ break;
+ } while (TRUE);
+ }
+ }
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/errors.cpp b/engines/glk/jacl/errors.cpp
new file mode 100644
index 0000000..fc791ad
--- /dev/null
+++ b/engines/glk/jacl/errors.cpp
@@ -0,0 +1,169 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+
+namespace Glk {
+namespace JACL {
+
+extern struct function_type *executing_function;
+extern char *word[];
+
+extern char error_buffer[];
+
+void badparrun() {
+ sprintf(error_buffer, BAD_PARENT, executing_function->name);
+
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void notintrun() {
+ sprintf(error_buffer, NOT_INTEGER, executing_function->name, word[0]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void unkfunrun(char *name) {
+ sprintf(error_buffer, UNKNOWN_FUNCTION_RUN, name);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkkeyerr(int line, int wordno) {
+ sprintf(error_buffer, UNKNOWN_KEYWORD_ERR, line, word[wordno]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void unkatterr(int line, int wordno) {
+ sprintf(error_buffer, UNKNOWN_ATTRIBUTE_ERR, line,
+ word[wordno]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void unkvalerr(int line, int wordno) {
+ sprintf(error_buffer, UNKNOWN_VALUE_ERR, line,
+ word[wordno]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void noproprun(int) {
+ sprintf(error_buffer, INSUFFICIENT_PARAMETERS_RUN, executing_function->name, word[0]);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void noobjerr(int line) {
+ sprintf(error_buffer, NO_OBJECT_ERR,
+ line, word[0]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void noproperr(int line) {
+ sprintf(error_buffer, INSUFFICIENT_PARAMETERS_ERR,
+ line, word[0]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void nongloberr(int line) {
+ sprintf(error_buffer, NON_GLOBAL_FIRST, line);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void nofnamerr(int line) {
+ sprintf(error_buffer, NO_NAME_FUNCTION, line);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void unkobjerr(int line, int wordno) {
+ sprintf(error_buffer, UNDEFINED_ITEM_ERR, line, word[wordno]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void maxatterr(int line, int wordno) {
+ sprintf(error_buffer,
+ MAXIMUM_ATTRIBUTES_ERR, line, word[wordno]);
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void unkobjrun(int wordno) {
+ sprintf(error_buffer, UNDEFINED_ITEM_RUN, executing_function->name, word[wordno]);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkattrun(int wordno) {
+ sprintf(error_buffer, UNKNOWN_ATTRIBUTE_RUN, executing_function->name, word[wordno]);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkdirrun(int wordno) {
+ sprintf(error_buffer, UNDEFINED_DIRECTION_RUN,
+ executing_function->name, word[wordno]);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void badparun() {
+ sprintf(error_buffer, BAD_PARENT, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void badplrrun(int value) {
+ sprintf(error_buffer, BAD_PLAYER, executing_function->name, value);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void badptrrun(char *name, int value) {
+ sprintf(error_buffer, BAD_POINTER, executing_function->name, name, value);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkvarrun(char *variable) {
+ sprintf(error_buffer, UNDEFINED_CONTAINER_RUN, executing_function->name, arg_text_of(variable));
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkstrrun(char *variable) {
+ sprintf(error_buffer, UNDEFINED_STRING_RUN, executing_function->name, variable);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void unkscorun(char *scope) {
+ sprintf(error_buffer, UNKNOWN_SCOPE_RUN, executing_function->name, scope);
+ log_error(error_buffer, PLUS_STDOUT);
+}
+
+void totalerrs(int errors) {
+ if (errors == 1)
+ sprintf(error_buffer, ERROR_DETECTED);
+ else {
+ sprintf(error_buffer, ERRORS_DETECTED, errors);
+ }
+
+ log_error(error_buffer, PLUS_STDERR);
+}
+
+void outofmem() {
+ log_error(OUT_OF_MEMORY, PLUS_STDERR);
+ error("Terminated");
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/findroute.cpp b/engines/glk/jacl/findroute.cpp
new file mode 100644
index 0000000..d05dbea
--- /dev/null
+++ b/engines/glk/jacl/findroute.cpp
@@ -0,0 +1,320 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+
+namespace Glk {
+namespace JACL {
+
+extern struct object_type *object[];
+extern int objects;
+
+/**************************************/
+/* Queue functions */
+/**************************************/
+
+struct QueueNode {
+ int val;
+ int val2;
+ struct QueueNode *next;
+};
+
+struct Queue {
+ QueueNode *head;
+ QueueNode *tail;
+};
+
+void qInit(Queue *q) {
+ q->head = q->tail = NULL;
+}
+
+void qDelete(Queue *q) {
+ QueueNode *node, *next;
+
+ for (node = q->head; node != NULL; node = next) {
+ next = node->next;
+ free(node);
+ }
+
+ q->head = q->tail = NULL;
+}
+
+int qIsEmpty(Queue *q) {
+ return (q->head == NULL);
+}
+
+void qDebug(Queue *q) {
+ debug("Queue:");
+
+ if (q->head == NULL) {
+ debug(" empty");
+ } else {
+ QueueNode *node;
+ for (node = q->head; node != NULL; node = node->next) {
+ debug(" %d (%d)", node->val, node->val2);
+ }
+ }
+
+ debug("\n");
+}
+
+void qAppend(Queue *q, int val, int val2) {
+ QueueNode *node = (QueueNode *) malloc(sizeof(QueueNode));
+ node->val = val;
+ node->val2 = val2;
+ node->next = NULL;
+
+ if (q->head == NULL) {
+ q->head = q->tail = node;
+ } else {
+ q->tail->next = node;
+ q->tail = node;
+ }
+}
+
+void qPop(Queue *q, int *val, int *val2) {
+ //assert(q->head != NULL);
+
+ *val = q->head->val;
+ *val2 = q->head->val2;
+
+ if (q->head == q->tail) {
+ q->head = q->tail = NULL;
+ } else {
+ q->head = q->head->next;
+ }
+}
+
+void qTest() {
+ int val, val2;
+ Queue q;
+
+ qInit(&q);
+ qDebug(&q);
+
+ debug("\nAdd 3, 0\n");
+ qAppend(&q, 3, 0);
+ qDebug(&q);
+
+ debug("\nAdd 4, 2\n");
+ qAppend(&q, 4, 2);
+ qDebug(&q);
+
+ debug("\nAdd 5, 1\n");
+ qAppend(&q, 5, 1);
+ qDebug(&q);
+
+ qPop(&q, &val, &val2);
+ debug("\nPop %d, %d\n", val, val2);
+ qDebug(&q);
+
+ qPop(&q, &val, &val2);
+ debug("\nPop %d, %d\n", val, val2);
+ qDebug(&q);
+
+ debug("\nAdd 6, 3\n");
+ qAppend(&q, 6, 3);
+ qDebug(&q);
+
+ debug("\nDelete all\n");
+ qDelete(&q);
+ qDebug(&q);
+}
+
+/**************************************/
+/* Set functions */
+/**************************************/
+
+/* linked list for hash table */
+struct SetNode {
+ int val;
+ struct SetNode *next;
+};
+
+#define SET_HASHSIZE 101
+
+struct Set {
+ SetNode *node[SET_HASHSIZE];
+};
+
+void setInit(Set *set) {
+ int n;
+
+ for (n = 0; n < SET_HASHSIZE; n++) {
+ set->node[n] = NULL;
+ }
+}
+
+void setDelete(Set *set) {
+ int n;
+
+ for (n = 0; n < SET_HASHSIZE; n++) {
+ SetNode *node, *next;
+
+ for (node = set->node[n]; node != NULL; node = next) {
+ next = node->next;
+ free(node);
+ }
+
+ set->node[n] = NULL;
+ }
+}
+
+void setDebug(Set *set) {
+ int n;
+
+ debug("Set:");
+
+ for (n = 0; n < SET_HASHSIZE; n++) {
+ SetNode *node;
+
+ for (node = set->node[n]; node != NULL; node = node->next) {
+ debug(" %d", node->val);
+ }
+ }
+
+ debug("\n");
+}
+
+int setHash(int val) {
+ return abs(val) % SET_HASHSIZE;
+}
+
+void setAdd(Set *set, int val) {
+ SetNode *node;
+ int n = setHash(val);
+
+ /* check if val is already in the set */
+
+ for (node = set->node[n]; node != NULL; node = node->next) {
+ if (node->val == val) {
+ return;
+ }
+ }
+
+ node = (SetNode *) malloc(sizeof(SetNode));
+ node->val = val;
+ node->next = set->node[n];
+ set->node[n] = node;
+}
+
+/* returns 1 if the set contains val, otherwise returns 0 */
+
+int setContains(Set *set, int val) {
+ SetNode *node;
+ int n = setHash(val);
+
+ for (node = set->node[n]; node != NULL; node = node->next) {
+ if (node->val == val) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void setTest() {
+ Set s;
+
+ setInit(&s);
+ setDebug(&s);
+
+ debug("\nAdd 34\n");
+ setAdd(&s, 34);
+ setDebug(&s);
+
+ debug("\nAdd 56\n");
+ setAdd(&s, 56);
+ setDebug(&s);
+
+ debug("\nAdd 34 again\n");
+ setAdd(&s, 34);
+ setDebug(&s);
+
+ debug("\nAdd %d\n", 34 + SET_HASHSIZE);
+ setAdd(&s, 34 + SET_HASHSIZE);
+ setDebug(&s);
+
+ debug("\nAdd 78\n");
+ setAdd(&s, 78);
+ setDebug(&s);
+
+ debug("\nDelete all\n");
+ setDelete(&s);
+ setDebug(&s);
+}
+
+/**************************************/
+
+#define DIR_NONE -1
+
+int find_route(int fromRoom, int toRoom, int known) {
+ Set visited;
+ Queue q;
+ int firstTime;
+ int result = DIR_NONE;
+
+ setInit(&visited);
+ qInit(&q);
+
+ qAppend(&q, fromRoom, DIR_NONE);
+ setAdd(&visited, fromRoom);
+ firstTime = 1;
+
+ while (!qIsEmpty(&q)) {
+ int n, dir, firstDir;
+ qPop(&q, &n, &firstDir);
+
+ if (n == toRoom) {
+ result = firstDir;
+ break;
+ }
+
+ for (dir = 0; dir < 12 ; dir++) {
+ int dest = object[n]->integer[dir];
+
+ if (dest < 1 || dest > objects) continue;
+
+ if (object[dest] == NULL) continue;
+
+ if (dest != NOWHERE && !setContains(&visited, dest)) {
+ if (!known || (object[dest]->attributes & KNOWN)) {
+ qAppend(&q, dest, (firstTime ? dir : firstDir));
+ setAdd(&visited, dest);
+ }
+ }
+ }
+
+ firstTime = 0;
+ }
+
+ setDelete(&visited);
+ qDelete(&q);
+
+ return result;
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/glk_saver.cpp b/engines/glk/jacl/glk_saver.cpp
new file mode 100644
index 0000000..abd718f
--- /dev/null
+++ b/engines/glk/jacl/glk_saver.cpp
@@ -0,0 +1,272 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+
+namespace Glk {
+namespace JACL {
+
+extern struct object_type *object[];
+extern struct integer_type *integer_table;
+extern struct integer_type *integer[];
+extern struct function_type *function_table;
+extern struct string_type *string_table;
+
+extern schanid_t sound_channel[];
+
+extern char temp_buffer[];
+
+extern int objects;
+extern int integers;
+extern int functions;
+extern int strings;
+extern int player;
+
+extern int it;
+extern int them[];
+extern int her;
+extern int him;
+extern int parent;
+
+extern int noun[];
+
+int save_game(frefid_t saveref) {
+ struct integer_type *current_integer = integer_table;
+ struct function_type *current_function = function_table;
+ struct string_type *current_string = string_table;
+
+ int index, counter;
+ strid_t bookmark = NULL;
+
+ bookmark = g_vm->glk_stream_open_file(saveref, filemode_Write, 0);
+
+ if (bookmark == NULL) {
+ return (FALSE);
+ }
+
+ /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
+ * HAS BEEN SUCCESSFULLY OPENED */
+ g_vm->glk_fileref_destroy(saveref);
+
+ /* THIS IS WRITTEN TO HELP VALIDATE THE SAVED GAME
+ * BEFORE CONTINUING TO LOAD IT */
+ write_integer(bookmark, objects);
+ write_integer(bookmark, integers);
+ write_integer(bookmark, functions);
+ write_integer(bookmark, strings);
+
+ while (current_integer != NULL) {
+ write_integer(bookmark, current_integer->value);
+ current_integer = current_integer->next_integer;
+ }
+
+ while (current_function != NULL) {
+ write_integer(bookmark, current_function->call_count);
+ current_function = current_function->next_function;
+ }
+
+ for (index = 1; index <= objects; index++) {
+ if (object[index]->nosave)
+ continue;
+
+ for (counter = 0; counter < 16; counter++) {
+ write_integer(bookmark, object[index]->integer[counter]);
+ }
+
+ write_long(bookmark, object[index]->attributes);
+ write_long(bookmark, object[index]->user_attributes);
+ }
+
+ /* WRITE OUT ALL THE CURRENT VALUES OF THE STRING VARIABLES */
+ while (current_string != NULL) {
+ for (index = 0; index < 255; index++) {
+ g_vm->glk_put_char_stream(bookmark, current_string->value[index]);
+ }
+ current_string = current_string->next_string;
+ }
+
+ write_integer(bookmark, player);
+ write_integer(bookmark, noun[3]);
+
+ /* SAVE THE CURRENT VOLUME OF EACH OF THE SOUND CHANNELS */
+ for (index = 0; index < 8; index++) {
+ sprintf(temp_buffer, "volume[%d]", index);
+ write_integer(bookmark, cinteger_resolve(temp_buffer)->value);
+ }
+
+ /* SAVE THE CURRENT VALUE OF THE GLK TIMER */
+ write_integer(bookmark, cinteger_resolve("timer")->value);
+
+ /* CLOSE THE STREAM */
+ g_vm->glk_stream_close(bookmark, NULL);
+
+ TIME->value = FALSE;
+ return (TRUE);
+}
+
+int restore_game(frefid_t saveref, int warn) {
+ struct integer_type *current_integer = integer_table;
+ struct function_type *current_function = function_table;
+ struct string_type *current_string = string_table;
+
+ int index, counter;
+ int file_objects,
+ file_integers,
+ file_functions,
+ file_strings;
+ strid_t bookmark;
+
+ bookmark = g_vm->glk_stream_open_file(saveref, filemode_Read, 0);
+
+ if (!bookmark) {
+ return (FALSE);
+ }
+
+ /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
+ * HAS BEEN SUCCESSFULLY OPENED */
+ g_vm->glk_fileref_destroy(saveref);
+
+ /* THIS IS WRITTEN TO HELP VALIDATE THE SAVED GAME
+ * BEFORE CONTINUING TO LOAD IT */
+ file_objects = read_integer(bookmark);
+ file_integers = read_integer(bookmark);
+ file_functions = read_integer(bookmark);
+ file_strings = read_integer(bookmark);
+
+ if (file_objects != objects
+ || file_integers != integers
+ || file_functions != functions
+ || file_strings != strings) {
+ if (warn == FALSE) {
+ log_error(cstring_resolve("BAD_SAVED_GAME")->value, PLUS_STDOUT);
+ }
+ g_vm->glk_stream_close(bookmark, NULL);
+ return (FALSE);
+ }
+
+ while (current_integer != NULL) {
+ current_integer->value = read_integer(bookmark);
+ current_integer = current_integer->next_integer;
+ }
+
+ while (current_function != NULL) {
+ current_function->call_count = read_integer(bookmark);
+ current_function = current_function->next_function;
+ }
+
+ for (index = 1; index <= objects; index++) {
+ if (object[index]->nosave)
+ continue;
+
+ for (counter = 0; counter < 16; counter++) {
+ object[index]->integer[counter] = read_integer(bookmark);
+ }
+
+ object[index]->attributes = read_integer(bookmark);
+ object[index]->user_attributes = read_integer(bookmark);
+ }
+
+ while (current_string != NULL) {
+ for (index = 0; index < 255; index++) {
+ current_string->value[index] = g_vm->glk_get_char_stream(bookmark);
+ }
+ current_string = current_string->next_string;
+ }
+
+ player = read_integer(bookmark);
+ noun[3] = read_integer(bookmark);
+
+ /* RESTORE THE CURRENT VOLUME OF EACH OF THE SOUND CHANNELS */
+ for (index = 0; index < 8; index++) {
+ sprintf(temp_buffer, "volume[%d]", index);
+ counter = read_integer(bookmark);
+ cinteger_resolve(temp_buffer)->value = counter;
+
+ if (SOUND_SUPPORTED->value) {
+ /* SET THE GLK VOLUME */
+ g_vm->glk_schannel_set_volume(sound_channel[index], (glui32) counter);
+ }
+ }
+
+ /* RESTORE THE CURRENT VALUE OF THE GLK TIMER */
+ counter = read_integer(bookmark);
+ cinteger_resolve("timer")->value = counter;
+
+ /* SET THE GLK TIMER */
+ g_vm->glk_request_timer_events((glui32) counter);
+
+ /* CLOSE THE STREAM */
+ g_vm->glk_stream_close(bookmark, NULL);
+
+ TIME->value = FALSE;
+ return (TRUE);
+}
+
+void write_integer(strid_t stream, int x) {
+ unsigned char c;
+
+ c = (unsigned char)(x) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 8) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 16) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 24) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+}
+
+int read_integer(strid_t stream) {
+ int a, b, c, d;
+ a = (int) g_vm->glk_get_char_stream(stream);
+ b = (int) g_vm->glk_get_char_stream(stream);
+ c = (int) g_vm->glk_get_char_stream(stream);
+ d = (int) g_vm->glk_get_char_stream(stream);
+ return a | (b << 8) | (c << 16) | (d << 24);
+}
+
+void write_long(strid_t stream, long x) {
+ unsigned char c;
+
+ c = (unsigned char)(x) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 8) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 16) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+ c = (unsigned char)(x >> 24) & 0xFF;
+ g_vm->glk_put_char_stream(stream, c);
+}
+
+long read_long(strid_t stream) {
+ long a, b, c, d;
+ a = (long) g_vm->glk_get_char_stream(stream);
+ b = (long) g_vm->glk_get_char_stream(stream);
+ c = (long) g_vm->glk_get_char_stream(stream);
+ d = (long) g_vm->glk_get_char_stream(stream);
+ return a | (b << 8) | (c << 16) | (d << 24);
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/glk_startup.cpp b/engines/glk/jacl/glk_startup.cpp
new file mode 100644
index 0000000..b49a6cd
--- /dev/null
+++ b/engines/glk/jacl/glk_startup.cpp
@@ -0,0 +1,166 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/constants.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/prototypes.h"
+#include "glk/jacl/version.h"
+#include "glk/glk_api.h"
+#include "glk/streams.h"
+
+namespace Glk {
+namespace JACL {
+
+int jpp_error = FALSE;
+
+extern strid_t game_stream;
+extern char game_file[];
+extern char temp_buffer[];
+extern char error_buffer[];
+extern char processed_file[];
+
+short int encrypt;
+extern short int release;
+
+struct glkunix_startup_t {
+ int argc;
+ char **argv;
+};
+
+struct glkunix_argumentlist_t {
+ const char *_switch;
+ int _value;
+ const char *_description;
+};
+
+glkunix_startup_t *arguments;
+
+/* THE STREAM FOR OPENING UP THE ARCHIVE CONTAINING GRAPHICS AND SOUND */
+extern strid_t blorb_stream;
+
+/* PROTOTYPE FOR NEEDED UTILITY FUNCTION */
+void create_paths();
+
+#ifdef UNUSED
+glkunix_argumentlist_t glkunix_arguments[] = {
+ {"", glkunix_arg_ValueFollows, "filename: The game file to load." },
+
+ {"-noencrypt", glkunix_arg_NoValue, "-noencrypt: Don't encrypt the processed game file."},
+ {"-release", glkunix_arg_NoValue, "-release: Don't include the debug libraries in the .j2 file."},
+ { NULL, glkunix_arg_End, NULL }
+};
+
+int glkunix_startup_code(glkunix_startup_t *data) {
+ int index = 0;
+
+ arguments = data;
+
+#ifdef GARGLK
+ sprintf(temp_buffer, "JACL %d.%d.%d", J_VERSION, J_RELEASE, J_BUILD);
+ garglk_set_program_name(temp_buffer);
+ sprintf(temp_buffer, "JACL %d.%d.%d by Stuart Allen.\n", J_VERSION, J_RELEASE, J_BUILD);
+ garglk_set_program_info(temp_buffer);
+#endif
+
+ /* YOU CAN PUT OTHER STARTUP CODE IN glkunix_startup_code(). THIS SHOULD
+ * GENERALLY BE LIMITED TO FINDING AND OPENING DATA FILES. */
+
+ if (arguments->argc == 1) {
+ sprintf(error_buffer, "%s^", NO_GAME);
+ jpp_error = TRUE;
+
+ /* WE NEED TO RETURN TRUE HERE SO THE INTERPRETER WILL OPEN A
+ * GLK WINDOWS TO DISPLAY THE ERROR MESSAGE IN */
+ return (TRUE);
+ } else {
+ strcpy(temp_buffer, arguments->argv[1]);
+
+ /* THERE IS AT LEAST ONE ARGUMENT, POSSIBLY JUST THE GAME FILE, BUT
+ * LOOK THROUGH THE LIST FOR ANYTHING THAT NEEDS ACTING ON */
+ for (index = 0; index < data->argc; index++) {
+ if (!strcmp(*data->argv, "-noencrypt")) {
+ encrypt = FALSE;
+ } else if (!strcmp(*data->argv, "-release")) {
+ release = TRUE;
+ }
+
+ /* INCREMENT THE POINTER TO THE NEXT ARGUMENT */
+ data->argv++;
+ }
+ }
+
+ /* SETUP ALL THE EXPECTED PATHS */
+ //create_paths(temp_buffer);
+
+ /* PREPROCESS THE FILE AND WRITE IT OUT TO THE NEW FILE */
+ /* WARNING: THIS FUNCTION USES stdio FUNCTIONS TO CREATE FILES
+ * IN SUBDIRECTORIES. IT IS PORTABLE ACROSS MODERN DESKTOPS, IE
+ * WINDOWS, MAC, UNIX ETC, BUT IT'S NOT GLK CODE... */
+ if (jpp() == FALSE) {
+ jpp_error = TRUE;
+
+ /* WE NEED TO RETURN TRUE HERE SO THE INTERPRETER WILL OPEN A
+ * GLK WINDOWS TO DISPLAY THE ERROR MESSAGE IN */
+ return (TRUE);
+ }
+
+ /* THIS OPENS AN ARBITRARY FILE, IN READ-ONLY MODE. NOTE THAT THIS FUNCTION
+ * IS *ONLY* AVAILABLE DURING glkunix_startup_code(). IT IS INHERENT
+ * NON-PORTABLE; IT SHOULD NOT AND CANNOT BE CALLED FROM INSIDE
+ * glk_main() NOTE: The middle argument FALSE indicates a binary file. */
+ game_stream = glkunix_stream_open_pathname(processed_file, FALSE, 0);
+
+ if (!game_stream) {
+ strcpy(error_buffer, NOT_FOUND);
+ jpp_error = TRUE;
+
+ /* WE NEED TO RETURN TRUE HERE SO THE INTERPRETER WILL OPEN A
+ * GLK WINDOWS TO DISPLAY THE ERROR MESSAGE IN */
+ return (TRUE);
+ }
+
+ /* SET THE LIBRARY'S IDEA OF THE "CURRENT DIRECTORY" FOR THE EXECUTING
+ * PROGRAM. THE ARGUMENT SHOULD BE THE NAME OF A FILE (NOT A DIRECTORY).
+ * WHEN THIS IS SET, fileref_create_by_name() WILL CREATE FILES IN THE SAME
+ * DIRECTORY AS THAT FILE, AND create_by_prompt() WILL BASE DEFAULT
+ * FILENAMES OFF OF THE FILE. IF THIS IS NOT CALLED, THE LIBRARY WORKS IN
+ * THE UNIX CURRENT WORKING DIRECTORY, AND PICKS REASONABLE DEFAULT
+ * DEFAULTS. */
+ glkunix_set_base_file(game_file);
+
+ /* Set title of game */
+#ifdef GARGLK
+ char *s;
+ s = strrchr(game_file, '\\');
+ if (!s) s = strrchr(game_file, '/');
+ garglk_set_story_name(s ? s + 1 : game_file);
+#endif
+
+ /* RETURN TRUE ERRORS OR NOT SO THE MAIN WINDOWS CAN BE OPENED AND
+ * ANY ERROR MESSAGE DISPLAYED */
+ return (TRUE);
+}
+#endif
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
new file mode 100644
index 0000000..47c07c8
--- /dev/null
+++ b/engines/glk/jacl/interpreter.cpp
@@ -0,0 +1,3458 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+#include "glk/jacl/csv.h"
+#include "common/str.h"
+
+namespace Glk {
+namespace JACL {
+
+#ifdef WIN32
+struct flock {
+ short l_type;
+ short l_whence;
+ long l_start;
+ long l_len;
+ long l_pid;
+};
+
+#define F_DUPFD 0
+#define F_GETFD 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define F_GETLK 5
+#define F_SETLK 6
+#define F_SETLKW 7
+
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+int fcntl(int __fd, int __cmd, ...) {
+ return 0;
+}
+#endif /* WIN32 */
+
+#ifndef strcasestr
+char *strcasestr(const char *s, const char *find) {
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = (char)tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (scumm_strnicmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
+#endif
+
+#define MAX_TRY 10
+
+struct flock read_lck;
+int read_fd;
+struct flock write_lck;
+int write_fd;
+
+char *url_encode(char *str);
+char to_hex(char code);
+
+char *location_attributes[] = {
+ "VISITED ", "DARK ", "ON_WATER ", "UNDER_WATER ", "WITHOUT_AIR ", "OUTDOORS ",
+ "MID_AIR ", "TIGHT_ROPE ", "POLLUTED ", "SOLVED ", "MID_WATER ", "DARKNESS ",
+ "MAPPED ", "KNOWN ",
+ NULL
+};
+
+char *object_attributes[] = {
+ "CLOSED ", "LOCKED ", "DEAD ", "IGNITABLE ", "WORN ", "CONCEALING ",
+ "LUMINOUS ", "WEARABLE ", "CLOSABLE ", "LOCKABLE ", "ANIMATE ", "LIQUID ",
+ "CONTAINER ", "SURFACE ", "PLURAL ", "FLAMMABLE ", "BURNING ", "LOCATION ",
+ "ON ", "DAMAGED ", "FEMALE ", "POSSESSIVE ", "OUT_OF_REACH ", "TOUCHED ",
+ "SCORED ", "SITTING ", "NPC ", "DONE ", "GAS ", "NO_TAB ",
+ "NOT_IMPORTANT ", NULL
+};
+
+char *object_elements[] = {
+ "parent", "capacity", "mass", "bearing", "velocity", "next", "previous",
+ "child", "index", "status", "state", "counter", "points", "class", "x", "y",
+ NULL
+};
+
+char *location_elements[] = {
+ "north", "south", "east", "west", "northeast", "northwest", "southeast",
+ "southwest", "up", "down", "in", "out", "points", "class", "x", "y",
+ NULL
+};
+
+struct csv_parser parser_csv;
+char in_name[1024];
+char out_name[1024];
+Common::SeekableReadStream *infile;
+Common::WriteStream *outfile;
+
+int stack = 0;
+int proxy_stack = 0;
+
+int field_no = 0;
+
+struct stack_type backup[STACK_SIZE];
+struct proxy_type proxy_backup[STACK_SIZE];
+
+struct function_type *resolved_function = NULL;
+struct string_type *resolved_string = NULL;
+
+struct string_type *new_string = NULL;
+struct string_type *current_cstring = NULL;
+struct string_type *previous_cstring = NULL;
+
+struct cinteger_type *new_cinteger = NULL;
+struct cinteger_type *current_cinteger = NULL;
+struct cinteger_type *previous_cinteger = NULL;
+
+long bit_mask;
+extern int encrypted;
+extern int after_from;
+extern int last_exact;
+
+extern char temp_directory[];
+extern char data_directory[];
+char csv_buffer[1024];
+
+int resolved_attribute;
+
+/* THE ITERATION VARIABLE USED FOR LOOPS */
+int *loop_integer = NULL;
+int *select_integer = NULL;
+
+int criterion_value = 0;
+int criterion_type = 0;
+int criterion_negate = FALSE;
+int current_level;
+int execution_level;
+int *ask_integer;
+int new_x;
+int new_y;
+
+int interrupted = FALSE;
+char string_buffer[2048];
+char argument_buffer[1024];
+#ifdef GLK
+extern schanid_t sound_channel[];
+extern strid_t game_stream;
+extern winid_t mainwin;
+extern winid_t statuswin;
+extern winid_t current_window;
+
+extern strid_t mainstr;
+extern strid_t statusstr;
+extern strid_t quotestr;
+extern strid_t inputstr;
+int top_of_loop = 0;
+int top_of_select = 0;
+int top_of_while = 0;
+int top_of_iterate = 0;
+int top_of_update = 0;
+int top_of_do_loop = 0;
+#else
+extern FILE *file;
+char option_buffer[2024];
+int style_stack[100];
+int style_index = 0;
+long top_of_loop = 0;
+long top_of_select = 0;
+long top_of_while = 0;
+long top_of_iterate = 0;
+long top_of_update = 0;
+long top_of_do_loop = 0;
+
+#endif
+
+#ifdef __NDS__
+extern int bold_mode;
+extern int pre_mode;
+extern int reverse_mode;
+extern int input_mode;
+extern int subheader_mode;
+extern int note_mode;
+#endif
+
+extern char user_id[];
+extern char prefix[];
+extern char text_buffer[];
+extern char chunk_buffer[];
+extern char *word[];
+
+extern char bookmark[];
+extern char file_prompt[];
+
+/* CONTAINED IN PARSER.C */
+extern int object_list[4][MAX_WORDS];
+extern int list_size[];
+extern int max_size[];
+
+/* CONTAINED IN ENCAPSULATE.C */
+extern int quoted[];
+
+extern struct object_type *object[];
+extern struct integer_type *integer_table;
+extern struct integer_type *integer[];
+extern struct cinteger_type *cinteger_table;
+extern struct attribute_type *attribute_table;
+extern struct string_type *string_table;
+extern struct string_type *cstring_table;
+extern struct function_type *function_table;
+extern struct function_type *executing_function;
+extern struct command_type *completion_list;
+extern struct word_type *grammar_table;
+extern struct synonym_type *synonym_table;
+extern struct filter_type *filter_table;
+
+extern char function_name[];
+extern char temp_buffer[];
+extern char error_buffer[];
+extern char proxy_buffer[];
+
+extern char default_function[];
+extern char override[];
+
+extern int noun[];
+extern int wp;
+extern int start_of_this_command;
+extern int start_of_last_command;
+extern int buffer_index;
+extern int objects;
+extern int integers;
+extern int player;
+extern int oec;
+extern int *object_element_address;
+extern int *object_backup_address;
+extern int walkthru_running;
+
+// VALUES FROM LOADER
+extern int value_resolved;
+
+extern Common::WriteStream *transcript;
+extern char margin_string[];
+
+char integer_buffer[16];
+char called_name[1024];
+char scope_criterion[24];
+char *output;
+
+void terminate(int code) {
+ // FREE ANY EXTRA RAM ALLOCATED BY THE CSV PARSER
+ csv_free(&parser_csv);
+
+#ifdef GLK
+ int index;
+ event_t event;
+
+ // FLUSH THE GLK WINDOW SO THE ERROR GETS DISPLAYED IMMEDIATELY.
+ g_vm->glk_select_poll(&event);
+
+ /* CLOSE THE SOUND CHANNELS */
+ for (index = 0; index < 8; index++) {
+ if (sound_channel[index] != NULL) {
+ g_vm->glk_schannel_destroy(sound_channel[index]);
+ }
+ }
+
+ /* CLOSE THE STREAM */
+ if (game_stream != NULL) {
+ g_vm->glk_stream_close(game_stream, NULL);
+ }
+
+ g_vm->glk_exit();
+#else
+ if (file != NULL) /* CLOSE THE GAME FILE */
+ fclose(file);
+
+ exit(code);
+#endif
+}
+
+void build_proxy() {
+ int index;
+
+ proxy_buffer[0] = 0;
+
+ /* LOOP THROUGH ALL THE PARAMETERS OF THE PROXY COMMAND
+ AND BUILD THE MOVE TO BE ISSUED ON THE PLAYER'S BEHALF */
+ for (index = 1; word[index] != NULL; index++) {
+ strcat(proxy_buffer, text_of_word(index));
+ }
+
+ for (index = 0; index < (int)strlen(proxy_buffer); index++) {
+ if (proxy_buffer[index] == '~') {
+ proxy_buffer[index] = '\"';
+ }
+ }
+
+ //printf("--- proxy buffer = \"%s\"\n", proxy_buffer);
+}
+
+void cb1(void *s, size_t i, void *not_used) {
+ struct string_type *resolved_cstring;
+
+ //sprintf (temp_buffer, "Trying to set field %d to equal %s^", field_no, (char *) s);
+ //write_text(temp_buffer);
+
+ sprintf(temp_buffer, "field[%d]", field_no);
+
+ if ((resolved_cstring = cstring_resolve(temp_buffer)) != NULL) {
+ //write_text("Resolved ");
+ //write_text(temp_buffer);
+ //write_text("^");
+ strncpy(resolved_cstring->value, (const char *)s, i);
+ resolved_cstring->value[i] = 0;
+ //sprintf(temp_buffer, "Setting field %d to ~%s~^", field_no, (char *) s);
+ //write_text(temp_buffer);
+ // INCREMENT THE FIELD NUMBER SO THE NEXT ONE GETS STORED IN THE RIGHT CONSTANT
+ field_no++;
+ } else {
+ write_text("Can't resolve ");
+ write_text(temp_buffer);
+ write_text("^");
+ }
+
+}
+
+void cb2(int c, void *not_used) {
+ // THE END OF THE RECORD HAS BEEN REACHED, EXPORT THE NUMBER OF FIELDS READ
+ struct cinteger_type *resolved_cinteger;
+
+ if ((resolved_cinteger = cinteger_resolve("field_count")) != NULL) {
+ resolved_cinteger->value = field_no;
+ }
+}
+
+int execute(char *funcname) {
+ int index;
+ int counter;
+ int *container;
+
+ int object_1,
+ object_2;
+
+ /* THESE VARIABLE KEEP TRACK OF if AND endif COMMANDS TO DECIDE WHETHER
+ *THE CURRENT LINE OF CODE SHOULD BE EXECUTED OR NOT */
+ int currentLevel = 0;
+ int executionLevel = 0;
+
+ /* THESE ARE USED AS FILE POINTER OFFSETS TO RETURN TO FIXED
+ * POINTS IN THE GAME FILE */
+#ifdef GLK
+ int result;
+ int before_command = 0;
+#else
+ long before_command = 0;
+#endif
+
+
+ strncpy(called_name, funcname, 1023);
+
+ /* GET THE FUNCTION OBJECT BY THE FUNCTION NAME */
+ resolved_function = function_resolve(called_name);
+
+ if (resolved_function == NULL) {
+ //printf("--- failed to find %s\n", called_name);
+ return (FALSE);
+ }
+
+#ifdef GLK
+ push_stack(g_vm->glk_stream_get_position(game_stream));
+#else
+ push_stack(ftell(file));
+#endif
+
+ top_of_loop = 0;
+ top_of_select = 0;
+ top_of_while = 0;
+ top_of_iterate = 0;
+ top_of_update = 0;
+ top_of_do_loop = 0;
+
+ executing_function = resolved_function;
+ executing_function->call_count++;
+
+ // CREATE ALL THE PASSED ARGUMENTS AS JACL INTEGER CONSTANTS
+ set_arguments(called_name);
+
+ // SET function_name TO THE CORE NAME STORED IN THE FUNCTION OBJECT
+ // LEAVING called_name TO CONTAIN THE FULL ARGUMENT LIST
+ strncpy(function_name, executing_function->name, 80);
+ strncpy(cstring_resolve("function_name")->value, executing_function->name, 80);
+
+ //sprintf(temp_buffer, "--- starting to execute %s^", function_name);
+ //write_text(temp_buffer);
+
+ // JUMP TO THE POINT IN THE PROCESSED GAME FILE WHERE THIS FUNCTION STARTS
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, executing_function->position, seekmode_Start);
+ before_command = executing_function->position;
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fseek(file, executing_function->position, SEEK_SET);
+ before_command = executing_function->position;
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+ while (text_buffer[0] != 125 && !interrupted) {
+ encapsulate();
+ if (word[0] == NULL);
+ else if (!strcmp(word[0], "endwhile")) {
+ currentLevel--;
+ if (currentLevel < executionLevel) {
+ // THIS ENDWHILE COMMAND WAS BEING EXECUTED,
+ // NOT JUST COUNTED.
+ if (top_of_while == FALSE) {
+ sprintf(error_buffer, NO_WHILE, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_while, seekmode_Start);
+#else
+ fseek(file, top_of_while, SEEK_SET);
+#endif
+ executionLevel = currentLevel;
+ }
+ }
+ } else if (!strcmp(word[0], "enditerate")) {
+ currentLevel--;
+ if (currentLevel < executionLevel) {
+ // THIS ENDITERATE COMMAND WAS BEING EXECUTED,
+ // NOT JUST COUNTED.
+ if (top_of_iterate == FALSE) {
+ sprintf(error_buffer, NO_ITERATE, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_iterate, seekmode_Start);
+#else
+ fseek(file, top_of_iterate, SEEK_SET);
+#endif
+ executionLevel = currentLevel;
+ }
+ }
+ } else if (!strcmp(word[0], "endupdate")) {
+ currentLevel--;
+ if (currentLevel < executionLevel) {
+ // THIS ENDUPDATE COMMAND WAS BEING EXECUTED,
+ // NOT JUST COUNTED.
+ if (top_of_update == FALSE) {
+ sprintf(error_buffer, NO_UPDATE, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_update, seekmode_Start);
+#else
+ fseek(file, top_of_update, SEEK_SET);
+#endif
+ executionLevel = currentLevel;
+ }
+ }
+ } else if (!strcmp(word[0], "print") && currentLevel != executionLevel) {
+ // SKIP THIS BLOCK OF PLAIN TEXT UNTIL IT FINDS A
+ // LINE THAT STARTS WITH A '.' OR A '}'
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+ while (text_buffer[0] != '.') {
+ if (text_buffer[0] == '}') {
+ // HIT THE END OF THE FUNCTION, JUST BAIL OUT
+ return (exit_function(TRUE));
+ }
+
+ // GET THE NEXT LINE
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+ }
+ } else if (!strcmp(word[0], "endif")) {
+ currentLevel--;
+ if (currentLevel < executionLevel) {
+ /* THIS SHOULD NEVER HAPPEN */
+ executionLevel = currentLevel;
+ }
+ } else if (!strcmp(word[0], "endall")) {
+ currentLevel = 0;
+ executionLevel = 0;
+ } else if (!strcmp(word[0], "else")) {
+ if (currentLevel == executionLevel) {
+ executionLevel--;
+ } else if (currentLevel == executionLevel + 1) {
+ executionLevel++;
+ }
+ } else if (currentLevel == executionLevel) {
+ if (!strcmp(word[0], "look")) {
+ // THIS IS JUST HERE FOR BACKWARDS COMPATIBILITY
+ object[HERE]->attributes &= ~1L;
+ look_around();
+ } else if (!strcmp(word[0], "repeat")) {
+#ifdef GLK
+ top_of_do_loop = g_vm->glk_stream_get_position(game_stream);
+#else
+ top_of_do_loop = ftell(file);
+#endif
+ } else if (!strcmp(word[0], "until")) {
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (top_of_do_loop == FALSE) {
+ sprintf(error_buffer, NO_REPEAT, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else if (!condition()) {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_do_loop, seekmode_Start);
+#else
+ fseek(file, top_of_do_loop, SEEK_SET);
+#endif
+ }
+ }
+ } else if (!strcmp(word[0], "untilall")) {
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (top_of_do_loop == FALSE) {
+ sprintf(error_buffer, NO_REPEAT, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else if (!and_condition()) {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_do_loop, seekmode_Start);
+#else
+ fseek(file, top_of_do_loop, SEEK_SET);
+#endif
+
+ }
+ }
+ } else if (!strcmp(word[0], "iterate")) {
+ int i;
+
+ // A NEW iterate LOOP MEANS STARTING BACK AT THE FIRST FIELD
+ field_no = 0;
+
+ currentLevel++;
+ /* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
+ EXECUTING, NOT THE LINE AFTER */
+
+ top_of_iterate = before_command;
+
+ // infile REMAINS OPEN DURING THE ITERATION, ONLY NEEDS
+ // OPENING THE FIRST TIME
+ if (infile == NULL) {
+ strcpy(temp_buffer, data_directory);
+ strcat(temp_buffer, prefix);
+ strcat(temp_buffer, "-");
+ strcat(temp_buffer, text_of_word(1));
+ strcat(temp_buffer, ".csv");
+
+ infile = File::openForReading(temp_buffer);
+
+ if (word[2] != NULL && !strcmp(word[2], "skip_header")) {
+ assert(infile);
+ infile->read(csv_buffer, 1024);
+ }
+ }
+
+ if (infile == NULL) {
+ sprintf(error_buffer, "Failed to open file %s: %s\n", temp_buffer, strerror(errno));
+ log_error(error_buffer, LOG_ONLY);
+ infile = NULL;
+ } else {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ // IF THERE IS ANOTHER RECORD TO READ FROM THE CSV FILE THEN
+ // SET THE field[] CONSTANTS AND INCREMENT THE executionLevel
+ infile->read(csv_buffer, 1024);
+
+ if (infile->pos() < infile->size()) {
+ i = strlen(csv_buffer);
+ //sprintf (temp_buffer, "Read ~%s~ with %d bytes.^", csv_buffer, i);
+ //write_text(temp_buffer);
+ if (csv_parse(&parser_csv, csv_buffer, i, cb1, cb2, (void *) NULL) != (uint)i) {
+ sprintf(error_buffer, "Error parsing file: %s\n", csv_strerror(csv_error(&parser_csv)));
+ log_error(error_buffer, PLUS_STDOUT);
+ delete infile;
+ infile = NULL;
+ } else {
+ // A LINE HAS BEEN SUCCESSFULLY READ, EXECUTE THE CONTENTS OF THE LOOP
+ executionLevel++;
+ }
+ } else {
+ delete infile;
+ infile = NULL;
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "update")) {
+ int i;
+
+ // SET UP THE RECORD LOCKING STRUCTURE, THE ADDRESS OF WHICH
+ // IS PASSED TO THE fcntl() SYSTEM CALL
+ write_lck.l_type = F_WRLCK; // SETTING A WRITE LOCK
+ write_lck.l_whence = 0; // OFFSET l_start FROM BEGINNING OF FILE
+ write_lck.l_start = 0LL;
+ write_lck.l_len = 0LL; // UNTIL THE END OF THE FILE ADDRESS SPACE
+
+ read_lck.l_type = F_RDLCK; // SETTING A READ LOCK
+ read_lck.l_whence = 0; // OFFSET l_start FROM BEGINNING OF FILE
+ read_lck.l_start = 0LL;
+ read_lck.l_len = 0LL; // UNTIL THE END OF THE FILE ADDRESS SPACE
+
+ // A NEW iterate LOOP MEANS STARTING BACK AT THE FIRST FIELD
+ field_no = 0;
+
+ currentLevel++;
+ // THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
+ // EXECUTING, NOT THE LINE AFTER
+
+ top_of_update = before_command;
+
+ // infile REMAINS OPEN DURING THE ITERATION, ONLY NEEDS
+ // OPENING THE FIRST TIME
+ if (infile == NULL) {
+ strcpy(in_name, data_directory);
+ strcat(in_name, prefix);
+ strcat(in_name, "-");
+ strcat(in_name, text_of_word(1));
+ strcat(in_name, ".csv");
+
+ infile = File::openForReading(in_name);
+ }
+
+ if (outfile == NULL) {
+ // OPEN A TEMPORARY OUTPUT FILE TO WRITE THE MODIFICATIONS TO
+ strcpy(out_name, data_directory);
+ strcat(out_name, prefix);
+ strcat(out_name, "-");
+ strcat(out_name, text_of_word(1));
+ strcat(out_name, "-");
+ strcat(out_name, user_id);
+ strcat(out_name, ".csv");
+
+ outfile = File::openForWriting(out_name);
+ }
+
+ if (infile == NULL) {
+ sprintf(error_buffer, "Failed to open input CSV file ~%s~: %s\n", in_name, strerror(errno));
+ log_error(error_buffer, LOG_ONLY);
+ if (outfile != NULL) {
+ delete outfile;
+ outfile = NULL;
+ }
+ return (exit_function(TRUE));
+ } else {
+ if (outfile == NULL) {
+ sprintf(error_buffer, "Failed to open output CSV file ~%s~: %s\n", out_name, strerror(errno));
+ log_error(error_buffer, LOG_ONLY);
+ if (infile != NULL) {
+ delete infile;
+ infile = NULL;
+ }
+ return (exit_function(TRUE));
+ } else {
+#ifdef FILE_CTL
+ int tryCtr = 0;
+ write_fd = fileno(outfile);
+ // ATTEMPT LOCKING OUTPUT FILE MAX_TRY TIMES BEFORE GIVING UP.
+ while (fcntl(write_fd, F_SETLK, &write_lck) < 0) {
+ if (errno == EAGAIN || errno == EACCES) {
+ // THERE MIGHT BE OTHER ERROR CASES IN WHICH
+ // USERS MIGHT TRY AGAIN
+ if (++tryCtr < MAX_TRY) {
+ jacl_sleep(1000);
+ continue;
+ }
+ sprintf(error_buffer, "File busy unable to get lock on output file.\n");
+ log_error(error_buffer, PLUS_STDOUT);
+ return (exit_function(TRUE));
+ }
+ }
+
+ tryCtr = 0;
+
+ read_fd = fileno(infile);
+ // ATTEMPT LOCKING OUTPUT FILE MAX_TRY TIMES BEFORE GIVING UP.
+ while (fcntl(read_fd, F_SETLK, &read_lck) < 0) {
+ if (errno == EAGAIN || errno == EACCES) {
+ // THERE MIGHT BE OTHER ERROR CASES IN WHICH
+ // USERS MIGHT TRY AGAIN
+ if (++tryCtr < MAX_TRY) {
+ jacl_sleep(1000);
+ continue;
+ }
+ sprintf(error_buffer, "File busy unable to get lock on input file.\n");
+ log_error(error_buffer, PLUS_STDOUT);
+ return (exit_function(TRUE));
+ }
+ }
+#endif
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ // IF THERE IS ANOTHER RECORD TO READ FROM THE CSV FILE THEN
+ // SET THE field[] CONSTANTS AND INCREMENT THE executionLevel
+ infile->read(csv_buffer, 1024);
+ if (infile->pos() < infile->size()) {
+ i = strlen(csv_buffer);
+ if (csv_parse(&parser_csv, csv_buffer, i, cb1, cb2, (int *) &field_no) != (uint)i) {
+ sprintf(error_buffer, "Error parsing file: %s\n", csv_strerror(csv_error(&parser_csv)));
+ log_error(error_buffer, PLUS_STDOUT);
+ read_lck.l_type = F_UNLCK; // SETTING A READ LOCK
+ fcntl(read_fd, F_SETLK, &read_lck);
+ delete infile;
+ infile = NULL;
+ } else {
+ // A LINE HAS BEEN SUCCESSFULLY READ, EXECUTE THE CONTENTS OF THE LOOP
+ executionLevel++;
+ }
+ } else {
+ write_lck.l_type = F_UNLCK; // REMOVE THE WRITE LOCK
+ fcntl(write_fd, F_SETLK, &write_lck);
+ delete outfile;
+
+ read_lck.l_type = F_UNLCK; // REMOVE THE READ LOCK
+ fcntl(read_fd, F_SETLK, &read_lck);
+ delete infile;
+
+ rename(out_name, in_name);
+
+ outfile = NULL;
+ infile = NULL;
+ }
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "while")) {
+ currentLevel++;
+ /* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
+ EXECUTING, NOT THE LINE AFTER */
+ top_of_while = before_command;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else if (condition()) {
+ executionLevel++;
+ }
+ } else if (!strcmp(word[0], "whileall")) {
+ currentLevel++;
+ /* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
+ EXECUTING, NOT THE LINE AFTER */
+ top_of_while = before_command;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else if (and_condition()) {
+ executionLevel++;
+ }
+ } else if (!strcmp(word[0], "loop")) {
+ /* THE LOOP COMMAND LOOPS ONCE FOR EACH DEFINED
+ * OBJECT (FOREACH) */
+#ifdef GLK
+ top_of_loop = g_vm->glk_stream_get_position(game_stream);
+#else
+ top_of_loop = ftell(file);
+#endif
+ if (word[1] == NULL) {
+ // IF NONE IS SUPPLIED DEFAULT TO noun3
+ loop_integer = &noun[2];
+ } else {
+ // STORE THE CONTAINER TO PUT THE CURRENT OBJECT IN
+ loop_integer = container_resolve(word[1]);
+
+ // IF THE SUPPLIED CONTAINER CAN'T BE RESOLVED
+ // DEFAULT TO noun3
+ if (loop_integer == NULL)
+ loop_integer = &noun[2];
+ }
+
+ // SET THE VALUE OF THE LOOP INDEX TO POINT TO THE FIRST OBJECT
+ *loop_integer = 1;
+
+ } else if (!strcmp(word[0], "endloop")) {
+ if (top_of_loop == FALSE) {
+ sprintf(error_buffer, NO_LOOP, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+ *loop_integer += 1;
+ if (*loop_integer > objects) {
+ top_of_loop = FALSE;
+ *loop_integer = 0;
+ } else {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_loop, seekmode_Start);
+#else
+ fseek(file, top_of_loop, SEEK_SET);
+#endif
+ }
+ }
+ } else if (!strcmp(word[0], "select")) {
+ /* THE SELECT COMMAND LOOPS ONCE FOR EACH DEFINED
+ * OBJECT THAT MATCHES THE SUPPLIED CRITERION */
+#ifdef GLK
+ top_of_select = g_vm->glk_stream_get_position(game_stream);
+#else
+ top_of_select = ftell(file);
+#endif
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else if (word[2] == NULL) {
+ // IF NONE IS SUPPLIED DEFAULT TO noun3
+ select_integer = &noun[2];
+ } else {
+ // STORE THE CONTAINER TO PUT THE CURRENT OBJECT IN
+ select_integer = container_resolve(word[2]);
+
+ // IF THE SUPPLIED CONTAINER CAN'T BE RESOLVED
+ // DEFAULT TO noun3
+ if (select_integer == NULL) {
+ select_integer = &noun[2];
+ }
+ }
+
+ // SET THE VALUE OF THE SELECT INDEX TO ONE BEFORE THE
+ // FIRST OBJECT. THE NEXT FUNCTION AUTOMATICALLY INCREMENTS
+ // THE INDEX BY ONE AT THE START OF THE WHILE LOOP.
+ *select_integer = 0;
+
+ if (word[1][0] == '!') {
+ criterion_negate = TRUE;
+ strcpy(argument_buffer, &word[1][1]);
+ } else {
+ criterion_negate = FALSE;
+ strcpy(argument_buffer, word[1]);
+ }
+
+ // DETERMINE THE CRITERION FOR SELETION
+ if (!strcmp(argument_buffer, "*held")
+ || !strcmp(argument_buffer, "*here")
+ || !strcmp(argument_buffer, "*anywhere")
+ || !strcmp(argument_buffer, "*present")) {
+ criterion_type = CRI_SCOPE;
+ strncpy(scope_criterion, argument_buffer, 20);
+ } else if ((criterion_value = attribute_resolve(argument_buffer))) {
+ criterion_type = CRI_ATTRIBUTE;
+ } else if ((criterion_value = user_attribute_resolve(argument_buffer))) {
+ criterion_type = CRI_USER_ATTRIBUTE;
+ } else {
+ // USE VALUE OF AS A CATCH ALL IF IT IS NOT AN ATTRIBUTE OR SCOPE
+ criterion_value = value_of(argument_buffer);
+
+ if (value_resolved) {
+ criterion_type = CRI_PARENT;
+ } else {
+ // CAN'T RESOLVE CRITERION
+ criterion_type = CRI_NONE;
+ }
+ }
+
+ if (criterion_type != CRI_NONE) {
+ if (select_next() == FALSE) {
+ *select_integer = 0;
+ top_of_select = 0;
+ }
+ } else {
+ *select_integer = 0;
+ }
+
+ if (*select_integer == 0) {
+ // THERE ARE NO MATCHING OBJECTS SO JUMP TO THE endselect
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+ while (text_buffer[0] != '}') {
+ encapsulate();
+ if (word[0] != NULL && !strcmp(word[0], "endselect")) {
+ break;
+ }
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ }
+ }
+ } else if (!strcmp(word[0], "endselect")) {
+ if (top_of_select == FALSE) {
+ sprintf(error_buffer, NO_LOOP, executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+ if (select_next(/* select_integer, criterion_type, criterion_value, scope_criterion */)) {
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, top_of_select, seekmode_Start);
+#else
+ fseek(file, top_of_select, SEEK_SET);
+#endif
+ } else {
+ *select_integer = 0;
+ top_of_select = 0;
+ }
+ }
+ } else if (!strcmp(word[0], "break")) {
+ currentLevel++;
+ executionLevel--;
+#ifdef GLK
+ } else if (!strcmp(word[0], "cursor")) {
+ if (word[2] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ if (current_window == statuswin) {
+ g_vm->glk_window_move_cursor(statuswin, value_of(word[1], TRUE), value_of(word[2], TRUE));
+ } else {
+ log_error(BAD_CURSOR, PLUS_STDOUT);
+ }
+ }
+ } else if (!strcmp(word[0], "stop")) {
+ int channel;
+
+ if (SOUND_SUPPORTED->value) {
+ /* SET THE CHANNEL TO STOP, IF SUPPLIED */
+ if (word[1] == NULL) {
+ channel = 0;
+ } else {
+ channel = value_of(word[1], TRUE);
+
+ /* SANITY CHECK THE CHANNEL SELECTED */
+ if (channel < 0 || channel > 7) {
+ channel = 0;
+ }
+ }
+ g_vm->glk_schannel_stop(sound_channel[channel]);
+ }
+ } else if (!strcmp(word[0], "volume")) {
+ int channel, volume;
+
+ if (SOUND_SUPPORTED->value) {
+ /* SET THE CHANNEL TO STOP, IF SUPPLIED */
+ if (word[2] == NULL) {
+ channel = 0;
+ } else {
+ channel = value_of(word[2], TRUE);
+
+ /* SANITY CHECK THE CHANNEL SELECTED */
+ if (channel < 0 || channel > 7) {
+ channel = 0;
+ }
+ }
+
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ volume = value_of(word[1], TRUE);
+
+ /* SANITY CHECK THE CHANNEL SELECTED */
+ if (volume < 0) {
+ volume = 0;
+ }
+
+ if (volume > 100) {
+ volume = 100;
+ }
+
+ /* STORE A COPY OF THE CURRENT VOLUME FOR ACCESS
+ * FROM JACL CODE */
+ sprintf(temp_buffer, "volume[%d]", channel);
+ cinteger_resolve(temp_buffer)->value = volume;
+
+ /* NOW SCALE THE 0-100 VOLUME TO THE 0-65536 EXPECTED
+ * BY Glk */
+ volume = volume * 655;
+
+ /* SET THE VOLUME */
+ g_vm->glk_schannel_set_volume(sound_channel[channel], (glui32) volume);
+ }
+ }
+ } else if (!strcmp(word[0], "timer")) {
+ if (TIMER_SUPPORTED->value && TIMER_ENABLED->value) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ index = value_of(word[1], TRUE);
+ /* DON'T ALLOW NEGATIVE VALUES, BUT NO UPPER LIMIT */
+ if (index < 0) index = 0;
+
+ /* SET THE GLK TIMER */
+ g_vm->glk_request_timer_events((glui32) index);
+
+ /* EXPOSE THE CURRENT VALUE THROUGH A JACL CONSTANT
+ SO THAT GAME CODE CAN READ THE IT */
+ cinteger_resolve("timer")->value = index;
+ }
+ }
+ } else if (!strcmp(word[0], "sound")) {
+ int channel;
+ glui32 repeats;
+
+ if (SOUND_SUPPORTED->value && SOUND_ENABLED->value) {
+ /* SET THE CHANNEL TO USE, IF SUPPLIED */
+ if (word[2] == NULL) {
+ channel = 0;
+ } else {
+ channel = value_of(word[2], TRUE);
+
+ /* SANITY CHECK THE CHANNEL SELECTED */
+ if (channel < 0 || channel > 7) {
+ channel = 0;
+ }
+ }
+
+ /* SET THE NUMBER OF REPEATS, IF SUPPLIED */
+ if (word[3] == NULL) {
+ repeats = 1;
+ } else {
+ repeats = value_of(word[3], TRUE);
+ }
+
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (g_vm->glk_schannel_play_ext(sound_channel[channel], (glui32) value_of(word[1], TRUE), repeats, channel + 1) == 0) {
+ /* THE CHANNEL NUMBER IS PASSED SO THAT THE SOUND
+ * NOTIFICATION EVENT CAN USE THE INFORMATION
+ * IT HAS 1 ADDED TO IT SO THAT IT IS A NON-ZERO
+ * NUMBER AND THE EVENT IS ACTIVATED */
+ sprintf(error_buffer, "Unable to play sound: %ld", value_of(word[1], FALSE));
+ log_error(error_buffer, PLUS_STDERR);
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "image")) {
+ if (GRAPHICS_SUPPORTED->value && GRAPHICS_ENABLED->value) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (g_vm->glk_image_draw(mainwin, (glui32) value_of(word[1], TRUE), imagealign_InlineDown, 0) == 0) {
+ sprintf(error_buffer, "Unable to draw image: %ld", value_of(word[1], FALSE));
+ log_error(error_buffer, PLUS_STDERR);
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ /* GET A POINTER TO THE STRING BEING MODIFIED */
+ if ((resolved_string = string_resolve(word[1])) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ // PROMPT THE USER TO INPUT A STRING AND STORE IT IN THE
+ // RESOLVED VARIABLE
+ get_string(resolved_string->value);
+ }
+
+ } else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
+ int low, high;
+
+ int insist = FALSE;
+
+ /* THE ONLY DIFFERENCE WITH THE getnumber COMMAND IS THAT
+ * IT INSISTS THE PLAYER GIVES A LEGAL RESPONSE */
+ if (!strcmp(word[0], "getnumber")) {
+ insist = TRUE;
+ }
+
+ if (word[3] != NULL) {
+ ask_integer = container_resolve(word[1]);
+ if (ask_integer == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ low = value_of(word[2], TRUE);
+ high = value_of(word[3], TRUE);
+
+ if (high == -1 || low == -1) {
+ return (exit_function(TRUE));
+ }
+
+ *ask_integer = get_number(insist, low, high);
+ } else {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+ } else if (!strcmp(word[0], "getyesorno")) {
+ if (word[1] != NULL) {
+ ask_integer = container_resolve(word[1]);
+ if (ask_integer == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ *ask_integer = get_yes_or_no();
+ } else {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+ } else if (!strcmp(word[0], "clear")) {
+ if (!walkthru_running) {
+ g_vm->glk_window_clear(current_window);
+ }
+ } else if (!strcmp(word[0], "terminate")) {
+ terminate(0);
+ } else if (!strcmp(word[0], "more")) {
+ if (word[1] == NULL) {
+ more("[MORE]");
+ } else {
+ more(word[1]);
+ }
+ } else if (!strcmp(word[0], "style")) {
+ /* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
+ * STREAM STYLES */
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (!strcmp(word[1], "bold")
+ || !strcmp(word[1], "emphasised")) {
+ g_vm->glk_set_style(style_Emphasized);
+ } else if (!strcmp(word[1], "note")) {
+ g_vm->glk_set_style(style_Note);
+ } else if (!strcmp(word[1], "input")) {
+ g_vm->glk_set_style(style_Input);
+ } else if (!strcmp(word[1], "header")) {
+ g_vm->glk_set_style(style_Header);
+ } else if (!strcmp(word[1], "subheader")) {
+ g_vm->glk_set_style(style_Subheader);
+ } else if (!strcmp(word[1], "reverse")
+ || !strcmp(word[1], "inverse")) {
+ if (current_window == mainwin) {
+ g_vm->glk_set_style(style_User2);
+ } else {
+ g_vm->glk_set_style(style_User1);
+ }
+ } else if (!strcmp(word[1], "pre")
+ || !strcmp(word[1], "preformatted")) {
+ g_vm->glk_set_style(style_Preformatted);
+ } else if (!strcmp(word[1], "normal")) {
+ g_vm->glk_set_style(style_Normal);
+ }
+ }
+ } else if (!strcmp(word[0], "flush")) {
+ } else if (!strcmp(word[0], "hyperlink")) {
+ /* OUTPUT LINK TEXT AS PLAIN TEXT UNDER Glk */
+ if (word[2] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ write_text(text_of_word(1));
+ }
+#else
+#ifdef __NDS__
+ } else if (!strcmp(word[0], "flush")) {
+ jflush();
+ } else if (!strcmp(word[0], "cursor")) {
+ if (word[2] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ printf("\x1b[%d;%dH", (int) value_of(word[1], TRUE), (int) value_of(word[2], TRUE));
+ }
+ } else if (!strcmp(word[0], "stop")) {
+ } else if (!strcmp(word[0], "volume")) {
+ } else if (!strcmp(word[0], "timer")) {
+ } else if (!strcmp(word[0], "sound")) {
+ } else if (!strcmp(word[0], "image")) {
+ } else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ /* GET A POINTER TO THE STRING BEING MODIFIED */
+ if ((resolved_string = string_resolve(word[1])) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ // PROMPT THE USER TO INPUT A STRING AND STORE IT IN THE
+ // RESOLVED VARIABLE
+ get_string(resolved_string->value);
+ }
+
+ } else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
+ int low, high;
+
+ int insist = FALSE;
+
+ /* THE ONLY DIFFERENCE WITH THE getnumber COMMAND IS THAT
+ * IT INSISTS THE PLAYER GIVES A LEGAL RESPONSE */
+ if (!strcmp(word[0], "getnumber")) {
+ insist = TRUE;
+ }
+
+ if (word[3] != NULL) {
+ ask_integer = container_resolve(word[1]);
+ if (ask_integer == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ low = value_of(word[2], TRUE);
+ high = value_of(word[3], TRUE);
+
+ if (high == -1 || low == -1) {
+ return (exit_function(TRUE));
+ }
+
+ *ask_integer = get_number(insist, low, high);
+ } else {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+ } else if (!strcmp(word[0], "getyesorno")) {
+ if (word[1] != NULL) {
+ ask_integer = container_resolve(word[1]);
+ if (ask_integer == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ *ask_integer = get_yes_or_no();
+ } else {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+ } else if (!strcmp(word[0], "clear")) {
+ clrscrn();
+ } else if (!strcmp(word[0], "terminate")) {
+ terminate(0);
+ } else if (!strcmp(word[0], "more")) {
+ if (word[1] == NULL) {
+ more("[MORE]");
+ } else {
+ more(word[1]);
+ }
+ } else if (!strcmp(word[0], "style")) {
+ /* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
+ * STREAM STYLES */
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (!strcmp(word[1], "bold")
+ || !strcmp(word[1], "emphasised")) {
+ printf("\x1b[37;1m"); // SET TO BRIGHT WHITE
+ bold_mode = TRUE;
+ } else if (!strcmp(word[1], "note")) {
+ printf("\x1b[34;1m"); // SET TO BRIGHT BLUE
+ note_mode = TRUE;
+ } else if (!strcmp(word[1], "input")) {
+ printf("\x1b[32;0m"); // SET TO DIM GREEN
+ input_mode = TRUE;
+ } else if (!strcmp(word[1], "header")) {
+ printf("\x1b[37;0m"); // SET TO DIM WHITE
+ } else if (!strcmp(word[1], "subheader")) {
+ printf("\x1b[33;1m"); // SET TO BRIGHT YELLOW
+ subheader_mode = TRUE;
+ } else if (!strcmp(word[1], "reverse")
+ || !strcmp(word[1], "inverse")) {
+ printf("\x1b[7m"); // SET TO DIM WHITE
+ reverse_mode = TRUE;
+ } else if (!strcmp(word[1], "pre")
+ || !strcmp(word[1], "preformatted")) {
+ printf("\x1b[37;0m"); // SET TO DIM WHITE
+ pre_mode = TRUE;
+ } else if (!strcmp(word[1], "normal")) {
+ printf("\x1b[37;0m"); // SET TO DIM WHITE
+ bold_mode = FALSE;
+ pre_mode = FALSE;
+ reverse_mode = FALSE;
+ input_mode = FALSE;
+ subheader_mode = FALSE;
+ note_mode = FALSE;
+ }
+ }
+ } else if (!strcmp(word[0], "hyperlink")) {
+ /* OUTPUT LINK TEXT AS PLAIN TEXT UNDER Glk */
+ if (word[2] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ write_text(text_of_word(1));
+ }
+#else
+ /* HERE STARTS THE CGIJACL-ONLY FUNCTIONS */
+ } else if (!strcmp(word[0], "option")) {
+ /* USED TO ADD AN OPTION TO AN HTML LIST */
+ if (word[1] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ index = value_of(word[1]);
+ if (word[2] != NULL) {
+ sprintf(option_buffer, "<option value=\"%d\">",
+ index);
+ } else {
+ object_names(index, temp_buffer);
+ sprintf(option_buffer, "<option value=\"%s\">", temp_buffer);
+ }
+
+ write_text(option_buffer);
+ list_output(index, TRUE);
+ write_text(temp_buffer);
+
+ }
+ } else if (!strcmp(word[0], "getenv")) {
+ struct string_type *resolved_setstring = NULL;
+
+ if (word[2] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ // GET A POINTER TO THE STRING BEING MODIFIED
+ if ((resolved_setstring = string_resolve(word[1])) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ // COPY THE VARIABLE OF THE CGI VARIABLE INTO THE SPECIFIED STRING VARIABLE
+ if (getenv(text_of_word(2)) != NULL) {
+ strncpy(resolved_setstring->value, getenv(text_of_word(2)), 255);
+ } else {
+ strncpy(resolved_setstring->value, "", 255);
+ }
+ }
+ } else if (!strcmp(word[0], "button")) {
+ /* USED TO CREATE AN HTML BUTTON */
+ if (word[1] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ }
+ if (word[2] != NULL) {
+ sprintf(option_buffer, "<input class=~button~ type=~image~ src=~%s~ name=~verb~ value=~", text_of_word(2));
+ strcat(option_buffer, text_of_word(1));
+ strcat(option_buffer, "~>");
+ write_text(option_buffer);
+ } else {
+ sprintf(option_buffer, "<input class=~button~ type=~submit~ style=~width: 90px; margin: 5px;~ name=~verb~ value=~%s~>", text_of_word(1));
+ write_text(option_buffer);
+ }
+ } else if (!strcmp(word[0], "hidden")) {
+ sprintf(temp_buffer, "<INPUT TYPE=\"hidden\" NAME=\"user_id\" VALUE=\"%s\">", user_id);
+ write_text(temp_buffer);
+ } else if (!strcmp(word[0], "control")) {
+ /* USED TO CREATE A HYPERLINK THAT IS AN IMAGE */
+ if (word[2] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ sprintf(option_buffer, "<a href=\"?command=%s&user_id=%s\"><img border=0 SRC=\"", text_of_word(2), user_id);
+ strcat(option_buffer, text_of_word(1));
+ strcat(option_buffer, "\"></a>");
+ write_text(option_buffer);
+ }
+ } else if (!strcmp(word[0], "hyperlink") || !strcmp(word[0], "hyperlinkNE")) {
+ string_buffer[0] = 0;
+
+ /* USED TO CREATE A HYPERLINK WITH SESSION INFORMATION INCLUDED */
+ if (word[2] == NULL) {
+ noproprun();
+ pop_stack();
+ return (TRUE);
+ } else {
+ char *encoded;
+
+ if (!strcmp(word[0], "hyperlink")) {
+ encoded = url_encode(text_of_word(2));
+ } else {
+ encoded = text_of_word(2);
+ }
+
+ if (word[3] == NULL) {
+ sprintf(string_buffer, "<a href=\"?command=%s&user_id=%s\">", encoded, user_id);
+ strcat(string_buffer, text_of_word(1));
+ strcat(string_buffer, "</a>");
+ } else {
+ sprintf(string_buffer, "<a class=\"%s\" href=\"?command=", text_of_word(3));
+ strcat(string_buffer, encoded);
+ sprintf(option_buffer, "&user_id=%s\">%s</a>", user_id, text_of_word(1));
+ strcat(string_buffer, option_buffer);
+ }
+
+ if (!strcmp(word[0], "hyperlink")) {
+ free(encoded);
+ }
+
+ write_text(string_buffer);
+ }
+ } else if (!strcmp(word[0], "prompt")) {
+ /* USED TO OUTPUT A HTML INPUT CONTROL THAT CONTAINS SESSION INFORMATION */
+ if (word[1] != NULL) {
+ sprintf(temp_buffer, "<input id=\"JACLCommandPrompt\" type=text name=~command~ onKeyPress=~%s~>\n", word[1]);
+ write_text(temp_buffer);
+ } else {
+ sprintf(temp_buffer, "<input id=\"JACLCommandPrompt\" type=text name=~command~>\n");
+ write_text(temp_buffer);
+ }
+ sprintf(temp_buffer, "<input type=hidden name=\"user_id\" value=\"%s\">", user_id);
+ write_text(temp_buffer);
+ } else if (!strcmp(word[0], "style")) {
+ /* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
+ * STREAM STYLES */
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (!strcmp(word[1], "bold")
+ || !strcmp(word[1], "emphasised")) {
+ write_text("<b>");
+ style_stack[style_index++] = BOLD;
+ } else if (!strcmp(word[1], "note")) {
+ write_text("<i>");
+ style_stack[style_index++] = NOTE;
+ } else if (!strcmp(word[1], "input")) {
+ write_text("<i>");
+ style_stack[style_index++] = INPUT;
+ } else if (!strcmp(word[1], "header")) {
+ write_text("<h1>");
+ style_stack[style_index++] = HEADER;
+ } else if (!strcmp(word[1], "subheader")) {
+ write_text("<h2>");
+ style_stack[style_index++] = SUBHEADER;
+ } else if (!strcmp(word[1], "reverse")
+ || !strcmp(word[1], "inverse")) {
+ write_text("<b>");
+ style_stack[style_index++] = REVERSE;
+ } else if (!strcmp(word[1], "pre")
+ || !strcmp(word[1], "preformatted")) {
+ write_text("<pre>");
+ style_stack[style_index++] = PRE;
+ } else if (!strcmp(word[1], "normal")) {
+ style_index--;
+ for (; style_index > -1; style_index--) {
+ switch (style_stack[style_index]) {
+ case BOLD:
+ write_text("</b>");
+ break;
+ case NOTE:
+ write_text("</i>");
+ break;
+ case INPUT:
+ write_text("</i>");
+ break;
+ case HEADER:
+ write_text("</h1>");
+ break;
+ case SUBHEADER:
+ write_text("</h2>");
+ break;
+ case REVERSE:
+ write_text("</b>");
+ break;
+ case PRE:
+ write_text("</pre>");
+ break;
+ }
+ }
+ style_index = 0;
+ }
+ }
+ /* THESE FINAL COMMANDS HAVE NO EFFECT UNDER CGIJACL
+ AND THERE IS NO HARM IN IGNORING THEM */
+ } else if (!strcmp(word[0], "flush")) {
+ } else if (!strcmp(word[0], "image")) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ if (word[2] == NULL) {
+ sprintf(option_buffer, "<img src=~%s~>", text_of_word(1));
+ } else {
+ sprintf(option_buffer, "<img class=~%s~ src=~%s~>", text_of_word(2), text_of_word(1));
+ }
+
+ write_text(option_buffer);
+ }
+ } else if (!strcmp(word[0], "sound")) {
+ if (word[2] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ write_text("<audio autoplay=~autoplay~>");
+ if (word[3] == NULL) {
+ sprintf(option_buffer, "<source src=~%s~ type=~%s~>", text_of_word(1), text_of_word(2));
+ write_text(option_buffer);
+ }
+ write_text("</audio>");
+ }
+ } else if (!strcmp(word[0], "cursor")) {
+ } else if (!strcmp(word[0], "timer")) {
+ } else if (!strcmp(word[0], "volume")) {
+ } else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
+ } else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
+ } else if (!strcmp(word[0], "getyesorno")) {
+ } else if (!strcmp(word[0], "clear")) {
+ } else if (!strcmp(word[0], "more")) {
+ } else if (!strcmp(word[0], "terminate")) {
+#endif
+#endif
+ } else if (!strcmp(word[0], "proxy")) {
+ /* THE PROXY COMMAND ISSUES A MOVE ON THE PLAYER'S BEHALF
+ * ALL STATE MUST BE SAVED SO THE CURRENT MOVE CAN CONTINUE
+ * ONCE THE PROXIED MOVE IS COMPLETE */
+#ifdef GLK
+ push_stack(g_vm->glk_stream_get_position(game_stream));
+#else
+ push_stack(ftell(file));
+#endif
+ push_proxy();
+
+ build_proxy();
+
+ // TEXT BUFFER IS THE NORMAL ARRAY FOR HOLDING THE PLAYERS
+ // MOVE FOR PROCESSING
+ strncpy(text_buffer, proxy_buffer, 1024);
+
+ command_encapsulate();
+
+ jacl_truncate();
+
+ preparse();
+
+ pop_proxy();
+
+ pop_stack();
+ } else if (!strcmp(word[0], "override")) {
+ /* TELLS THE INTERPRETER TO LOOK FOR AN _override FUNCTION
+ * TO EXECUTE IN PLACE OF ANY CODE THAT FOLLOWS THIS LINE.
+ * THIS COMMAND IS USED EXCLUSIVELY IN GLOBAL FUNCTIONS
+ * ASSOCIATED WITH GRAMMAR LINES */
+ if (execute(override) == TRUE) {
+ return (exit_function(TRUE));
+ } else {
+ if (execute(default_function) == TRUE) {
+ return (exit_function(TRUE));
+ }
+ }
+ } else if (!strcmp(word[0], "execute") || !strcmp(word[0], "call")) {
+ /* CALLS ANOTHER JACL FUNCTION */
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ /* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
+ string_buffer[0] = 0;
+
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ strcat(string_buffer, arg_text_of_word(counter));
+ }
+
+ if (function_resolve(string_buffer) == NULL && !strcmp(word[0], "execute")) {
+ char *argstart;
+
+ /* REMOVE ANY PARAMETERS FROM FUNCTION NAME
+ BEFORE DISPLAYING ERROR MESSAGE */
+ argstart = strchr(string_buffer, '<');
+ if (argstart != NULL)
+ *argstart = 0;
+
+ sprintf(error_buffer, UNDEFINED_FUNCTION, executing_function->name, string_buffer);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+ execute(string_buffer);
+ }
+ }
+ } else if (!strcmp(word[0], "points")) {
+ /* INCREASE THE PLAYER'S SCORE AND POTENTIALLY INFORM THEM OF THE INCREASE */
+ if (word[1] != NULL) {
+ SCORE->value += value_of(word[1], TRUE);
+ if (NOTIFY->value) {
+#ifdef GLK
+ g_vm->glk_set_style(style_Note);
+#else
+#ifdef __NDS__
+ printf("\x1b[34;1m"); // SET TO BRIGHT BLUE
+ note_mode = TRUE;
+#else
+ write_text("<b><i>");
+#endif
+#endif
+ write_text(cstring_resolve("SCORE_UP")->value);
+ sprintf(temp_buffer, "%ld", value_of(word[1], TRUE));
+ write_text(temp_buffer);
+ if (value_of(word[1], TRUE) == 1) {
+ write_text(cstring_resolve("POINT")->value);
+ } else {
+ write_text(cstring_resolve("POINTS")->value);
+ }
+#ifdef GLK
+ g_vm->glk_set_style(style_Normal);
+#else
+#ifdef __NDS__
+ printf("\x1b[37;0m"); // SET TO DIM WHITE
+ note_mode = FALSE;
+#else
+ write_text("</i></b>");
+#endif
+#endif
+ }
+ } else {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+ } else if (!strcmp(word[0], "print")) {
+ int non_space = FALSE;
+
+ // DISPLAYS A BLOCK OF PLAIN TEXT UNTIL IT FINDS A
+ // LINE THAT STARTS WITH A '.' OR A '}'
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+ while (text_buffer[0] != '.' && text_buffer[0] != '}') {
+ index = 0;
+ non_space = FALSE;
+
+ /* REMOVE ANY NEWLINE CHARACTERS */
+ while (text_buffer[index] != 0) {
+ if (text_buffer[index] == '|' && non_space == FALSE) {
+ /* THE BAR CHARACTER IS CHANGED TO A SPACE TO
+ * ALLOW INDENTING OF NEW PARAGRAPHS ETC */
+ text_buffer[index] = ' ';
+ } else if (text_buffer[index] == '\r') {
+ text_buffer[index] = 0;
+ break;
+ } else if (text_buffer[index] == '\n') {
+ text_buffer[index] = 0;
+ break;
+ } else if (text_buffer[index] != ' ' && text_buffer[index] != '\t') {
+ non_space = TRUE;
+ }
+
+ index++;
+ }
+
+ if (text_buffer[0] != 0) {
+ // CHECK IF THERE IS THE NEED TO ADD AN
+ // IMPLICIT SPACE
+ index = strlen(text_buffer);
+
+ if (text_buffer[index - 1] == '\\') {
+ // A BACKSLASH IS USED TO INDICATE AN IMPLICIT
+ // SPACE SHOULD NOT BE PRINTED
+ text_buffer[index - 1] = 0;
+ } else if (text_buffer[index - 1] != '^') {
+ // ADD AN IMPLICIT SPACE IF THE PREVIOUS LINE
+ // DIDN'T END WITH A CARRIAGE RETURN
+ strcat(text_buffer, " ");
+ }
+
+ // OUTPUT THE LINE READ AS PLAIN TEXT
+ write_text(text_buffer);
+ }
+
+ // GET THE NEXT LINE
+#ifdef GLK
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+
+ if (encrypted) jacl_decrypt(text_buffer);
+ }
+ } else if (!strcmp(word[0], "mesg")) {
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ warning("%s", text_of_word(counter));
+ }
+ } else if (!strcmp(word[0], "error")) {
+ write_text("ERROR: In function ~");
+ write_text(executing_function->name);
+ write_text("~, ");
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ write_text(text_of_word(counter));
+ }
+ } else if (!strcmp(word[0], "debug") && DEBUG->value) {
+ write_text("DEBUG: ");
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ write_text(text_of_word(counter));
+ }
+ } else if (!strcmp(word[0], "write")) {
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ output = text_of_word(counter);
+ if (*output != 0) {
+ // IF THE OUTPUT ISN'T AN EMPTY STRING, DISPLAY IT
+ write_text(output);
+ }
+ }
+ } else if (!strcmp(word[0], "length")) {
+ if (word[2] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ if ((container = container_resolve(word[1])) == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ *container = strlen(text_of(word[2]));
+ }
+ } else if (!strcmp(word[0], "savegame")) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if ((container = container_resolve(word[1])) == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ } else {
+ if (word[2] == NULL) {
+ *container = save_interaction(NULL);
+ } else {
+ *container = save_interaction(arg_text_of_word(2));
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "restoregame")) {
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if ((container = container_resolve(word[1])) == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ } else {
+ if (word[2] == NULL) {
+ *container = restore_interaction(NULL);
+ } else {
+ *container = restore_interaction(arg_text_of_word(2));
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "restartgame")) {
+ restart_game();
+ execute("+intro");
+ eachturn();
+#ifdef GLK
+ } else if (!strcmp(word[0], "undomove")) {
+ undoing();
+ } else if (!strcmp(word[0], "updatestatus")) {
+ status_line();
+#else
+ } else if (!strcmp(word[0], "undomove")) {
+ } else if (!strcmp(word[0], "updatestatus")) {
+#endif
+ } else if (!strcmp(word[0], "split")) {
+
+ // 0 1 2 3 4
+ // split counter source delimiter destination
+
+ int *split_container;
+ char split_buffer[256] = "";
+ char container_buffer[256] = "";
+ char delimiter[256] = "";
+ char *match = NULL;
+ struct string_type *resolved_splitstring = NULL;
+
+ strcpy(split_buffer, text_of_word(2));
+ strcpy(delimiter, text_of_word(3));
+
+ char *source = split_buffer;
+
+ if (word[4] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ split_container = container_resolve(var_text_of_word(1));
+
+ if (split_container == NULL) {
+ unkvarrun(var_text_of_word(1));
+ return (exit_function(TRUE));
+ } else {
+ *split_container = 0;
+ match = source; // THERE IS ALWAYS ONE MATCH, EVEN IF
+ // NO DELIMETERS ARE FOUND
+
+ while ((match = strstr(source, delimiter))) {
+ *match = 0;
+ strcpy(container_buffer, var_text_of_word(4));
+ strcat(container_buffer, "[");
+ sprintf(integer_buffer, "%d", *split_container);
+ strcat(container_buffer, integer_buffer);
+ strcat(container_buffer, "]");
+
+ if ((resolved_splitstring = string_resolve(container_buffer)) == NULL) {
+ unkstrrun(var_text_of_word(4));
+ return (exit_function(TRUE));
+ } else {
+ strcpy(resolved_splitstring->value, source);
+ source = match + strlen(delimiter);
+ (*split_container)++;
+ }
+ }
+ strcpy(container_buffer, var_text_of_word(4));
+ strcat(container_buffer, "[");
+ sprintf(integer_buffer, "%d", *split_container);
+ strcat(container_buffer, integer_buffer);
+ strcat(container_buffer, "]");
+
+ if ((resolved_splitstring = string_resolve(container_buffer)) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ } else {
+ strcpy(resolved_splitstring->value, source);
+ (*split_container)++;
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "setstring") ||
+ !strcmp(word[0], "addstring")) {
+ char setstring_buffer[2048] = "";
+ struct string_type *resolved_setstring = NULL;
+
+ if (word[2] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ /* GET A POINTER TO THE STRING BEING MODIFIED */
+ if ((resolved_setstring = string_resolve(var_text_of_word(1))) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ /* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
+ for (counter = 2; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ strcat(setstring_buffer, text_of_word(counter));
+ }
+
+ /* setstring_buffer IS NOW FILLED, COPY THE UP TO 256 BYTES OF
+ * IT INTO THE STRING */
+ if (!strcmp(word[0], "setstring")) {
+ strncpy(resolved_setstring->value, setstring_buffer, 255);
+ } else {
+ /* CALCULATE HOW MUCH SPACE IS LEFT IN THE STRING */
+ counter = 255 - strlen(resolved_setstring->value);
+ /* THIS IS A addstring COMMAND, SO USE STRNCAT INSTEAD */
+ strncat(resolved_setstring->value, setstring_buffer, counter);
+ }
+ }
+ } else if (!strcmp(word[0], "padstring")) {
+ char setstring_buffer[2048] = "";
+ struct string_type *resolved_setstring = NULL;
+ string_buffer[0] = 0;
+
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ /* GET A POINTER TO THE STRING BEING MODIFIED */
+ if ((resolved_setstring = string_resolve(word[1])) == NULL) {
+ unkstrrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ index = value_of(word[3], TRUE);
+
+ for (counter = 0; counter < index; counter++) {
+ strcat(setstring_buffer, text_of_word(2));
+ }
+
+ /* setstring_buffer IS NOW FILLED, COPY THE UP TO 256 BYTES OF
+ * IT INTO THE STRING */
+ strncpy(resolved_setstring->value, setstring_buffer, 255);
+ }
+ } else if (!strcmp(word[0], "return")) {
+ /* RETURN FROM THIS FUNCTION, POSSIBLY RETURNING AN INTEGER VALUE */
+ if (word[1] == NULL) {
+ return (exit_function(TRUE));
+ } else {
+ index = value_of(word[1], TRUE);
+ return (exit_function(index));
+ }
+ } else if (!strcmp(word[0], "position")) {
+ /* MOVE AN OBJECT TO ITS NEW X,Y COORDINATES BASED ON ITS CURRENT VALUES
+ * FOR x, y, bearing, velocity */
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ object_1 = value_of(word[1], TRUE);
+
+ if (object_1 < 1 || object_1 > objects) {
+ badptrrun(word[1], object_1);
+ return (exit_function(TRUE));
+ } else {
+ new_position((double) object[object_1]->X,
+ (double) object[object_1]->Y,
+ (double) object[object_1]->BEARING,
+ (double) object[object_1]->VELOCITY);
+
+ object[object_1]->X = new_x;
+ object[object_1]->Y = new_y;
+ }
+ }
+ } else if (!strcmp(word[0], "bearing")) {
+ /* CALCULATE THE BEARING BETWEEN TWO OBJECTS */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if ((container = container_resolve(word[1])) == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ }
+
+ object_1 = value_of(word[2], TRUE);
+
+ if (object_1 < 1 || object_1 > objects) {
+ badptrrun(word[2], object_1);
+ return (exit_function(TRUE));
+ } else {
+ object_2 = value_of(word[3], TRUE);
+
+ if (object_2 < 1 || object_2 > objects) {
+ badptrrun(word[3], object_2);
+ return (exit_function(TRUE));
+ } else {
+ if (container != NULL
+ && object_1 != FALSE
+ && object_2 != FALSE) {
+ *container = bearing((double) object[object_1]->X,
+ (double) object[object_1]->Y,
+ (double) object[object_2]->X,
+ (double) object[object_2]->Y);
+ }
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "distance")) {
+ /* CALCULATE THE DISTANCE BETWEEN TWO OBJECTS */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ container = container_resolve(word[1]);
+
+ object_1 = value_of(word[2], TRUE);
+
+ if (object_1 < 1 || object_1 > objects) {
+ badptrrun(word[2], object_1);
+ return (exit_function(TRUE));
+ } else {
+ object_2 = value_of(word[3], TRUE);
+
+ if (object_2 < 1 || object_2 > objects) {
+ badptrrun(word[3], object_2);
+ return (exit_function(TRUE));
+ } else {
+ if (container != NULL
+ && object_1 != FALSE
+ && object_2 != FALSE) {
+ *container = distance((double)
+ object[object_1]->X,
+ (double)
+ object[object_1]->Y,
+ (double)
+ object[object_2]->X,
+ (double)
+ object[object_2]->Y);
+ }
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "dir_to") ||
+ !strcmp(word[0], "npc_to")) {
+ /* CALCULATE THE FIRST DIRECTION TO TRAVEL IN GET TO
+ * A SPECIFIED LOCATION */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ container = container_resolve(word[1]);
+
+ object_1 = value_of(word[2], TRUE);
+
+ if (object_1 < 1 || object_1 > objects) {
+ badptrrun(word[2], object_1);
+ return (exit_function(TRUE));
+ } else {
+ object_2 = value_of(word[3], TRUE);
+
+ if (object_2 < 1 || object_2 > objects) {
+ badptrrun(word[3], object_2);
+ return (exit_function(TRUE));
+ } else {
+ if (container != NULL
+ && object_1 != FALSE
+ && object_2 != FALSE) {
+ if (!strcmp(word[0], "dir_to")) {
+ *container = find_route(object_1, object_2, TRUE);
+ } else {
+ *container = find_route(object_1, object_2, FALSE);
+ }
+ }
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "set")) {
+ /* SET THE VALUE OF AN ELEMENT TO A SUPPLIED INTEGER */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ container = container_resolve(var_text_of_word(1));
+
+ if (container == NULL) {
+ unkvarrun(word[1]);
+ return (exit_function(TRUE));
+ } else {
+ int mark = 2; // SET mark TO POINT TO THE FIRST OPERATOR
+ while (word[mark + 1] != NULL) {
+ counter = value_of(word[mark + 1], TRUE);
+
+ if (word[mark][0] == '+')
+ *container += counter;
+ else if (word[mark][0] == '-')
+ *container -= counter;
+ else if (word[mark][0] == '*')
+ *container = *container * counter;
+ else if (word[mark][0] == '%')
+ *container = *container % counter;
+ else if (word[mark][0] == '/') {
+ if (counter == 0) {
+ sprintf(error_buffer, DIVIDE_BY_ZERO,
+ executing_function->name);
+ log_error(error_buffer, PLUS_STDOUT);
+ } else
+ *container = *container / counter;
+ } else if (!strcmp(word[mark], "locationof")) {
+ *container = grand_of(counter, FALSE);
+ } else if (!strcmp(word[mark], "grandof")) {
+ *container = grand_of(counter, TRUE);
+ } else if (word[mark][0] == '=') {
+ *container = counter;
+ } else {
+ sprintf(error_buffer, ILLEGAL_OPERATOR,
+ executing_function->name,
+ word[2]);
+ log_error(error_buffer, PLUS_STDOUT);
+ }
+
+ mark += 2;
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "ensure")) {
+ /* USED TO GIVE OR TAKE AN ATTRIBUTE TO OR FROM AND OBJECT */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if ((bit_mask = attribute_resolve(arg_text_of(word[3])))) {
+ index = value_of(word[1], TRUE);
+ if (index < 1 || index > objects) {
+ badptrrun(word[1], index);
+ return (exit_function(TRUE));
+ } else {
+ if (!strcmp(word[2], "has")) {
+ object[index]->attributes =
+ object[index]->attributes | bit_mask;
+ } else if (!strcmp(word[2], "hasnt")) {
+ bit_mask = ~bit_mask;
+ object[index]->attributes =
+ object[index]->attributes & bit_mask;
+ }
+ }
+ } else if ((bit_mask = user_attribute_resolve(arg_text_of(word[3])))) {
+ index = value_of(word[1], TRUE);
+ if (index < 1 || index > objects) {
+ badptrrun(word[1], index);
+ return (exit_function(TRUE));
+ } else {
+ if (!strcmp(word[2], "has")) {
+ object[index]->user_attributes =
+ object[index]->user_attributes | bit_mask;
+ } else if (!strcmp(word[2], "hasnt")) {
+ bit_mask = ~bit_mask;
+ object[index]->user_attributes =
+ object[index]->user_attributes & bit_mask;
+ }
+ }
+ } else {
+ unkattrun(3);
+ return (exit_function(TRUE));
+ }
+ }
+ } else if (!strcmp(word[0], "append")) {
+ int first = TRUE;
+
+ if (word[2] == NULL) {
+ // NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ strcpy(temp_buffer, data_directory);
+ strcat(temp_buffer, prefix);
+ strcat(temp_buffer, "-");
+ strcat(temp_buffer, text_of_word(1));
+ strcat(temp_buffer, ".csv");
+
+ outfile = File::openForWriting(temp_buffer);
+
+ if (outfile == NULL) {
+ sprintf(error_buffer, "Failed to open file %s: %s\n", temp_buffer, strerror(errno));
+ log_error(error_buffer, PLUS_STDOUT);
+ } else {
+ for (counter = 2; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ output = text_of_word(counter);
+ if (*output != 0) {
+ if (first == FALSE) {
+ outfile->writeByte(',');
+ }
+ csv_fwrite(outfile, output, (size_t) strlen(output));
+ first = FALSE;
+ }
+ }
+
+ // TERMINATE THE LINE
+ outfile->writeByte('\n');
+
+ // FLUSH AND CLOSE THE FILE
+ outfile->flush();
+ }
+
+ delete outfile;
+ outfile = NULL;
+ }
+ } else if (!strcmp(word[0], "insert")) {
+ int first = TRUE;
+
+ if (word[1] == NULL) {
+ // NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ if (outfile == NULL) {
+ log_error("Insert statement not inside an 'update' loop.", PLUS_STDOUT);
+ } else {
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ output = text_of_word(counter);
+ if (*output != 0) {
+ if (first == FALSE) {
+ outfile->writeByte(',');
+ }
+ csv_fwrite(outfile, output, (size_t) strlen(output));
+ first = FALSE;
+ }
+ }
+
+ // TERMINATE THE LINE
+ outfile->writeByte('\n');
+ }
+ }
+ } else if (!strcmp(word[0], "inspect")) {
+ if (word[1] == NULL) {
+ // NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
+ noproprun();
+ return (exit_function(TRUE));
+ } else {
+ inspect(value_of(word[1], TRUE));
+ }
+ } else if (!strcmp(word[0], "move")) {
+ /* THIS COMMAND IS USED TO MOVE AN OBJECT TO HAVE ANOTHER PARENT
+ * INCLUDING MODIFYING ALL QUANTITY VALUES BASED ON THE OBJECTS MASS */
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun();
+ return (exit_function(TRUE));
+ }
+
+ index = value_of(word[1], TRUE);
+ if (index < 1 || index > objects) {
+ badptrrun(word[1], index);
+ return (exit_function(TRUE));
+ } else {
+ object_2 = object[index]->PARENT;
+ if (object_2 && !(object[object_2]->attributes & LOCATION)) {
+ object[object_2]->QUANTITY += object[index]->MASS;
+ }
+ object_1 = value_of(word[3], TRUE);
+ if (object_1 < 1 || object_1 > objects) {
+ badptrrun(word[1], object_1);
+ return (exit_function(TRUE));
+ } else {
+ object[index]->PARENT = object_1;
+ if (!(object[object_1]->attributes & LOCATION))
+ object[object_1]->QUANTITY -= object[index]->MASS;
+ }
+ }
+ } else if (!strcmp(word[0], "ifstringall")) {
+ /* CHECK IF A STRING EQUALS OR CONTAINS ANOTHER STRING */
+ currentLevel++;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else if (and_strcondition()) {
+ executionLevel++;
+ }
+ } else if (!strcmp(word[0], "ifstring")) {
+ /* CHECK IF A STRING EQUALS OR CONTAINS ANOTHER STRING */
+ currentLevel++;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else if (strcondition()) {
+ executionLevel++;
+ }
+ } else if (!strcmp(word[0], "ifexecute")) {
+ currentLevel++;
+ if (word[1] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else {
+ /* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
+ string_buffer[0] = 0;
+
+ for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
+ strcat(string_buffer, arg_text_of_word(counter));
+ }
+
+ if (execute(string_buffer)) {
+ executionLevel++;
+ }
+ }
+ } else if (!strcmp(word[0], "if")) {
+ currentLevel++;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else if (condition()) {
+ executionLevel++;
+ }
+ } else if (!strcmp(word[0], "ifall")) {
+ currentLevel++;
+ if (word[3] == NULL) {
+ /* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
+ noproprun(0);
+ return (exit_function(TRUE));
+ } else if (and_condition()) {
+ executionLevel++;
+ }
+ } else {
+ sprintf(error_buffer, UNKNOWN_COMMAND,
+ executing_function->name, word[0]);
+ log_error(error_buffer, PLUS_STDOUT);
+ }
+ } else if (!strcmp(word[wp], "if")
+ || !strcmp(word[wp], "ifall")
+ || !strcmp(word[wp], "ifstring")
+ || !strcmp(word[wp], "ifstringall")
+ || !strcmp(word[wp], "ifexecute")
+ || !strcmp(word[wp], "iterate")
+ || !strcmp(word[wp], "update")
+ || !strcmp(word[wp], "while")
+ || !strcmp(word[wp], "whileall")) {
+ currentLevel++;
+ }
+
+#ifdef GLK
+ before_command = g_vm->glk_stream_get_position(game_stream);
+ glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ before_command = ftell(file);
+ fgets(text_buffer, 1024, file);
+#endif
+ if (encrypted) jacl_decrypt(text_buffer);
+ };
+
+ return (exit_function(TRUE));
+}
+
+int exit_function(int return_code) {
+ if (infile != NULL) {
+ read_lck.l_type = F_UNLCK; // SETTING A READ LOCK
+ fcntl(read_fd, F_SETLK, &read_lck);
+ delete infile;
+ infile = NULL;
+ }
+
+ if (outfile != NULL) {
+ write_lck.l_type = F_UNLCK; // SETTING A WRITE LOCK
+ fcntl(write_fd, F_SETLK, &write_lck);
+ delete outfile;
+ outfile = NULL;
+ }
+
+ /* POP THE STACK REGARDLESS OF THE RETURN CODE */
+ pop_stack();
+
+ return (return_code);
+}
+
+char *object_names(int object_index, char *names_buffer) {
+ /* THIS FUNCTION CREATES A LIST OF ALL AN OBJECT'S NAMES.
+ THE escape ARGUMENT INDICATES WHETHER A + SIGN SHOULD BE
+ USED IN PLACE OF A SPACE BETWEEN EACH OF THE NAMES */
+ struct name_type *current_name = object[object_index]->first_name;
+ names_buffer[0] = 0;
+
+ while (current_name != NULL) {
+ strcat(names_buffer, " ");
+ strcat(names_buffer, current_name->name);
+ current_name = current_name->next_name;
+ }
+
+ return names_buffer;
+}
+
+int distance(double x1, double y1, double x2, double y2) {
+ /* THIS FUNCTION CALCULATES THE DISTANCE BETWEEN TWO POINTS IN A
+ TWO-DIMENSIONAL PLANE */
+ double delta_x,
+ delta_y;
+ double distance,
+ total;
+
+ /*
+ * Object two in which quadrant compared to object one? 0 x = opp, y =
+ * ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
+ * + 180 degrees 3 x = adj, y = opp + 270 degrees
+ */
+
+ /*
+ * DETERMINE WHICH QUADRANT OBJECT TWO IS IN
+ */
+
+ if (x2 > x1) {
+ /*
+ * OBJECT TWO IS IN 1 OR 2
+ */
+ delta_x = x2 - x1;
+ if (y2 > y1) {
+ delta_y = y2 - y1;
+ } else {
+ delta_y = y1 - y2;
+ }
+ } else {
+ /*
+ * OBJECT TWO IS IN 3 OR 4
+ */
+ delta_x = x1 - x2;
+ if (y2 > y1) {
+ delta_y = y2 - y1;
+ } else {
+ delta_y = y1 - y2;
+ }
+ }
+
+ delta_y = delta_y * delta_y;
+ delta_x = delta_x * delta_x;
+
+ total = delta_y + delta_x;
+
+ distance = sqrt(total);
+
+ return ((int) distance);
+}
+
+void new_position(double x1, double y1, double bearing, double velocity) {
+ double delta_x,
+ delta_y;
+ double radians;
+
+ /*
+ * Object two in which quadrant compared to object one? 0 x = opp, y =
+ * ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
+ * + 180 degrees 3 x = adj, y = opp + 270 degrees
+ */
+
+ /*
+ * sin finds opp, cos finds adj
+ */
+
+ if (bearing < 91) {
+ radians = bearing * 2.0 * M_PI / 360.;
+ delta_x = velocity * sin(radians);
+ delta_y = velocity * cos(radians);
+ new_x = x1 + delta_x;
+ new_y = y1 + delta_y;
+ } else if (bearing < 181) {
+ bearing -= 90;
+ radians = bearing * 2.0 * M_PI / 360.;
+ delta_y = velocity * sin(radians);
+ delta_x = velocity * cos(radians);
+ new_x = x1 + delta_x;
+ new_y = y1 - delta_y;
+ } else if (bearing < 271) {
+ bearing -= 180;
+ radians = bearing * 2.0 * M_PI / 360.;
+ delta_x = velocity * sin(radians);
+ delta_y = velocity * cos(radians);
+ new_x = x1 - delta_x;
+ new_y = y1 - delta_y;
+ } else {
+ bearing -= 270;
+ radians = bearing * 2.0 * M_PI / 360.;
+ delta_y = velocity * sin(radians);
+ delta_x = velocity * cos(radians);
+ new_x = x1 - delta_x;
+ new_y = y1 + delta_y;
+ }
+}
+
+int bearing(double x1, double y1, double x2, double y2) {
+ int quadrant;
+ double delta_x,
+ delta_y;
+ double oppoadj;
+ double bearing;
+
+ /*
+ * Object two in which quadrant compared to object one? 0 x = opp, y =
+ * ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
+ * + 180 degrees 3 x = adj, y = opp + 270 degrees
+ */
+
+ if (x2 > x1) {
+ delta_x = x2 - x1;
+ if (y2 > y1) {
+ quadrant = 0;
+ delta_y = y2 - y1;
+ oppoadj = delta_x / delta_y;
+ } else {
+ quadrant = 1;
+ delta_y = y1 - y2;
+ oppoadj = delta_y / delta_x;
+ }
+ } else {
+ delta_x = x1 - x2;
+ if (y2 > y1) {
+ quadrant = 3;
+ delta_y = y2 - y1;
+ oppoadj = delta_y / delta_x;
+ } else {
+ quadrant = 2;
+ delta_y = y1 - y2;
+ oppoadj = delta_x / delta_y;
+ }
+ }
+
+ bearing = atan(oppoadj);
+ bearing = bearing / (2.0 * M_PI) * 360.;
+ bearing = bearing + (90 * quadrant);
+
+ return ((int) bearing);
+}
+
+void set_arguments(char *function_call) {
+ /* THIS FUNCTION CREATES AN ARRAY OF JACL INTEGER CONSTANTS TO
+ REPRESENT THE ARGUMENTS PASSED TO A JACL FUNCTION */
+ int index,
+ counter,
+ length;
+ int position = 0; /* STORE THE INDEX OF THE WORD */
+ /* SETTING new_word TO FALSE SKIPS THE FIRST */
+ /* WORD WHICH IS THE FUNCTION NAME */
+ int new_word = FALSE;
+
+ char *arg_ptr[MAX_WORDS];
+ int arg_value[MAX_WORDS];
+
+ struct integer_type *resolved_integer;
+ struct cinteger_type *resolved_cinteger;
+
+ /* SPLIT UP THE FUNCTION CALL STRING AND EXTRACT THE ARGUMENTS */
+ length = strlen(function_call);
+
+ for (index = 0; index < length; index++) {
+ if (function_call[index] == '<') {
+ argument_buffer[index] = 0;
+ new_word = TRUE;
+ } else {
+ // COPY THE CHARACTER FROM THE CALLED NAME INTO THE CURRENT
+ // ARGUMENT BUFFER
+ argument_buffer[index] = function_call[index];
+ if (new_word) {
+ // THIS IS THE FIRST CHARACTER OF A NEW ARGUMENT SO STORE
+ // THE ADDRESS OF THIS CHARACTER IN THE ARGUMENT BUFFER
+ arg_ptr[position] = &argument_buffer[index];
+ new_word = FALSE;
+ if (position < MAX_WORDS)
+ position++;
+ }
+ }
+ }
+
+ argument_buffer[index] = 0;
+
+ /* CLEAR THE NEXT ARGUMENT POINTER */
+ arg_ptr[position] = NULL;
+
+ /* STORE THE INTEGER VALUE OF EACH ARGUMENT PASSED*/
+ index = 0;
+ while (arg_ptr[index] != NULL) {
+ //arg_value[index] = value_of(arg_ptr[index], TRUE);
+
+ if ((resolved_integer = integer_resolve(arg_ptr[index])) != NULL) {
+ arg_value[index] = resolved_integer->value;
+ } else if ((resolved_cinteger = cinteger_resolve(arg_ptr[index])) != NULL) {
+ arg_value[index] = resolved_cinteger->value;
+ } else if (object_element_resolve(arg_ptr[index])) {
+ arg_value[index] = oec;
+ } else if ((counter = object_resolve(arg_ptr[index])) != -1) {
+ if (counter < 1 || counter > objects) {
+ badptrrun(arg_ptr[index], counter);
+ pop_stack();
+ return;
+ } else {
+ arg_value[index] = counter;
+ }
+ } else if (validate(arg_ptr[index])) {
+ arg_value[index] = atoi(arg_ptr[index]);
+ } else {
+ arg_value[index] = -1;
+ }
+
+ index++;
+ }
+
+ /* THE CURRENT ARGUMENTS HAVE ALREADY BEEN PUSHED ONTO THE STACK
+ * AND STORED IF PASSED AS AN ARGUMENT TO THIS FUNCTION SO IT IS
+ * OKAY TO CLEAR THEM AND SET THE NEW VALUES */
+ clear_cinteger("arg");
+ clear_cstring("string_arg");
+
+ /* CREATE A CONSTANT FOR EACH ARGUMENT AFTER THE CORE FUNCTION NAME */
+ index = 0;
+ while (arg_ptr[index] != NULL) {
+ if (index == 0) noun[3] = arg_value[index];
+ add_cinteger("arg", arg_value[index]);
+ //printf("--- %s = %s\n", arg_ptr[index], arg_text_of(arg_ptr[index]));
+ add_cstring("string_arg", arg_text_of(arg_ptr[index]));
+ index++;
+ }
+}
+
+void pop_stack() {
+ int index, counter;
+
+ stack--;
+
+ clear_cinteger("arg");
+ clear_cstring("string_arg");
+
+ /* RECREATE THE arg ARRAY FOR THIS STACK FRAME */
+ for (index = 0; index < backup[stack].argcount; index++) {
+ if (index == 0) noun[3] = backup[stack].arguments[0];
+ add_cinteger("arg", backup[stack].arguments[index]);
+ }
+
+ /* RECREATE THE string_arg ARRAY FOR THIS STACK FRAME */
+ for (index = 0; index < backup[stack].argcount; index++) {
+ add_cstring("string_arg", backup[stack].str_arguments[index]);
+ }
+
+ /* RESTORE THE CONTENTS OF text_buffer */
+ for (counter = 0; counter < 1024; counter++)
+ text_buffer[counter] = backup[stack].text_buffer[counter];
+
+ /* RESTORE THE CONTENTS OF called_name */
+ //for (counter = 0; counter < 256; counter++)
+ //called_name[counter] = backup[stack].called_name[counter];
+ strncpy(called_name, backup[stack].called_name, 1024);
+
+ /* RESTORE THE CONTENTS OF scope_criterion */
+ //for (counter = 0; counter < 21; counter++)
+ // scope_criterion[counter] = backup[stack].scope_criterion[counter];
+ strncpy(scope_criterion, backup[stack].scope_criterion, 20);
+
+ /* RESTORE THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
+ * 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
+ strncpy(override, backup[stack].override, 80);
+ strncpy(default_function, backup[stack].default_function, 80);
+
+ /* RESTORE ALL THE WORD POINTERS */
+ for (counter = 0; counter < MAX_WORDS; counter++) {
+ word[counter] = backup[stack].word[counter];
+ quoted[counter] = backup[stack].quoted[counter];
+ }
+
+ executing_function = backup[stack].function;
+
+ if (executing_function != NULL) {
+ strncpy(function_name, executing_function->name, 80);
+ strncpy(cstring_resolve("function_name")->value, executing_function->name, 80);
+ }
+
+ wp = backup[stack].wp;
+ top_of_loop = backup[stack].top_of_loop;
+ outfile = backup[stack].outfile;
+ infile = backup[stack].infile;
+ top_of_select = backup[stack].top_of_select;
+ top_of_while = backup[stack].top_of_while;
+ top_of_iterate = backup[stack].top_of_iterate;
+ top_of_update = backup[stack].top_of_update;
+ top_of_do_loop = backup[stack].top_of_do_loop;
+ criterion_value = backup[stack].criterion_value;
+ criterion_type = backup[stack].criterion_type;
+ criterion_negate = backup[stack].criterion_negate;
+ current_level = backup[stack].current_level;
+ execution_level = backup[stack].execution_level;
+ loop_integer = backup[stack].loop_integer;
+ select_integer = backup[stack].select_integer;
+
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, backup[stack].address, seekmode_Start);
+#else
+ fseek(file, backup[stack].address, SEEK_SET);
+#endif
+
+}
+
+void push_stack(int32 file_pointer) {
+ /* COPY ALL THE CURRENT SYSTEM DATA ONTO THE STACK */
+ int index;
+ int counter = 0;
+
+ if (stack == STACK_SIZE) {
+ log_error("Stack overflow.", PLUS_STDERR);
+ terminate(45);
+ } else {
+ backup[stack].infile = infile;
+ infile = NULL;
+ backup[stack].outfile = outfile;
+ outfile = NULL;
+ backup[stack].function = executing_function;
+ backup[stack].address = file_pointer;
+ backup[stack].wp = wp;
+ backup[stack].top_of_loop = top_of_loop;
+ backup[stack].top_of_select = top_of_select;
+ backup[stack].top_of_while = top_of_while;
+ backup[stack].top_of_iterate = top_of_iterate;
+ backup[stack].top_of_update = top_of_update;
+ backup[stack].top_of_do_loop = top_of_do_loop;
+ backup[stack].criterion_value = criterion_value;
+ backup[stack].criterion_type = criterion_type;
+ backup[stack].criterion_negate = criterion_negate;
+ backup[stack].current_level = current_level;
+ backup[stack].execution_level = execution_level;
+ backup[stack].loop_integer = loop_integer;
+ backup[stack].select_integer = select_integer;
+
+ /* MAKE A COPY OF THE CURRENT CONTENTS OF text_buffer */
+ for (counter = 0; counter < 1024; counter++)
+ backup[stack].text_buffer[counter] = text_buffer[counter];
+
+ /* MAKE A COPY OF THE CURRENT CONTENTS OF called_name */
+ strncpy(backup[stack].called_name, called_name, 1024);
+
+ // MAKE A COPY OF THE CURRENT CONTENTS OF scope_criterion
+ strncpy(backup[stack].scope_criterion, scope_criterion, 20);
+
+ /* COPY THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
+ * 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
+ strncpy(backup[stack].override, override, 80);
+ strncpy(backup[stack].default_function, default_function, 80);
+
+ /* PUSH ALL THE WORD POINTERS ONTO THE STACK */
+ for (counter = 0; counter < MAX_WORDS; counter++) {
+ backup[stack].word[counter] = word[counter];
+ backup[stack].quoted[counter] = quoted[counter];
+ }
+
+ // PUSH ALL THE ARGUMENTS AS INTEGERS ONTO THE STACK
+ index = 0;
+ current_cinteger = cinteger_table;
+
+ if (current_cinteger != NULL) {
+ do {
+ if (!strcmp(current_cinteger->name, "arg")) {
+ backup[stack].arguments[index++] = current_cinteger->value;
+ }
+ current_cinteger = current_cinteger->next_cinteger;
+ } while (current_cinteger != NULL);
+ }
+
+ // STORE THE NUMBER OF ARGUMENTS PASSED TO THIS FUNCTION
+ // THIS IS THE SAME NUMBER FOR STRINGS AND INTEGERS
+ backup[stack].argcount = index;
+
+ // PUSH ALL THE ARGUMENTS AS STRINGS STRING ONTO THE STACK
+ index = 0;
+ current_cstring = cstring_table;
+
+ if (current_cstring != NULL) {
+ do {
+ if (!strcmp(current_cstring->name, "string_arg")) {
+ strncpy(backup[stack].str_arguments[index++], current_cstring->value, 255);
+ }
+
+ current_cstring = current_cstring->next_string;
+ } while (current_cstring != NULL);
+ }
+ }
+
+ // PUSH ON TO THE NEXT STACK FRAME
+ stack++;
+}
+
+void pop_proxy() {
+ int index, counter;
+
+ proxy_stack--;
+
+ clear_cinteger("$integer");
+ clear_cstring("$string");
+ clear_cstring("$word");
+
+ /* RECREATE THE integer ARRAY FOR THIS STACK FRAME */
+ for (index = 0; index < proxy_backup[proxy_stack].integercount; index++) {
+ add_cinteger("$integer", proxy_backup[proxy_stack].integer[index]);
+ }
+
+ /* RECREATE THE text ARRAY FOR THIS STACK FRAME */
+ for (index = 0; index < proxy_backup[proxy_stack].textcount; index++) {
+ add_cstring("$string", proxy_backup[proxy_stack].text[index]);
+ }
+
+ /* RECREATE THE $word ARRAY FOR THIS STACK FRAME */
+ for (index = 0; index < proxy_backup[proxy_stack].commandcount; index++) {
+ add_cstring("$word", proxy_backup[proxy_stack].command[index]);
+ }
+
+ /* RESTORE ALL THE NOUN POINTERS */
+ for (counter = 0; counter < 4; counter++)
+ noun[counter] = proxy_backup[proxy_stack].object_pointers[counter];
+
+ /* PUSH ALL THE RESOLVED OBJECTS ONTO THE STACK */
+ for (index = 0; index < 4; index++) {
+ list_size[index] = proxy_backup[proxy_stack].list_size[index];
+ max_size[index] = proxy_backup[proxy_stack].max_size[index];
+ for (counter = 0; counter < max_size[index]; counter++) {
+ object_list[index][counter] = proxy_backup[proxy_stack].object_list[index][counter];
+ }
+ }
+
+ start_of_this_command = proxy_backup[proxy_stack].start_of_this_command;
+ start_of_last_command = proxy_backup[proxy_stack].start_of_last_command;
+ after_from = proxy_backup[proxy_stack].after_from;
+ last_exact = proxy_backup[proxy_stack].last_exact;
+}
+
+void push_proxy() {
+ /* COPY ALL THE CURRENT SYSTEM DATA ONTO THE STACK */
+ int index;
+ int counter = 0;
+ int command = 0;
+ int text = 0;
+
+ current_cinteger = cinteger_table;
+ current_cstring = cstring_table;
+
+ if (proxy_stack == STACK_SIZE) {
+ log_error("Stack overflow.", PLUS_STDERR);
+ terminate(45);
+ } else {
+ proxy_backup[proxy_stack].start_of_this_command = start_of_this_command;
+ proxy_backup[proxy_stack].start_of_last_command = start_of_last_command;
+
+ /* PUSH ALL THE OBJECT POINTERS ONTO THE STACK */
+ for (counter = 0; counter < 4; counter++)
+ proxy_backup[proxy_stack].object_pointers[counter] = noun[counter];
+
+ /* PUSH ALL THE RESOLVED OBJECTS ONTO THE STACK */
+ for (index = 0; index < 4; index++) {
+ for (counter = 0; counter < max_size[index]; counter++) {
+ proxy_backup[proxy_stack].object_list[index][counter]
+ = object_list[index][counter];
+ }
+ proxy_backup[proxy_stack].list_size[index] = list_size[index];
+ proxy_backup[proxy_stack].max_size[index] = max_size[index];
+ }
+
+ /* PUSH ALL THE CURRENT COMMAND INTEGERS ONTO THE STACK */
+ counter = 0;
+
+ if (current_cinteger != NULL) {
+ do {
+ if (!strcmp(current_cinteger->name, "$integer")) {
+ proxy_backup[proxy_stack].integer[counter++] = current_cinteger->value;
+ }
+ current_cinteger = current_cinteger->next_cinteger;
+ } while (current_cinteger != NULL);
+ }
+
+ proxy_backup[proxy_stack].integercount = counter;
+
+ // PUSH ALL THE TEXT STRING SUPPLIED BY THE CURRENT COMMAND ONTO THE STACK
+ text = 0;
+ command = 0;
+
+ if (current_cstring != NULL) {
+ do {
+ if (!strcmp(current_cstring->name, "$string")) {
+ strncpy(proxy_backup[proxy_stack].text[text++], current_cstring->value, 255);
+ proxy_backup[proxy_stack].text[counter++][255] = 0;
+ } else if (!strcmp(current_cstring->name, "$word")) {
+ strncpy(proxy_backup[proxy_stack].command[command++], current_cstring->value, 255);
+ }
+
+ current_cstring = current_cstring->next_string;
+ } while (current_cstring != NULL);
+ }
+
+ proxy_backup[proxy_stack].textcount = counter;
+ proxy_backup[proxy_stack].commandcount = command;
+ proxy_backup[proxy_stack].after_from = after_from;
+ proxy_backup[proxy_stack].last_exact = last_exact;
+ }
+
+ // PUSH ON TO THE NEXT STACK FRAME
+ proxy_stack++;
+}
+
+int condition() {
+ /* COMPARE GROUPS OF TWO ELEMENTS. RETURN TRUE IF ANY ONE GROUP OF
+ * ELEMENTS COMPARE 'TRUE' */
+ int first;
+
+ first = 1;
+
+ while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
+ if (logic_test(first))
+ return (TRUE);
+ else
+ first = first + 3;
+ }
+ return (FALSE);
+}
+
+int and_condition() {
+ /* COMPARE GROUPS OF TWO ELEMENTS. RETURN FALSE IF ANY ONE GROUP OF
+ * ELEMENTS COMPARE 'FALSE' */
+ int first;
+
+ first = 1;
+
+ while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
+ if (logic_test(first) == FALSE)
+ return (FALSE);
+ else
+ first = first + 3;
+ }
+ return (TRUE);
+}
+
+int logic_test(int first) {
+ long index,
+ compare;
+
+ resolved_attribute = FALSE;
+
+ index = value_of(word[first], TRUE);
+ compare = value_of(word[first + 2], TRUE);
+
+ if (!strcmp(word[first + 1], "=") || !strcmp(word[first + 1], "==")) {
+ if (index == compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], ">")) {
+ if (index > compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "<")) {
+ if (index < compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "is")) {
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else
+ return (scope(index, word[first + 2]));
+ } else if (!strcmp(word[first + 1], "isnt")) {
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else
+ return (!scope(index, word[first + 2]));
+ } else if (!strcmp(word[first + 1], "has"))
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else {
+ if (resolved_attribute == SYSTEM_ATTRIBUTE) {
+ return (object[index]->attributes & compare);
+ } else {
+ return (object[index]->user_attributes & compare);
+ }
+ }
+ else if (!strcmp(word[first + 1], "hasnt"))
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else {
+ if (resolved_attribute == SYSTEM_ATTRIBUTE) {
+ return (!(object[index]->attributes & compare));
+ } else {
+ return (!(object[index]->user_attributes & compare));
+ }
+ }
+ else if (!strcmp(word[first + 1], "!=")
+ || !strcmp(word[first + 1], "<>")) {
+ if (index != compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], ">=")
+ || !strcmp(word[first + 1], "=>")) {
+ if (index >= compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "<=")
+ || !strcmp(word[first + 1], "=<")) {
+ if (index <= compare)
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "grandof")) {
+ /* GRANDOF SAYS THAT AN OBJECT IS THE EVENTUAL PARENT OF ANOTHER OBJECT, NOT
+ * NECESSARILY IMMEDIATE */
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else {
+ if (compare < 1 || compare > objects) {
+ unkobjrun(first + 2);
+ return (FALSE);
+ } else {
+ if (parent_of(index, compare, UNRESTRICT))
+ return (TRUE);
+ else
+ return (FALSE);
+ }
+ }
+ } else if (!strcmp(word[first + 1], "!grandof")) {
+ if (index < 1 || index > objects) {
+ unkobjrun(first);
+ return (FALSE);
+ } else {
+ if (compare < 1 || compare > objects) {
+ unkobjrun(first + 2);
+ return (FALSE);
+ } else {
+ if (parent_of(index, compare, UNRESTRICT))
+ return (FALSE);
+ else
+ return (TRUE);
+ }
+ }
+ } else {
+ sprintf(error_buffer,
+ "ERROR: In function \"%s\", illegal operator \"%s\".^",
+ executing_function->name, word[2]);
+ write_text(error_buffer);
+ return (FALSE);
+ }
+}
+
+int strcondition() {
+ int first;
+
+ first = 1;
+
+ while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
+ if (str_test(first))
+ return (TRUE);
+ else
+ first = first + 3;
+ }
+ return (FALSE);
+}
+
+int and_strcondition() {
+ int first;
+
+ first = 1;
+
+ while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
+ if (str_test(first) == FALSE)
+ return (FALSE);
+ else
+ first = first + 3;
+ }
+ return (TRUE);
+}
+
+int str_test(int first) {
+ char *index;
+ char *compare;
+
+ // GET THE TWO STRING VALUES TO COMPARE
+
+ index = arg_text_of_word(first);
+ compare = arg_text_of_word(first + 2);
+
+ if (!strcmp(word[first + 1], "==") || !strcmp(word[first + 1], "=")) {
+ if (!scumm_stricmp(index, compare)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ } else if (!strcmp(word[first + 1], "!contains")) {
+ if (strcasestr(index, compare))
+ return (FALSE);
+ else
+ return (TRUE);
+ } else if (!strcmp(word[first + 1], "contains")) {
+ if (strcasestr(index, compare))
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "<>") || !strcmp(word[first + 1], "!=")) {
+ if (scumm_stricmp(index, compare))
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "==C") || !strcmp(word[first + 1], "=C")) {
+ if (!strcmp(index, compare)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ } else if (!strcmp(word[first + 1], "!containsC")) {
+ if (strstr(index, compare))
+ return (FALSE);
+ else
+ return (TRUE);
+ } else if (!strcmp(word[first + 1], "containsC")) {
+ if (strstr(index, compare))
+ return (TRUE);
+ else
+ return (FALSE);
+ } else if (!strcmp(word[first + 1], "<>C") || !strcmp(word[first + 1], "!=C")) {
+ if (strcmp(index, compare))
+ return (TRUE);
+ else
+ return (FALSE);
+ } else {
+ sprintf(error_buffer,
+ "ERROR: In function \"%s\", illegal operator \"%s\".^",
+ executing_function->name, word[2]);
+ write_text(error_buffer);
+ return (FALSE);
+ }
+}
+
+void add_cinteger(char *name, int value) {
+ /* THIS FUNCTION ADDS A NEW JACL CONSTANT TO THE LIST */
+
+ if ((new_cinteger = (struct cinteger_type *)
+ malloc(sizeof(struct cinteger_type))) == NULL)
+ outofmem();
+ else {
+ if (cinteger_table == NULL) {
+ cinteger_table = new_cinteger;
+ } else {
+ /* FIND LAST CONSTANT IN LIST */
+ current_cinteger = cinteger_table;
+ while (current_cinteger->next_cinteger != NULL) {
+ current_cinteger = current_cinteger->next_cinteger;
+ }
+ current_cinteger->next_cinteger = new_cinteger;
+ }
+ strncpy(new_cinteger->name, name, 40);
+ new_cinteger->name[40] = 0;
+ new_cinteger->value = value;
+ new_cinteger->next_cinteger = NULL;
+ }
+}
+
+void clear_cinteger(char *name) {
+ /* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
+
+ //printf("--- clear integer %s\n", name);
+ if (cinteger_table != NULL) {
+ current_cinteger = cinteger_table;
+ previous_cinteger = cinteger_table;
+ while (current_cinteger != NULL) {
+ //sprintf(temp_buffer, "--- checking integer %s^", current_cinteger->name);
+ //write_text(temp_buffer);
+ if (!strcmp(current_cinteger->name, name)) {
+ //sprintf(temp_buffer, "--- found integer %s^", name);
+ //write_text(temp_buffer);
+ /* FREE THIS CONSTANT */
+ if (previous_cinteger == current_cinteger) {
+ // THE INTEGER BEING CLEARED IS THE FIRST INTEGER IN THE LIST
+ cinteger_table = current_cinteger->next_cinteger;
+ previous_cinteger = current_cinteger->next_cinteger;
+ free(current_cinteger);
+ current_cinteger = previous_cinteger;
+ } else {
+ previous_cinteger->next_cinteger = current_cinteger->next_cinteger;
+ free(current_cinteger);
+ current_cinteger = previous_cinteger->next_cinteger;
+ }
+ } else {
+ previous_cinteger = current_cinteger;
+ current_cinteger = current_cinteger->next_cinteger;
+ }
+ }
+ }
+ //printf("--- leaving clear integer\n");
+}
+
+void add_cstring(char *name, char *value) {
+ /* ADD A STRING CONSTANT WITH THE SUPPLIED NAME AND VALUE */
+
+ if ((new_string = (struct string_type *)
+ malloc(sizeof(struct string_type))) == NULL)
+ outofmem();
+ else {
+ if (cstring_table == NULL) {
+ cstring_table = new_string;
+ } else {
+ /* FIND LAST STRING IN LIST */
+ current_cstring = cstring_table;
+ while (current_cstring->next_string != NULL) {
+ current_cstring = current_cstring->next_string;
+ }
+ current_cstring->next_string = new_string;
+ }
+ strncpy(new_string->name, name, 40);
+ new_string->name[40] = 0;
+ strncpy(new_string->value, value, 255);
+ new_string->value[255] = 0;
+ new_string->next_string = NULL;
+ }
+}
+
+void clear_cstring(char *name) {
+ /* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
+ if (cstring_table != NULL) {
+ current_cstring = cstring_table;
+ previous_cstring = cstring_table;
+ while (current_cstring != NULL) {
+ if (!strcmp(current_cstring->name, name)) {
+ /* FREE THIS STRING */
+ if (previous_cstring == current_cstring) {
+ cstring_table = current_cstring->next_string;
+ previous_cstring = current_cstring->next_string;
+ free(current_cstring);
+ current_cstring = previous_cstring;
+ } else {
+ previous_cstring->next_string = current_cstring->next_string;
+ free(current_cstring);
+ current_cstring = previous_cstring->next_string;
+ }
+ } else {
+ previous_cstring = current_cstring;
+ current_cstring = current_cstring->next_string;
+ }
+ }
+ }
+}
+
+void inspect(int object_num) {
+ // THIS FUNCTION DISPLAYS THE STATE OF A JACL OBJECT FOR DEBUGGING
+
+ int index, attribute_value;
+
+ struct attribute_type *pointer = attribute_table;
+
+ if (object_num < 1 || object_num > objects) {
+ badptrrun(word[1], object_num);
+ return;
+ }
+
+ write_text("label: ");
+ write_text(object[object_num]->label);
+
+ if (object[object_num]->attributes & LOCATION) {
+ // OUTPUT ALL THE ATTRIBUTES WITH LOCATION ATTRIBUTE TEXT
+ write_text("^has location attributes: ");
+ index = 0;
+ attribute_value = 1;
+ while (location_attributes[index] != NULL) {
+ if (object[object_num]->attributes & attribute_value) {
+ write_text(location_attributes[index]);
+ }
+ index++;
+ attribute_value *= 2;
+ }
+ } else {
+ // OUTPUT ALL THE ATTRIBUTES WITH OBJECT ATTRIBUTE TEXT
+ write_text("^has object attributes: ");
+ index = 0;
+ attribute_value = 1;
+ while (object_attributes[index] != NULL) {
+ if (object[object_num]->attributes & attribute_value) {
+ write_text(object_attributes[index]);
+ }
+ index++;
+ attribute_value *= 2;
+ }
+
+ write_text("^has user attributes: ");
+ attribute_value = 1;
+ }
+
+ if (pointer != NULL) {
+ // THERE ARE USER ATTRIBUTES, SO CHECK IF THIS OBJECT OR LOCATION
+ // HAS ANY OF THEM
+ do {
+ if (object[object_num]->user_attributes & pointer->value) {
+ write_text(pointer->name);
+ write_text(" ");
+ }
+
+ pointer = pointer->next_attribute;
+ } while (pointer != NULL);
+ }
+
+ write_text("^");
+
+ index = 0;
+ if (object[object_num]->attributes & LOCATION) {
+ while (location_elements[index] != NULL) {
+ if (index < 12) {
+ if (object[object_num]->integer[index] < 1 || object[object_num]->integer[index] > objects) {
+ sprintf(temp_buffer, "%s: nowhere (%d)^", location_elements[index], object[object_num]->integer[index]);
+ } else {
+ sprintf(temp_buffer, "%s: %s (%d)^", location_elements[index], object[object[object_num]->integer[index]]->label, object[object_num]->integer[index]);
+ }
+ } else {
+ sprintf(temp_buffer, "%s: %d^", location_elements[index], object[object_num]->integer[index]);
+ }
+ write_text(temp_buffer);
+ index++;
+ }
+ } else {
+ while (object_elements[index] != NULL) {
+ if (index == 0) {
+ sprintf(temp_buffer, "%s: %s (%d)^", object_elements[index], object[object[object_num]->integer[index]]->label, object[object_num]->integer[index]);
+ } else {
+ sprintf(temp_buffer, "%s: %d^", object_elements[index], object[object_num]->integer[index]);
+ }
+ write_text(temp_buffer);
+ index++;
+ }
+ }
+}
+
+int grand_of(int child, int objs_only) {
+ /* THIS FUNCTION WILL CLIMB THE OBJECT TREE STARTING AT 'CHILD' UNTIL
+ * A 'PARENT' IS REACHED */
+
+ /* objs_only ARGUMENT TELLS FUNCTION TO IGNORE OBJECT IF IT IS IN A
+ * LOCATION */
+
+ int parent;
+
+ if (object[child]->PARENT != NOWHERE) {
+ /* STORE THE CHILDS PARENT OBJECT */
+ parent = object[child]->PARENT;
+
+ if (object[parent]->attributes & LOCATION) {
+ if (objs_only) {
+ /* THE CHILDS PARENT IS LOCATION AND SEARCH IS RESTRICTED TO
+ * OBJECTS */
+ return (child);
+ } else {
+ return (parent);
+ }
+ } else {
+ /* KEEP LOOKING UP THE TREE UNTIL THE CHILD HAS NO
+ * PARENT */
+ return (grand_of(parent, objs_only));
+ }
+ } else {
+ /* THE SPECIFIED OBJECT HAS NO PARENT */
+ return (child);
+ }
+}
+
+int select_next() {
+ while (++*select_integer <= objects) {
+ switch (criterion_type) {
+ case CRI_ATTRIBUTE:
+ if (object[*select_integer]->attributes & criterion_value) {
+ if (!criterion_negate) {
+ return TRUE;
+ }
+ } else {
+ if (criterion_negate) {
+ return TRUE;
+ }
+ }
+ break;
+ case CRI_USER_ATTRIBUTE:
+ if (object[*select_integer]->user_attributes & criterion_value) {
+ if (!criterion_negate) {
+ return TRUE;
+ }
+ } else {
+ if (criterion_negate) {
+ return TRUE;
+ }
+ }
+ break;
+ case CRI_PARENT:
+ if (object[*select_integer]->PARENT == criterion_value) {
+ if (!criterion_negate) {
+ return TRUE;
+ }
+ } else {
+ if (criterion_negate) {
+ return TRUE;
+ }
+ }
+ break;
+ case CRI_SCOPE:
+ if (scope(*select_integer, scope_criterion)) {
+ if (!criterion_negate) {
+ return TRUE;
+ }
+ } else {
+ if (criterion_negate) {
+ return TRUE;
+ }
+ }
+ break;
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Converts an integer value to its hex character*/
+char to_hex(char code) {
+ static char hex[] = "0123456789abcdef";
+ return hex[code & 15];
+}
+
+/* Returns a url-encoded version of str */
+/* IMPORTANT: be sure to free() the returned string after use */
+char *url_encode(char *str) {
+ char *pstr = str, *buf = (char *)malloc(strlen(str) * 3 + 1), *pbuf = buf;
+ while (*pstr) {
+ if (Common::isAlnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
+ *pbuf++ = *pstr;
+ else if (*pstr == ' ')
+ *pbuf++ = '+';
+ else
+ *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
+ pstr++;
+ }
+ *pbuf = '\0';
+ return buf;
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
index 0178b1c..c967a88 100644
--- a/engines/glk/jacl/jacl.cpp
+++ b/engines/glk/jacl/jacl.cpp
@@ -21,7 +21,7 @@
*/
#include "glk/jacl/jacl.h"
-#include "glk/jacl/common/config-manager.h"
+#include "common/config-manager.h"
namespace Glk {
namespace JACL {
@@ -29,7 +29,7 @@ namespace JACL {
JACL *g_vm;
JACL::JACL(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
- _saveSlot(-1) {
+ _saveSlot(-1) {
g_vm = this;
}
diff --git a/engines/glk/jacl/jacl.h b/engines/glk/jacl/jacl.h
index ce04c89..b49b121 100644
--- a/engines/glk/jacl/jacl.h
+++ b/engines/glk/jacl/jacl.h
@@ -77,7 +77,9 @@ public:
/**
* Returns true if a savegame is being loaded directly from the ScummVM launcher
*/
- bool loadingSavegame() const { return _saveSlot != -1; }
+ bool loadingSavegame() const {
+ return _saveSlot != -1;
+ }
};
extern JACL *g_vm;
diff --git a/engines/glk/jacl/jacl_main.cpp b/engines/glk/jacl/jacl_main.cpp
new file mode 100644
index 0000000..6b77f85
--- /dev/null
+++ b/engines/glk/jacl/jacl_main.cpp
@@ -0,0 +1,1582 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/csv.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/prototypes.h"
+#include "glk/jacl/version.h"
+
+namespace Glk {
+namespace JACL {
+
+int convert_to_utf32(unsigned char *text);
+
+glui32 status_width, status_height;
+
+schanid_t sound_channel[8] = { NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+ };
+
+event_t *cancelled_event;
+
+extern struct csv_parser parser_csv;
+
+extern char text_buffer[];
+extern char *word[];
+extern short int quoted[];
+extern short int punctuated[];
+extern int wp;
+
+extern int custom_error;
+extern int interrupted;
+
+extern int jpp_error;
+
+extern int it;
+extern int them[];
+extern int her;
+extern int him;
+
+extern int oops_word;
+
+#ifdef WINGLK
+struct string_type *resolved_string;
+#endif
+
+char include_directory[81] = "\0";
+char temp_directory[81] = "\0";
+char data_directory[81] = "\0";
+char special_prompt[81] = "\n: \0";
+char file_prompt[5] = ": \0";
+char bookmark[81] = "\0";
+char walkthru[81] = "\0";
+
+char function_name[81];
+
+extern char default_function[84];
+char override[81];
+
+char temp_buffer[1024];
+char error_buffer[1024];
+unsigned char chunk_buffer[4096];
+#ifndef NOUNICODE
+glui32 chunk_buffer_uni[4096];
+#endif
+char proxy_buffer[1024];
+
+char oops_buffer[1024];
+char oopsed_current[1024];
+char last_command[1024];
+char *blank_command = "blankjacl\0";
+char *current_command = (char *) NULL;
+char command_buffer[1024];
+#ifndef NOUNICODE
+glui32 command_buffer_uni[1024];
+#endif
+char players_command[1024];
+
+int walkthru_running = FALSE;
+
+int start_of_last_command;
+int start_of_this_command;
+
+int objects, integers, functions, strings;
+
+/* A STREAM FOR THE GAME FILE, WHEN IT'S OPEN. */
+strid_t game_stream = NULL;
+
+/* THE STREAM FOR OPENING UP THE ARCHIVE CONTAINING GRAPHICS AND SOUND */
+strid_t blorb_stream;
+
+/* A FILE REFERENCE FOR THE TRANSCRIPT FILE. */
+static frefid_t script_fref = NULL;
+/* A STREAM FOR THE TRANSCRIPT FILE, WHEN IT'S OPEN. */
+static strid_t script_stream = NULL;
+
+int noun[4];
+int player = 0;
+
+int noun3_backup;
+int player_backup = 0;
+
+int variable_contents;
+int oec;
+int *object_element_address,
+ *object_backup_address;
+
+short int spaced = TRUE;
+
+int delay = 0;
+
+/* START OF GLK STUFF */
+
+/* POINTERS TO THE GLK WINDOWS */
+winid_t mainwin = NULL;
+winid_t statuswin = NULL;
+winid_t promptwin = NULL;
+winid_t inputwin = NULL;
+winid_t current_window = NULL;
+
+/* POINTERS TO THE WINDOWS STREAMS */
+strid_t mainstr = NULL;
+strid_t statusstr = NULL;
+strid_t promptstr = NULL;
+strid_t inputstr = NULL;
+
+/* END OF GLK STUFF */
+
+char user_id[] = "local";
+char prefix[81] = "\0";
+char blorb[81] = "\0";
+char game_path[256] = "\0";
+char game_file[256] = "\0";
+char processed_file[256] = "\0";
+
+struct object_type *object[MAX_OBJECTS];
+struct integer_type *integer_table = NULL;
+struct cinteger_type *cinteger_table = NULL;
+struct window_type *window_table = NULL;
+struct attribute_type *attribute_table = NULL;
+struct string_type *string_table = NULL;
+struct string_type *cstring_table = NULL;
+struct function_type *function_table = NULL;
+struct function_type *executing_function = NULL;
+struct command_type *completion_list = NULL;
+struct word_type *grammar_table = NULL;
+struct synonym_type *synonym_table = NULL;
+struct filter_type *filter_table = NULL;
+
+// Forward declarations
+static void word_check();
+static void version_info();
+
+
+void glk_main() {
+ int index;
+ frefid_t blorb_file;
+
+ override[0] = 0;
+
+ /* ALLOC AN EVENT TO STORE A CANCELLED EVENT IN */
+ if ((cancelled_event = (event_t *) malloc(sizeof(event_t))) == NULL)
+ outofmem();
+
+ /* CREATE style_User1 FOR USE IN THE STATUS LINE */
+ g_vm->glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
+ g_vm->glk_stylehint_set(wintype_TextBuffer, style_User2, stylehint_ReverseColor, 1);
+
+ /* OPEN THE MAIN WINDOW THE GLK WINDOWS */
+ mainwin = g_vm->glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+
+ if (!mainwin) {
+ /* IT'S POSSIBLE THAT THE MAIN WINDOW FAILED TO OPEN. THERE's
+ * NOTHING WE CAN DO WITHOUT IT, SO EXIT. */
+ return;
+ } else {
+ /* GET A REFERENCE TO mainwin's STREAM */
+ mainstr = g_vm->glk_window_get_stream(mainwin);
+ }
+
+ /* SET THE CURRENT OUTPUT STREAM TO PRINT TO IT. */
+ jacl_set_window(mainwin);
+
+ /* OPEN A THIRD WINDOW: A TEXT GRID, BELOW THE MAIN WINDOW, ONE LINE
+ * HIGH. THIS IS THE WINDOW TO DISPLAY THE COMMAND PROMPT IN */
+ //promptwin = g_vm->glk_window_open(mainwin, winmethod_Below | winmethod_Fixed,
+ // 3, wintype_TextBuffer, 0);
+
+ /* SET THIS TO DETERMINE THE SYTEM OF INPUT TO USE */
+ //inputwin = promptwin;
+ inputwin = mainwin;
+
+ if (jpp_error) {
+ /* THERE WAS AN ERROR DURING PREPROCESSING. NOW THAT THERE IS AN
+ * OPEN GLK WINDOW, OUTPUT THE ERROR MESSAGE AND EXIT */
+ log_error(error_buffer, FALSE);
+ terminate(200);
+ }
+
+ /* OPEN THE BLORB FILE IF ONE EXISTS */
+#ifndef WINGLK
+ blorb_file = g_vm->glk_fileref_create_by_name(fileusage_BinaryMode, blorb, 0);
+#else
+ strcpy(temp_buffer, game_path);
+ strcat(temp_buffer, blorb);
+ strcpy(blorb, temp_buffer);
+ blorb_file = wing_vm->glk_fileref_create_by_name(fileusage_BinaryMode, blorb, 0, 0);
+#endif
+
+#ifdef UNUSED
+ if (blorb_file != NULL && g_vm->glk_fileref_does_file_exist(blorb_file)) {
+ blorb_stream = g_vm->glk_stream_open_file(blorb_file, filemode_Read, 0);
+
+ if (blorb_stream != NULL) {
+ /* IF THE FILE EXISTS, SET THE RESOURCE MAP */
+ giblorb_set_resource_map(blorb_stream);
+ }
+ }
+#endif
+ // INTIALISE THE CSV PARSER
+ csv_init(&parser_csv, CSV_APPEND_NULL);
+
+ /* NO PREPROCESSOR ERRORS, LOAD THE GAME FILE */
+ read_gamefile();
+
+ execute("+bootstrap");
+
+ // OPEN A SECOND WINDOW: A TEXT GRID, ABOVE THE MAIN WINDOW, ONE LINE
+ // HIGH. IT IS POSSIBLE THAT THIS WILL FAIL ALSO, BUT WE ACCEPT THAT.
+ statuswin = g_vm->glk_window_open(mainwin, winmethod_Above | winmethod_Fixed,
+ 0, wintype_TextGrid, 0);
+
+ // GET A REFERENCE TO statuswin's STREAM
+ if (statuswin != NULL) {
+ statusstr = g_vm->glk_window_get_stream(statuswin);
+ }
+
+#ifdef WINGLK
+ if ((resolved_string = cstring_resolve("game_title")) != NULL) {
+ wing_vm->glk_window_set_title(resolved_string->value);
+ } else {
+ sprintf(temp_buffer, "JACL v%d.%d.%d ", J_VERSION, J_RELEASE, J_BUILD);
+ wing_vm->glk_window_set_title(temp_buffer);
+ }
+#endif
+
+ if (SOUND_SUPPORTED->value) {
+ /* CREATE THE EIGHT SOUND CHANNELS */
+ for (index = 0; index < 8; index++) {
+ sound_channel[index] = g_vm->glk_schannel_create(0);
+ }
+ }
+
+ jacl_set_window(mainwin);
+
+ execute("+intro");
+
+ if (object[2] == NULL) {
+ log_error(CANT_RUN, PLUS_STDERR);
+ terminate(43);
+ }
+
+ /* DUMMY RETRIEVE OF 'HERE' FOR TESTING OF GAME STATE */
+ get_here();
+
+ eachturn();
+
+ /* TOP OF COMMAND LOOP */
+ do {
+ int gotline;
+ event_t ev;
+
+ custom_error = FALSE;
+
+ jacl_set_window(mainwin);
+
+ execute("+bottom");
+
+ status_line();
+
+ if (current_command != NULL) {
+ strcpy(last_command, current_command);
+ }
+
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ jacl_set_window(inputwin);
+ }
+
+ /* OUTPUT THE CUSTOM COMMAND PROMPT */
+ write_text(string_resolve("command_prompt")->value);
+
+#ifdef NOUNICODE
+ g_vm->glk_request_line_event(inputwin, command_buffer, 255, 0);
+#else
+ g_vm->glk_request_line_event_uni(inputwin, command_buffer_uni, 255, 0);
+#endif
+
+ jacl_set_window(inputwin);
+
+ gotline = FALSE;
+
+ while (!gotline) {
+ /* GRAB AN EVENT. */
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+
+ case evtype_LineInput:
+ if (ev.window == inputwin) {
+ gotline = TRUE;
+ jacl_set_window(mainwin);
+ /* REALLY THE EVENT CAN *ONLY* BE FROM MAINWIN,
+ * BECAUSE WE NEVER REQUEST LINE INPUT FROM THE
+ * STATUS WINDOW. BUT WE DO A PARANOIA TEST,
+ * BECAUSE COMMANDBUF IS ONLY FILLED IF THE LINE
+ * EVENT COMES FROM THE MAINWIN REQUEST. IF THE
+ * LINE EVENT COMES FROM ANYWHERE ELSE, WE IGNORE
+ * IT. */
+ }
+ break;
+
+ case evtype_SoundNotify:
+ /* A SOUND HAS FINISHED PLAYING CALL +sound_finished
+ * WITH THE RESOUCE NUMBER AS THE FIRST ARGUMENT
+ * AND THE CHANNEL NUMBER AS THE SECOND ARGUMENT */
+ sprintf(temp_buffer, "+sound_finished<%d<%d", (int) ev.val1, (int) ev.val2 - 1);
+ execute(temp_buffer);
+ break;
+
+ case evtype_Timer:
+ /* A TIMER EVENT IS TRIGGERED PERIODICALLY IF THE GAME
+ * REQUESTS THEM. THIS SIMPLY EXECUTES THE FUNCTION
+ * +timer WHICH IS LIKE +eachturn EXCEPT IT DOESN'T
+ * WAIT FOR THE PLAYER TO TYPE A COMMAND */
+
+ jacl_set_window(mainwin);
+ execute("+timer");
+ break;
+
+ case evtype_Arrange:
+ /* WINDOWS HAVE CHANGED SIZE, SO WE HAVE TO REDRAW THE
+ * STATUS WINDOW. */
+ status_line();
+ break;
+ }
+ }
+
+ // THE PLAYER'S INPUT WILL BE UTF-32. CONVERT IT TO UTF-8 AND NULL TERMINATE IT
+#ifndef NOUNICODE
+ convert_to_utf8(command_buffer_uni, ev.val1);
+#endif
+
+ current_command = command_buffer;
+
+ /* SET ALL THE OUTPUT TO GO TO mainwin NOW THE COMMAND HAS BEEN READ */
+ if (inputwin == promptwin) {
+ jacl_set_window(mainwin);
+ write_text(string_resolve("command_prompt")->value);
+ g_vm->glk_set_style(style_Input);
+ write_text(current_command);
+ g_vm->glk_set_style(style_Normal);
+ write_text("^");
+ }
+
+ execute("+top");
+
+ index = 0;
+
+ if (*current_command) {
+ while (*(current_command + index) && index < 1024) {
+ if (*(current_command + index) == '\r' || *(current_command + index) == '\n') {
+ break;
+ } else {
+ text_buffer[index] = *(current_command + index);
+ index++;
+ }
+ }
+ }
+
+ text_buffer[index] = 0;
+
+ if (text_buffer[0] == 0) {
+ /* NO COMMAND WAS SPECIFIED, FILL THE COMMAND IN AS 'blankjacl'
+ * FOR THE GAME TO PROCESS AS DESIRED */
+ strcpy(text_buffer, "blankjacl");
+ current_command = blank_command;
+ }
+
+ command_encapsulate();
+ jacl_truncate();
+
+ index = 0;
+
+ /* SET THE INTEGER INTERRUPTED TO FALSE. IF THIS IS SET TO
+ * TRUE BY ANY COMMAND, FURTHER PROCESSING WILL STOP */
+ INTERRUPTED->value = FALSE;
+
+ interrupted = FALSE;
+
+ if (word[0] != NULL) {
+ if (strcmp(word[0], "undo")) {
+ /* COMMAND DOES NOT EQUAL undo */
+ save_game_state();
+ }
+
+ if (word[0][0] == '*') {
+ if (script_stream) {
+ write_text(cstring_resolve("COMMENT_RECORDED")->value);
+ } else {
+ write_text(cstring_resolve("COMMENT_IGNORED")->value);
+ }
+ } else {
+ /* COMMAND IS NOT NULL, START PROCESSING IT */
+ preparse();
+ }
+ } else {
+ /* NO COMMAND WAS SPECIFIED, FILL THE COMMAND IN AS 'blankjacl'
+ * FOR THE GAME TO PROCESS AS DESIRED */
+ strcpy(text_buffer, "blankjacl");
+ command_encapsulate();
+ preparse();
+ }
+
+ } while (TRUE);
+}
+
+void preparse() {
+ int position;
+
+ // THE INTERRUPTED VARIABLE IS USED TO STOP LATER ACTIONS IN A COMMAND
+ // IF ANY ONE
+ while (word[wp] != NULL && INTERRUPTED->value == FALSE) {
+ //printf("--- preparse %s\n", word[wp]);
+ // PROCESS THE CURRENT COMMAND
+ // CREATE THE command STRINGS FROM THIS POINT ONWARDS SO THE VERB OF
+ // THE CURRENT COMMAND IS ALWAYS command[0].
+
+ clear_cstring("command");
+
+ position = wp;
+
+ while (word[position] != NULL && strcmp(word[position], cstring_resolve("THEN_WORD")->value)) {
+ add_cstring("command", word[position]);
+ position++;
+ };
+
+ // PROCESS THE COMMAND
+ word_check();
+
+ /* THE PREVIOUS COMMAND HAS FINISHED, LOOK FOR ANOTHER COMMAND */
+ while (word[wp] != NULL) {
+ if (word[wp] != NULL && !strcmp(word[wp], cstring_resolve("THEN_WORD")->value)) {
+ wp++;
+ break;
+ }
+ wp++;
+ }
+ }
+}
+
+void word_check() {
+ int index;
+
+ /* REMEMBER THE START OF THIS COMMAND TO SUPPORT 'oops' AND 'again' */
+ start_of_this_command = wp;
+ //printf("--- command starts at %d\n", start_of_this_command);
+
+ /* START CHECKING THE PLAYER'S COMMAND FOR SYSTEM COMMANDS */
+ if (!strcmp(word[wp], cstring_resolve("QUIT_WORD")->value) || !strcmp(word[wp], "q")) {
+ if (execute("+quit_game") == FALSE) {
+ TIME->value = FALSE;
+ write_text(cstring_resolve("SURE_QUIT")->value);
+ if (get_yes_or_no()) {
+ newline();
+ execute("+score");
+ terminate(0);
+ } else {
+ write_text(cstring_resolve("RETURN_GAME")->value);
+ }
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("RESTART_WORD")->value)) {
+ if (execute("+restart_game") == FALSE) {
+ TIME->value = FALSE;
+ write_text(cstring_resolve("SURE_RESTART")->value);
+ if (get_yes_or_no()) {
+ write_text(cstring_resolve("RESTARTING")->value);
+ restart_game();
+ g_vm->glk_window_clear(current_window);
+ execute("+intro");
+ eachturn();
+ } else {
+ write_text(cstring_resolve("RETURN_GAME")->value);
+ }
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("UNDO_WORD")->value)) {
+ if (execute("+undo_move") == FALSE) {
+ undoing();
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("OOPS_WORD")->value) || !strcmp(word[wp], "o")) {
+ //printf("--- oops word is %d\n", oops_word);
+ if (word[++wp] != NULL) {
+ if (oops_word == -1) {
+ if (TOTAL_MOVES->value == 0) {
+ write_text(cstring_resolve("NO_MOVES")->value);
+ TIME->value = FALSE;
+ } else {
+ write_text(cstring_resolve("CANT_CORRECT")->value);
+ TIME->value = FALSE;
+ }
+ } else {
+ strcpy(oops_buffer, word[wp]);
+ strcpy(text_buffer, last_command);
+ command_encapsulate();
+ //printf("--- trying to replace %s with %s\n", word[oops_word], oops_buffer);
+ jacl_truncate();
+ word[oops_word] = (char *) &oops_buffer;
+
+ /* BUILD A PLAIN STRING REPRESENTING THE NEW COMMAND */
+ oopsed_current[0] = 0;
+ index = 0;
+
+ while (word[index] != NULL) {
+ if (oopsed_current[0] != 0) {
+ strcat(oopsed_current, " ");
+ }
+
+ strcat(oopsed_current, word[index]);
+
+ index++;
+ }
+
+ current_command = oopsed_current;
+ //printf("--- current command is: %s\n", current_command);
+
+ /* PROCESS THE FIXED COMMAND ONLY */
+ wp = start_of_last_command;
+ word_check();
+ }
+ } else {
+ write_text(cstring_resolve("BAD_OOPS")->value);
+ TIME->value = FALSE;
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("AGAIN_WORD")->value) || !strcmp(word[wp], "g")) {
+ if (TOTAL_MOVES->value == 0) {
+ write_text(cstring_resolve("NO_MOVES")->value);
+ TIME->value = FALSE;
+ } else if (last_command[0] == 0) {
+ write_text(cstring_resolve("NOT_CLEVER")->value);
+ TIME->value = FALSE;
+ } else {
+ strcpy(text_buffer, last_command);
+ current_command = last_command;
+ command_encapsulate();
+ jacl_truncate();
+ //printf("--- command started at %d\n", start_of_last_command);
+ wp = start_of_last_command;
+ word_check();
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("SCRIPT_WORD")->value) || !strcmp(word[wp], "transcript")) {
+ scripting();
+ } else if (!strcmp(word[wp], cstring_resolve("UNSCRIPT_WORD")->value)) {
+ if (!script_stream) {
+ write_text(cstring_resolve("SCRIPTING_ALREADY_OFF")->value);
+ } else {
+ /* Close the file. */
+ g_vm->glk_put_string_stream(script_stream, "\nEND OF A TRANSCRIPT\n");
+ g_vm->glk_stream_close(script_stream, NULL);
+ write_text(cstring_resolve("SCRIPTING_OFF")->value);
+ script_stream = NULL;
+ }
+ } else if (!strcmp(word[wp], cstring_resolve("WALKTHRU_WORD")->value)) {
+ walking_thru();
+ } else if (!strcmp(word[wp], cstring_resolve("INFO_WORD")->value) || !strcmp(word[wp], "version")) {
+ version_info();
+ write_text("you can redistribute it and/or modify it under the ");
+ write_text("terms of the GNU General Public License as published by ");
+ write_text("the Free Software Foundation; either version 2 of the ");
+ write_text("License, or any later version.^^");
+ write_text("This program is distributed in the hope that it will be ");
+ write_text("useful, but WITHOUT ANY WARRANTY; without even the ");
+ write_text("implied warranty of MERCHANTABILITY or FITNESS FOR A ");
+ write_text("PARTICULAR PURPOSE. See the GNU General Public License ");
+ write_text("for more details.^^");
+ write_text("You should have received a copy of the GNU General ");
+ write_text("Public License along with this program; if not, write ");
+ write_text("to the Free Software Foundation, Inc., 675 Mass Ave, ");
+ write_text("Cambridge, MA 02139, USA.^^");
+ sprintf(temp_buffer, "OBJECTS DEFINED: %d^", objects);
+ write_text(temp_buffer);
+ TIME->value = FALSE;
+ } else {
+ /* NO WORD HAS BEEN MARKED AS AN ERROR YET*/
+ oops_word = -1;
+
+ /* THIS IS NOT A SYSTEM COMMAND, CALL parser TO PROCESS THE COMMAND */
+ parser();
+ }
+
+ start_of_last_command = start_of_this_command;
+}
+
+void version_info() {
+ char buffer[80];
+
+ sprintf(buffer, "JACL Interpreter v%d.%d.%d ", J_VERSION, J_RELEASE,
+ J_BUILD);
+ write_text(buffer);
+ sprintf(buffer, "/ %d object.^", MAX_OBJECTS);
+ write_text(buffer);
+ write_text("Copyright (c) 1992-2010 Stuart Allen.^^");
+}
+
+void save_game_state() {
+ /* THIS FUNCTION MAKES AN IN-MEMORY COPY OF THE GAME STATE AFTER EACH
+ * OF THE PLAYER'S COMMANDS SO THE 'undo' COMMAND CAN BE USED */
+ int index,
+ counter;
+
+ struct integer_type *current_integer = integer_table;
+ struct function_type *current_function = function_table;
+
+ do {
+ current_function->call_count_backup = current_function->call_count;
+ current_function = current_function->next_function;
+ } while (current_function != NULL);
+
+ do {
+ current_integer->value_backup = current_integer->value;
+ current_integer = current_integer->next_integer;
+ } while (current_integer != NULL);
+
+ for (index = 1; index <= objects; index++) {
+ if (object[index]->nosave)
+ continue;
+
+ for (counter = 0; counter < 16; counter++) {
+ object[index]->integer_backup[counter] =
+ object[index]->integer[counter];
+ }
+
+ object[index]->attributes_backup = object[index]->attributes;
+ object[index]->user_attributes_backup = object[index]->user_attributes;
+ }
+
+ player_backup = player;
+ noun3_backup = noun[3];
+}
+
+int save_interaction(char *filename) {
+ frefid_t saveref;
+
+ jacl_set_window(inputwin);
+
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ newline();
+ }
+
+ if (filename == NULL) {
+ saveref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame | fileusage_BinaryMode, filemode_Write, 0);
+ } else {
+ saveref = g_vm->glk_fileref_create_by_name(fileusage_SavedGame | fileusage_BinaryMode, filename, 0);
+
+ }
+
+ jacl_set_window(mainwin);
+
+ if (!saveref) {
+ write_text(cstring_resolve("CANT_SAVE")->value);
+ return (FALSE);
+ } else {
+ if (save_game(saveref)) {
+ return (TRUE);
+ } else {
+ write_text(cstring_resolve("CANT_SAVE")->value);
+ return (FALSE);
+ }
+ }
+}
+
+void restore_game_state() {
+ /* THIS FUNCTION IS CALLED AS A RESULT OF THE PLAYER USING THE 'undo'
+ * COMMAND */
+ int index,
+ counter;
+
+ struct integer_type *current_integer = integer_table;
+ struct function_type *current_function = function_table;
+
+ do {
+ current_function->call_count = current_function->call_count_backup;
+ current_function = current_function->next_function;
+ } while (current_function != NULL);
+
+
+ do {
+ current_integer->value = current_integer->value_backup;
+ current_integer = current_integer->next_integer;
+ } while (current_integer != NULL);
+
+ for (index = 1; index <= objects; index++) {
+ if (object[index]->nosave)
+ continue;
+
+ for (counter = 0; counter < 16; counter++)
+ object[index]->integer[counter] =
+ object[index]->integer_backup[counter];
+
+ object[index]->attributes = object[index]->attributes_backup;
+ object[index]->user_attributes = object[index]->user_attributes_backup;
+ }
+
+ player = player_backup;
+ noun[3] = noun3_backup;
+
+ write_text(cstring_resolve("MOVE_UNDONE")->value);
+ object[HERE]->attributes &= ~1;
+ execute("+top");
+ execute("+look_around");
+ execute("+bottom");
+ TIME->value = FALSE;
+}
+
+void write_text(char *string_buffer) {
+ int index,
+ length;
+
+ if (!strcmp(string_buffer, "tilde")) {
+ g_vm->glk_put_string("~");
+ return;
+ } else if (!strcmp(string_buffer, "caret")) {
+ g_vm->glk_put_string("^");
+ return;
+ }
+
+ length = strlen(string_buffer);
+
+ for (index = 0; index < length; index++) {
+ if (*(string_buffer + index) == '^') {
+ chunk_buffer[index] = '\n';
+ } else if (*(string_buffer + index) == '~') {
+ chunk_buffer[index] = '\"';
+ } else {
+ chunk_buffer[index] = *(string_buffer + index);
+ }
+ }
+
+ chunk_buffer[index] = 0;
+
+ /* PRINT THE CONTENTS OF string_buffer */
+#ifdef NOUNICODE
+ g_vm->glk_put_string(chunk_buffer);
+#else
+ chunk_buffer_uni[(glui32) convert_to_utf32(chunk_buffer)] = 0;
+ g_vm->glk_put_string_uni(chunk_buffer_uni);
+#endif
+}
+
+void jacl_sleep(unsigned int mseconds) {
+ g_system->delayMillis(mseconds);
+}
+
+void status_line() {
+ int cursor, index;
+ winid_t pair_window;
+
+ if (!statuswin) {
+ return;
+ } else {
+ // THERE IS AN EXISTING STATUS WINDOW, MAKE SURE A NEW SIZE HASN'T BEEN
+ // REQUESTED
+ g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
+ if (status_height != (uint)integer_resolve("status_window")->value) {
+ // HEIGHT HAS CHANGED, UPDATE THE WINDOW
+ pair_window = g_vm->glk_window_get_parent(statuswin);
+ g_vm->glk_window_set_arrangement(pair_window, winmethod_Above | winmethod_Fixed, integer_resolve("status_window")->value, statuswin);
+ g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
+ }
+ }
+
+ if (status_height == 0) {
+ // THE STATUS WINDOW CAN'T BE CLOSED, ONLY SET TO HAVE A HEIGHT OF ZERO
+ return;
+ }
+
+ jacl_set_window(statuswin);
+ g_vm->glk_window_clear(statuswin);
+
+ if (execute("+update_status_window") == FALSE) {
+ g_vm->glk_set_style(style_User1);
+
+ /* DISPLAY THE INVERSE STATUS LINE AT THE TOP OF THE SCREEN */
+ for (index = 0; index < (int)status_width; index++) {
+ temp_buffer[index] = ' ';
+ }
+ temp_buffer[index] = 0;
+ write_text(temp_buffer);
+
+ /* PRINT THE LOCATION'S TITLE ON THE LEFT. */
+ g_vm->glk_window_move_cursor(statuswin, 1, 0);
+ write_text(sentence_output(HERE, TRUE));
+
+ /* BUILD THE SCORE/ MOVES STRING */
+ temp_buffer[0] = 0;
+ sprintf(temp_buffer, "Score: %d Moves: %d", SCORE->value, TOTAL_MOVES->value);
+
+ cursor = status_width - strlen(temp_buffer);
+ cursor--;
+ g_vm->glk_window_move_cursor(statuswin, cursor, 0);
+ write_text(temp_buffer);
+ }
+
+ jacl_set_window(mainwin);
+
+}
+
+void newline() {
+ /* START A NEW LINE ON THE SCREEN */
+ write_text("\n");
+}
+
+void more(char *message) {
+ int character;
+
+ jacl_set_window(inputwin);
+
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ newline();
+ }
+
+ g_vm->glk_set_style(style_Emphasized);
+ write_text(message);
+ g_vm->glk_set_style(style_Normal);
+
+ character = get_key();
+
+ if (inputwin == mainwin) newline();
+}
+
+int get_key() {
+ event_t ev;
+
+ g_vm->glk_request_char_event(inputwin);
+
+ while (1) {
+
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+ case evtype_CharInput:
+ if (ev.window == inputwin) {
+ return (ev.val1);
+ }
+ break;
+ }
+ }
+
+}
+
+int get_number(int insist, int low, int high) {
+ char *cx;
+ char commandbuf[256];
+ int response;
+ int gotline;
+ event_t ev;
+
+ status_line();
+
+ sprintf(temp_buffer, cstring_resolve("TYPE_NUMBER")->value, low, high);
+
+ /* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
+
+ while (1) {
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ jacl_set_window(inputwin);
+ }
+
+ write_text(temp_buffer);
+ jacl_set_window(mainwin);
+
+ g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
+
+ gotline = FALSE;
+ while (!gotline) {
+
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+ case evtype_LineInput:
+ if (ev.window == inputwin) {
+ gotline = TRUE;
+ }
+ break;
+
+ case evtype_Arrange:
+ status_line();
+ break;
+ }
+ }
+
+ commandbuf[ev.val1] = '\0';
+ for (cx = commandbuf; *cx == ' '; cx++) { };
+
+ if (validate(cx)) {
+ response = atoi(cx);
+ if (response >= low && response <= high) {
+ return (response);
+ }
+ }
+
+ if (!insist) {
+ return (-1);
+ } else {
+ write_text(cstring_resolve("INVALID_SELECTION")->value);
+ }
+ }
+}
+
+void get_string(char *string_buffer) {
+ char *cx;
+ char commandbuf[256];
+ int gotline;
+ event_t ev;
+
+ status_line();
+
+ /* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
+
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ jacl_set_window(inputwin);
+ }
+
+ jacl_set_window(mainwin);
+
+ g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
+
+ gotline = FALSE;
+ while (!gotline) {
+
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+ case evtype_LineInput:
+ if (ev.window == inputwin) {
+ gotline = TRUE;
+ }
+ break;
+
+ case evtype_Arrange:
+ status_line();
+ break;
+ }
+ }
+
+ commandbuf[ev.val1] = '\0';
+ for (cx = commandbuf; *cx == ' '; cx++) { };
+
+ // COPY UP TO 255 BYTES OF THE ENTERED TEXT INTO THE SUPPLIED STRING
+ strncpy(string_buffer, cx, 255);
+}
+
+int get_yes_or_no() {
+ char *cx;
+ char commandbuf[256];
+ int gotline;
+ event_t ev;
+
+ status_line();
+
+ /* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
+
+ while (1) {
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ jacl_set_window(inputwin);
+ }
+
+ write_text(cstring_resolve("YES_OR_NO")->value);
+ jacl_set_window(mainwin);
+
+ g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
+
+ gotline = FALSE;
+ while (!gotline) {
+
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+ case evtype_LineInput:
+ if (ev.window == inputwin) {
+ gotline = TRUE;
+ }
+ break;
+
+ case evtype_Arrange:
+ status_line();
+ break;
+ }
+ }
+
+ commandbuf[ev.val1] = '\0';
+ for (cx = commandbuf; *cx == ' '; cx++) { };
+
+ // PUSH THE FIRST NON-SPACE CHARACTER TO LOWER FOR COMPARISON
+ // WITH CONSTANT
+ *cx = tolower(*cx);
+
+ if (*cx == cstring_resolve("YES_WORD")->value[0]) {
+ return TRUE;
+ } else if (*cx == cstring_resolve("NO_WORD")->value[0]) {
+ return FALSE;
+ }
+
+ }
+}
+
+char get_character(char *message) {
+ char *cx;
+ char commandbuf[256];
+ int gotline;
+ event_t ev;
+
+ status_line();
+
+ /* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
+
+ while (1) {
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ jacl_set_window(inputwin);
+ }
+
+ write_text(message);
+ g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
+ jacl_set_window(mainwin);
+
+ gotline = FALSE;
+ while (!gotline) {
+
+ g_vm->glk_select(&ev);
+
+ switch (ev.type) {
+ case evtype_LineInput:
+ if (ev.window == inputwin) {
+ gotline = TRUE;
+ }
+ break;
+
+ case evtype_Arrange:
+ status_line();
+ break;
+ }
+ }
+
+ commandbuf[ev.val1] = '\0';
+ for (cx = commandbuf; *cx == ' '; cx++) { };
+
+ return (*cx);
+ }
+}
+
+strid_t open_glk_file(uint usage, uint mode, char *filename) {
+
+ frefid_t file_reference;
+ strid_t stream_reference;
+
+ file_reference = g_vm->glk_fileref_create_by_name(usage, filename, 0);
+
+ if (file_reference) {
+ stream_reference = g_vm->glk_stream_open_file(file_reference, (FileMode)mode, 0);
+
+ if (stream_reference) {
+ /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
+ * HAS BEEN SUCCESSFULLY OPENED */
+ g_vm->glk_fileref_destroy(file_reference);
+
+ return (stream_reference);
+ }
+ }
+
+ return (strid_t) NULL;
+}
+
+void scripting() {
+ if (script_stream) {
+ write_text(cstring_resolve("SCRIPTING_ALREADY_ON")->value);
+ return;
+ }
+
+ /* IF WE'VE TURNED ON SCRIPTING BEFORE, USE THE SAME FILE REFERENCE;
+ * OTHERWISE, PROMPT THE PLAYER FOR A FILE. */
+ if (!script_fref) {
+ script_fref = g_vm->glk_fileref_create_by_prompt(
+ fileusage_Transcript | fileusage_TextMode,
+ filemode_WriteAppend, 0);
+ if (!script_fref) {
+ write_text(cstring_resolve("CANT_WRITE_SCRIPT")->value);
+ return;
+ }
+ }
+
+ /* OPEN THE TRANSCRIPT FILE */
+ script_stream = g_vm->glk_stream_open_file(script_fref, filemode_WriteAppend, 0);
+
+ if (!script_stream) {
+ write_text(cstring_resolve("CANT_WRITE_SCRIPT")->value);
+ return;
+ }
+ write_text(cstring_resolve("SCRIPTING_ON")->value);
+ g_vm->glk_window_set_echo_stream(mainwin, script_stream);
+ g_vm->glk_put_string_stream(script_stream, "TRANSCRIPT OF: ");
+ g_vm->glk_put_string_stream(script_stream, cstring_resolve("game_title")->value);
+ g_vm->glk_put_string_stream(script_stream, "\n");
+}
+
+void undoing() {
+ if (TOTAL_MOVES->value && strcmp(last_command, cstring_resolve("UNDO_WORD")->value)) {
+ restore_game_state();
+ } else {
+ write_text(cstring_resolve("NO_UNDO")->value);
+ TIME->value = FALSE;
+ }
+}
+
+void walking_thru() {
+ int result, index;
+
+ int length;
+ char script_line[81];
+
+ /* A FILE REFERENCE FOR THE WALKTHRU FILE. */
+ frefid_t walkthru_fref = NULL;
+
+ /* A STREAM FOR THE WALKTHRU FILE, WHEN IT'S OPEN. */
+ strid_t walkthru_stream = NULL;
+
+ walkthru_fref = g_vm->glk_fileref_create_by_prompt(fileusage_Data | fileusage_TextMode, filemode_Read, 0);
+
+ if (!walkthru_fref) {
+ write_text(cstring_resolve("ERROR_READING_WALKTHRU")->value);
+ return;
+ }
+
+ /* OPEN THE WALKTHRU FILE */
+ walkthru_stream = g_vm->glk_stream_open_file(walkthru_fref, filemode_Read, 0);
+
+ if (!walkthru_stream) {
+ write_text(cstring_resolve("ERROR_READING_WALKTHRU")->value);
+ return;
+ }
+
+ walkthru_running = TRUE;
+
+ /* ISSUE ALL THE COMMANDS STORE IN THE WALKTHRU FILE */
+
+ /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
+ * HAS BEEN SUCCESSFULLY OPENED */
+ g_vm->glk_fileref_destroy(walkthru_fref);
+
+ result = g_vm->glk_get_line_stream(walkthru_stream, text_buffer, (glui32) 80);
+
+ /* SET TO LOWER CASE AND STRIP NEWLINES */
+ length = strlen(text_buffer);
+ for (index = 0; index < length; index++) {
+ if (text_buffer[index] == '\r' ||
+ text_buffer[index] == '\n') {
+ text_buffer[index] = 0;
+ break;
+ }
+ }
+
+ strcpy(script_line, text_buffer);
+
+ while (result && INTERRUPTED->value == FALSE) {
+ /* THERE COULD BE A LOT OF PROCESSING GOING ON HERE BEFORE GETTING
+ * TO THE NEXT EVENT LOOP SO CALL g_vm->glk_tick AFTER EACH LINE READ */
+ g_vm->glk_tick();
+ command_encapsulate();
+ jacl_truncate();
+ if (word[0] != NULL) {
+ custom_error = FALSE;
+
+ execute("+bottom");
+
+ write_text(string_resolve("command_prompt")->value);
+ g_vm->glk_set_style(style_Input);
+ write_text(script_line);
+ newline();
+ g_vm->glk_set_style(style_Normal);
+
+ execute("+top");
+
+ preparse();
+ }
+
+ result = g_vm->glk_get_line_stream(walkthru_stream, text_buffer, (glui32) 80);
+
+ /* SET TO LOWER CASE AND STRIP NEWLINES */
+ length = strlen(text_buffer);
+ for (index = 0; index < length; index++) {
+ if (text_buffer[index] == '\r' ||
+ text_buffer[index] == '\n') {
+ text_buffer[index] = 0;
+ break;
+ }
+ }
+
+ strcpy(script_line, text_buffer);
+ }
+
+ /* CLOSE THE STREAM */
+ g_vm->glk_stream_close(walkthru_stream, NULL);
+
+ /* FINISH UP */
+ walkthru_running = FALSE;
+}
+
+int restore_interaction(char *filename) {
+ frefid_t saveref;
+
+ jacl_set_window(inputwin);
+
+ if (inputwin == promptwin) {
+ g_vm->glk_window_clear(promptwin);
+ newline();
+ }
+
+ if (filename == NULL) {
+ saveref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame | fileusage_BinaryMode, filemode_Read, 0);
+ } else {
+ saveref = g_vm->glk_fileref_create_by_name(fileusage_SavedGame | fileusage_BinaryMode, filename, 0);
+ }
+
+ jacl_set_window(mainwin);
+
+ if (!saveref) {
+ write_text(cstring_resolve("CANT_RESTORE")->value);
+ return (FALSE);
+ }
+
+ if (restore_game(saveref, TRUE) == FALSE) {
+ write_text(cstring_resolve("CANT_RESTORE")->value);
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+glui32 glk_get_bin_line_stream(strid_t file_stream, char *buffer, glui32 max_length) {
+ int character = 0;
+
+ register int index = 0;
+
+ character = g_vm->glk_get_char_stream(file_stream);
+ while (character != -1 && index < (int) max_length) {
+ *(buffer + index) = (char) character;
+ index++;
+ if (character == (int) '\n' ||
+ character == (int) '\r') {
+ break;
+ }
+ character = g_vm->glk_get_char_stream(file_stream);
+ };
+
+ *(buffer + index) = 0;
+
+ return ((glui32) index);
+}
+
+void jacl_set_window(winid_t new_window) {
+ current_window = new_window;
+ g_vm->glk_set_window(new_window);
+}
+
+#ifdef READLINE
+char **command_completion(char *text, int start, int end) {
+ /* READLINE TAB COMPLETION CODE */
+ char **options;
+
+ options = (char **) NULL;
+
+ if (start == 0)
+ options = completion_matches(text, verb_generator);
+ else
+ options = completion_matches(text, object_generator);
+
+ return (options);
+}
+#endif
+
+char *object_generator(char *text, int state) {
+ static int len;
+ static struct command_type *now;
+ struct command_type *to_send;
+ struct name_type *current_name = (struct name_type *) NULL;
+
+ /* IF THIS IS A NEW WORD TO COMPLETE, INITIALIZE NOW. THIS INCLUDES
+ SAVING THE LENGTH OF TEXT FOR EFFICIENCY, AND INITIALIZING THE INDEX
+ VARIABLE TO 0. */
+
+ if (!state) {
+ /* BUILD THE LIST */
+ int index;
+ completion_list = NULL;
+
+ /* LOOP THROUGH ALL THE OBJECTS AND SEE IF THEY ARE IN
+ THE CURRENT LOCATION */
+ for (index = 1; index <= objects; index++) {
+ if (parent_of(HERE, index, UNRESTRICT) && !(object[index]->attributes & NO_TAB)) {
+ /* LOOP THROUGH ALL THE OBJECTS NAMES AND
+ THEM TO THE COMPLETION LIST */
+ current_name = object[index]->first_name;
+ while (current_name) {
+ add_word(current_name->name);
+ current_name = current_name->next_name;
+ }
+ }
+ }
+ now = completion_list;
+ len = strlen(text);
+ }
+
+ while (now != NULL) {
+ if (!strncmp(text, now->word, len)) {
+ to_send = now;
+ now = now->next;
+ return ((char *) to_send->word);
+ }
+ now = now->next;
+ }
+
+ return (char *) NULL;
+}
+
+char *verb_generator(char *text, int state) {
+ static int len;
+ static struct command_type *now;
+ struct command_type *to_send;
+ struct word_type *pointer;
+
+ /* IF THIS IS A NEW WORD TO COMPLETE, INITIALIZE NOW. THIS INCLUDES
+ SAVING THE LENGTH OF TEXT FOR EFFICIENCY, AND INITIALIZING THE INDEX
+ VARIABLE TO 0. */
+
+ if (!state) {
+ /* BUILD THE LIST */
+ completion_list = NULL;
+
+ pointer = grammar_table;
+ while (pointer != NULL) {
+ add_word(pointer->word);
+ pointer = pointer->next_sibling;
+ }
+
+ add_word("walkthru");
+
+ now = completion_list;
+ len = strlen(text);
+ }
+
+ while (now != NULL) {
+ if (!strncmp(text, now->word, len)) {
+ to_send = now;
+ now = now->next;
+
+ /* MALLOC A COPY AND RETURN A POINTER TO THE COPY */
+ return ((char *) to_send->word);
+ }
+ now = now->next;
+ }
+
+ return (char *) NULL;
+}
+
+/* ADD A COPY OF STRING TO A LIST OF STRINGS IF IT IS NOT
+ ALREADY IN THE LIST. THIS IS FOR THE USE OF READLINE */
+void add_word(char *newWord) {
+ static struct command_type *current_word = NULL;
+ struct command_type *previous_word = NULL;
+
+ /* DON'T ADD WORDS SUCH AS *present TO THE LIST*/
+ if (*newWord == '*')
+ return;
+
+ if (current_word != NULL)
+ previous_word = current_word;
+
+ current_word = (struct command_type *) malloc(sizeof(struct command_type));
+
+ if (current_word != NULL) {
+ if (completion_list == NULL) {
+ completion_list = current_word;
+ }
+
+ strncpy(current_word->word, newWord, 40);
+ current_word->word[40] = 0;
+ current_word->next = NULL;
+
+ if (previous_word != NULL) {
+ previous_word->next = current_word;
+ }
+ }
+}
+
+void convert_to_utf8(glui32 *text, int len) {
+ int i, k;
+
+ i = 0;
+ k = 0;
+
+ /*convert UTF-32 to UTF-8 */
+ while (i < len) {
+ if (text[i] < 0x80) {
+ command_buffer[k] = text[i];
+ k++;
+ } else if (text[i] < 0x800) {
+ command_buffer[k ] = (0xC0 | ((text[i] & 0x7C0) >> 6));
+ command_buffer[k + 1] = (0x80 | (text[i] & 0x03F));
+ k = k + 2;
+ } else if (text[i] < 0x10000) {
+ command_buffer[k ] = (0xE0 | ((text[i] & 0xF000) >> 12));
+ command_buffer[k + 1] = (0x80 | ((text[i] & 0x0FC0) >> 6));
+ command_buffer[k + 2] = (0x80 | (text[i] & 0x003F));
+ k = k + 3;
+ } else if (text[i] < 0x200000) {
+ command_buffer[k ] = (0xF0 | ((text[i] & 0x1C0000) >> 18));
+ command_buffer[k + 1] = (0x80 | ((text[i] & 0x03F000) >> 12));
+ command_buffer[k + 2] = (0x80 | ((text[i] & 0x000FC0) >> 6));
+ command_buffer[k + 3] = (0x80 | (text[i] & 0x00003F));
+ k = k + 4;
+ } else {
+ command_buffer[k] = '?';
+ k++;
+ }
+ i++;
+ }
+
+ /* null-terminated string */
+ command_buffer[k] = '\0';
+}
+
+#ifndef NOUNICODE
+int convert_to_utf32(unsigned char *text) {
+ int text_len;
+ int rlen;
+
+ if (!text) {
+ return 0;
+ }
+
+ text_len = strlen((const char *)text);
+
+ if (!text_len) {
+ return 0;
+ }
+
+ rlen = (int) parse_utf8(text, text_len, chunk_buffer_uni, text_len);
+
+ return (rlen);
+}
+
+glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen) {
+ glui32 pos = 0;
+ glui32 outpos = 0;
+ glui32 res;
+ glui32 val0, val1, val2, val3;
+
+ while (outpos < outlen) {
+ if (pos >= buflen)
+ break;
+
+ val0 = buf[pos++];
+
+ if (val0 < 0x80) {
+ res = val0;
+ out[outpos++] = res;
+ continue;
+ }
+
+ if ((val0 & 0xe0) == 0xc0) {
+ if (pos + 1 > buflen) {
+ warning("incomplete two-byte character");
+ break;
+ }
+ val1 = buf[pos++];
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed two-byte character");
+ break;
+ }
+ res = (val0 & 0x1f) << 6;
+ res |= (val1 & 0x3f);
+ out[outpos++] = res;
+ continue;
+ }
+
+ if ((val0 & 0xf0) == 0xe0) {
+ if (pos + 2 > buflen) {
+ warning("incomplete three-byte character");
+ break;
+ }
+ val1 = buf[pos++];
+ val2 = buf[pos++];
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed three-byte character");
+ break;
+ }
+ if ((val2 & 0xc0) != 0x80) {
+ warning("malformed three-byte character");
+ break;
+ }
+ res = (((val0 & 0xf) << 12) & 0x0000f000);
+ res |= (((val1 & 0x3f) << 6) & 0x00000fc0);
+ res |= (((val2 & 0x3f)) & 0x0000003f);
+ out[outpos++] = res;
+ continue;
+ }
+
+ if ((val0 & 0xf0) == 0xf0) {
+ if ((val0 & 0xf8) != 0xf0) {
+ warning("malformed four-byte character");
+ break;
+ }
+ if (pos + 3 > buflen) {
+ warning("incomplete four-byte character");
+ break;
+ }
+ val1 = buf[pos++];
+ val2 = buf[pos++];
+ val3 = buf[pos++];
+ if ((val1 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ break;
+ }
+ if ((val2 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ break;
+ }
+ if ((val3 & 0xc0) != 0x80) {
+ warning("malformed four-byte character");
+ break;
+ }
+ res = (((val0 & 0x7) << 18) & 0x1c0000);
+ res |= (((val1 & 0x3f) << 12) & 0x03f000);
+ res |= (((val2 & 0x3f) << 6) & 0x000fc0);
+ res |= (((val3 & 0x3f)) & 0x00003f);
+ out[outpos++] = res;
+ continue;
+ }
+
+ warning("malformed character");
+ }
+
+ return outpos;
+}
+#endif
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/jpp.cpp b/engines/glk/jacl/jpp.cpp
new file mode 100644
index 0000000..f036b75
--- /dev/null
+++ b/engines/glk/jacl/jpp.cpp
@@ -0,0 +1,236 @@
+/* jpp.c --- The JACL Preprocessor
+ (C) 2001 Andreas Matthias
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "glk/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+#include "glk/jacl/version.h"
+#include "common/file.h"
+
+namespace Glk {
+namespace JACL {
+
+extern char text_buffer[];
+extern char temp_buffer[];
+extern char *word[];
+extern short int quoted[];
+extern short int punctuated[];
+extern int wp;
+
+extern char user_id[];
+extern char prefix[];
+extern char game_path[];
+extern char game_file[];
+extern char processed_file[];
+
+extern short int encrypted;
+
+extern char include_directory[];
+extern char temp_directory[];
+
+extern char error_buffer[];
+
+int lines_written;
+
+Common::WriteStream *outputFile = NULL;
+Common::SeekableReadStream *inputFile = NULL;
+
+char *stripped_line;
+
+/* INDICATES THAT THE CURRENT '.j2' FILE BEING WORKED
+ * WITH BEING PREPARED FOR RELEASE (DON'T INCLUDE DEBUG LIBARIES) */
+short int release = FALSE;
+
+/* INDICATES THAT THE CURRENT '.j2' FILE BEING WORKED
+ * SHOULD BE ENCRYPTED */
+short int do_encrypt = TRUE;
+
+/* INDICATES THAT THE CURRENT '.processed' FILE BRING WRITTEN SHOULD NOW
+ * HAVE EACH LINE ENCRYPTED AS THE FIRST NONE COMMENT LINE HAS BEEN HIT */
+short int encrypting = FALSE;
+
+int jpp() {
+ // TODO: Find out if this is actually used
+#ifdef UNUSED
+ int game_version;
+
+ lines_written = 0;
+
+ /* CHECK IF GAME FILE IS ALREADY A PROCESSED FILE BY LOOKING FOR THE
+ * STRING "#encrypted" OR "#processed" WITHIN THE FIRST FIVE LINES OF
+ * THE GAME FILE IF SO, RETURN THE GAME FILE AS THE PROCESSED FILE */
+ inputFile = File::open(game_file);
+
+ if (inputFile) {
+ int index = 0;
+ char *result = NULL;
+
+ if (inputFile->read(text_buffer, 1024) != 1024) {
+ sprintf(error_buffer, CANT_OPEN_SOURCE, game_file);
+ return (FALSE);
+ }
+
+ while (inputFile->pos() < inputFile->size() && index < 10) {
+ if (strstr(text_buffer, "#processed")) {
+ /* THE GAME FILE IS ALREADY A PROCESSED FILE, JUST USE IT
+ * DIRECTLY */
+ if (sscanf(text_buffer, "#processed:%d", &game_version)) {
+ if (INTERPRETER_VERSION < game_version) {
+ sprintf(error_buffer, OLD_INTERPRETER, game_version);
+ return (FALSE);
+ }
+ }
+ strcpy(processed_file, game_file);
+
+ return (TRUE);
+ }
+ if (inputFile->read(text_buffer, 1024) != 1024)
+ break;
+
+ index++;
+ }
+
+ delete inputFile;
+ } else {
+ sprintf(error_buffer, NOT_FOUND);
+ return (FALSE);
+ }
+
+ /* SAVE A TEMPORARY FILENAME INTO PROCESSED_FILE */
+ sprintf(processed_file, "%s%s.j2", temp_directory, prefix);
+
+ /* ATTEMPT TO OPEN THE PROCESSED FILE IN THE TEMP DIRECTORY */
+ if ((outputFile = fopen(processed_file, "w")) == NULL) {
+ /* NO LUCK, TRY OPEN THE PROCESSED FILE IN THE CURRENT DIRECTORY */
+ sprintf(processed_file, "%s.j2", prefix);
+ if ((outputFile = fopen(processed_file, "w")) == NULL) {
+ /* NO LUCK, CAN'T CONTINUE */
+ sprintf(error_buffer, CANT_OPEN_PROCESSED, processed_file);
+ return (FALSE);
+ }
+ }
+
+ if (process_file(game_file, (char *) NULL) == FALSE) {
+ return (FALSE);
+ }
+
+ fclose(outputFile);
+#else
+ error("TODO");
+#endif
+
+ /* ALL OKAY, RETURN TRUE */
+ return (TRUE);
+}
+
+int process_file(char *sourceFile1, char *sourceFile2) {
+ char temp_buffer1[1025];
+ char temp_buffer2[1025];
+ Common::File *srcFile = NULL;
+ char *includeFile = NULL;
+
+ /* THIS FUNCTION WILL CREATE A PROCESSED FILE THAT HAS HAD ALL
+ * LEADING AND TRAILING WHITE SPACE REMOVED AND ALL INCLUDED
+ * FILES INSERTED */
+ srcFile = File::openForReading(sourceFile1);
+
+ if (!srcFile) {
+ if (sourceFile2 != NULL) {
+ srcFile = File::openForReading(sourceFile2);
+ if (!srcFile) {
+ sprintf(error_buffer, CANT_OPEN_OR, sourceFile1, sourceFile2);
+ return (FALSE);
+ }
+
+ } else {
+ sprintf(error_buffer, CANT_OPEN_SOURCE, sourceFile1);
+ return (FALSE);
+ }
+ }
+
+ *text_buffer = 0;
+
+ if (srcFile->read(text_buffer, 1024) != 1024) {
+ sprintf(error_buffer, READ_ERROR);
+ delete srcFile;
+ return (FALSE);
+ }
+
+ while (srcFile->pos() < srcFile->size() && *text_buffer != 0) {
+ if (!strncmp(text_buffer, "#include", 8) ||
+ (!strncmp(text_buffer, "#debug", 6) & !release)) {
+ includeFile = strrchr(text_buffer, '"');
+
+ if (includeFile != NULL)
+ *includeFile = 0;
+
+ includeFile = strchr(text_buffer, '"');
+
+ if (includeFile != NULL) {
+ strcpy(temp_buffer1, game_path);
+ strcat(temp_buffer1, includeFile + 1);
+ strcpy(temp_buffer2, include_directory);
+ strcat(temp_buffer2, includeFile + 1);
+ if (process_file(temp_buffer1, temp_buffer2) == FALSE) {
+ return (FALSE);
+ }
+ } else {
+ sprintf(error_buffer, BAD_INCLUDE);
+ return (FALSE);
+ }
+ } else {
+ /* STRIP WHITESPACE FROM LINE BEFORE WRITING TO OUTPUTFILE. */
+ stripped_line = stripwhite(text_buffer);
+
+ if (!encrypting && *stripped_line != '#' && *stripped_line != '\0' && do_encrypt & release) {
+ /* START ENCRYPTING FROM THE FIRST NON-COMMENT LINE IN
+ * THE SOURCE FILE */
+ outputFile->writeString("#encrypted\n");
+ encrypting = TRUE;
+ }
+
+ /* ENCRYPT PROCESSED FILE IF REQUIRED */
+ if (encrypting) {
+ jacl_encrypt(stripped_line);
+ }
+
+ outputFile->writeString(stripped_line);
+
+ lines_written++;
+ if (lines_written == 1) {
+ sprintf(temp_buffer, "#processed:%d\n", INTERPRETER_VERSION);
+ outputFile->writeString(temp_buffer);
+ }
+ }
+
+ *text_buffer = 0;
+
+ if (srcFile->read(text_buffer, 1024) != 1024)
+ // EOF HAS BEEN REACHED
+ break;
+ }
+
+ delete srcFile;
+
+ /* ALL OKAY, RETURN TRUE */
+ return (TRUE);
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/language.h b/engines/glk/jacl/language.h
new file mode 100644
index 0000000..6fef372
--- /dev/null
+++ b/engines/glk/jacl/language.h
@@ -0,0 +1,574 @@
+/* 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.
+ *
+ */
+namespace Glk {
+namespace JACL {
+
+/* THIS FILE CONTAINS ALL THE TEXT OUTPUT INTERNALLY BY THE INTERPRETER.
+ THE STRINGS FOR ANY GIVEN LANGUAGE ARE DIVIDED INTO TWO SECTIONS, ONE
+ THAT CONTAINS THE TEXT OUTPUT DURING REGULAR PLAY AND ONE THAT CONTAINS
+ THE TEXT OUTPUT DURING ERROR CONDITIONS (POSSIBLY BEFORE ANY GIVEN GAME
+ HAS FINISHED LOADING.
+
+ TO TRANSLATE A GAME TO LANGUAGE THAT IS NOT CURRENTLY SUPPORTED YOU
+ NEED TO TRANSLATE english.library AND verbs.library INTO YOUR CHOSEN
+ LANGUAGE.
+
+ THE NATIVE_LANGUAGE CONSTANT BELOW INDICATES WHAT SHOULD BE THE DEFAULT
+ LANGUAGE OF THE INTERPRETER WHEN IT IS COMPILED. THE 'GAME MESSAGES'
+ BLOCK CONTAINS THE SAME STRINGS AS THE FILE english.library (AND OTHER
+ LANGUAGES) AND THESE ARE THE VALUES USED BY THE INTERPRETER IF THOSE
+ CONSTANTS ARE NO DEFINED BY ANY GIVEN GAME.
+
+ THE 'SYSTEM MESSAGES' BLOCK CONTAINS ERROR MESSAGES AND OTHER SYSTEM-
+ LEVEL MESSAGES THAT ARE MOST COMMONLY SEEN DURING THE DEVELOPMENT OF A
+ GAME. THESE MESSAGES CANNOT BE OVERRIDDEN BY ANY SPECIFIC GAME. */
+
+
+#define ENGLISH 1
+#define GERMAN 2
+#define FRENCH 3
+
+#define NATIVE_LANGUAGE ENGLISH
+
+#if NATIVE_LANGUAGE==ENGLISH
+/* GAME MESSAGES */
+#define COMMENT_IGNORED "No transcript running, comment ignored.^"
+#define COMMENT_RECORDED "Comment recorded.^"
+#define YES_WORD "yes"
+#define NO_WORD "no"
+#define YES_OR_NO "^Please enter ~yes~ or ~no~: "
+#define INVALID_SELECTION "Invalid selection.^"
+#define RESTARTING "^Restarting...^"
+#define RETURN_GAME "^Returning to game.^"
+#define SCRIPTING_ON "Scripting on.^"
+#define SCRIPTING_OFF "Scripting off.^"
+#define SCRIPTING_ALREADY_OFF "Scripting already off.^"
+#define SCRIPTING_ALREADY_ON "Scripting already off.^"
+#define CANT_WRITE_SCRIPT "Unable to write to script file.^"
+#define ERROR_READING_WALKTHRU "Error reading walkthru file.^"
+#define BAD_OOPS "You must follow the ~oops~ command with the word you wish to use instead.^"
+#define CANT_CORRECT "I can't correct the last command using ~oops~, sorry.^"
+#define SURE_QUIT "Are you sure you want to quit?^"
+#define SURE_RESTART "Are you sure you want to restart?^"
+#define NOT_CLEVER "It wasn't so clever as to be worth repeating.^"
+#define NO_MOVES "But you haven't done anything yet!^"
+#define TYPE_NUMBER "^Type a number between %d and %d: "
+#define BY "By ~"
+#define REFERRING_TO "~, are you referring to:^"
+#define WALKTHRU_WORD "walkthru"
+#define INFO_WORD "info"
+#define RESTART_WORD "restart"
+#define AGAIN_WORD "again"
+#define SCRIPT_WORD "script"
+#define UNSCRIPT_WORD "unscript"
+#define QUIT_WORD "quit"
+#define UNDO_WORD "undo"
+#define OOPS_WORD "oops"
+#define FROM_WORD "from"
+#define EXCEPT_WORD "except"
+#define FOR_WORD "for"
+#define BUT_WORD "but"
+#define AND_WORD "and"
+#define THEN_WORD "then"
+#define OF_WORD "of"
+#define SHE_WORD "she"
+#define HE_WORD "he"
+#define THAT_WORD "that"
+#define THEM_WORD "them"
+#define THOSE_WORD "those"
+#define THEY_WORD "they"
+#define IT_WORD "it"
+#define ITSELF_WORD "itself"
+#define HIM_WORD "him"
+#define HIMSELF_WORD "himself"
+#define HER_WORD "her"
+#define HERSELF_WORD "herself"
+#define THEMSELVES_WORD "themselves"
+#define YOU_WORD "you"
+#define YOURSELF_WORD "yourself"
+#define ONES_WORD "ones"
+#define NO_MULTI_VERB "You can't refer to multiple objects directly after the word ~%s~.^"
+#define NO_MULTI_START "You can't refer to multiple objects at the start of a command.^"
+#define PERSON_CONCEALING "%s doesn't seem to be carrying any such thing.^"
+#define PERSON_POSSESSIVE "%s isn't about to let you take anything of theirs.^"
+#define CONTAINER_CLOSED "%s is closed.^"
+#define CONTAINER_CLOSED_FEM "%s is closed.^"
+#define FROM_NON_CONTAINER "The word ~%s~ must be followed by a container.^"
+#define DOUBLE_EXCEPT "You can only use the word ~%s~ once per object reference.^"
+#define NONE_HELD "You are not holding anything like that.^"
+#define NO_OBJECTS "I don't see what you are referring to.^"
+#define NO_FILENAME "Save and restore commands must be followed by a filename.^"
+#define MOVE_UNDONE "Previous move undone.^^"
+#define NO_UNDO "Nothing to undo.^"
+#define CANT_SAVE "Unable to save game state to file.^"
+#define CANT_RESTORE "Unable to restore game state from file.^"
+#define GAME_SAVED "Game saved.^"
+#define INCOMPLETE_SENTENCE "The sentence you typed was incomplete.^"
+#define UNKNOWN_OBJECT "You can't see any such thing as ~"
+#define UNKNOWN_OBJECT_END "~.^"
+#define CANT_USE_WORD "You can't use the word ~"
+#define IN_CONTEXT "~ in that context.^"
+#define DONT_SEE "You don't see "
+#define HERE_WORD " here.^"
+#define BAD_SAVED_GAME "Attempt to restore incompatible saved-game file."
+#define ARENT "aren't"
+#define ISNT "isn't"
+#define ARE "are"
+#define IS "is"
+#define DONT "don't"
+#define DOESNT "doesn't"
+#define DO "do"
+#define DOES "does"
+#define SCORE_UP "^[YOUR SCORE JUST WENT UP BY "
+#define POINT " POINT]^"
+#define POINTS " POINTS]^"
+#define STARTING "Starting."
+#define NO_IT "You must have referred to an appropriate noun previously to use the word ~"
+#define NO_IT_END "~.^"
+#define BACK_REFERENCE "You must have referred to a noun previously in the same sentence to use the word ~"
+#define BACK_REFERENCE_END "~.^"
+#define WHEN_YOU_SAY "When you say ~"
+#define MUST_SPECIFY "~, you must specify whether you mean "
+#define OR_WORD " or "
+
+/* SYSTEM MESSAGES */
+#define READ_ERROR "Error reading game file."
+#define OLD_INTERPRETER "Interpreter version is older than game file (v%d), can't continue."
+#define BAD_CURSOR "You can only use the ~cursor~ command in the status window.^"
+#define INCOMPLETE_GRAMMAR "Incomplete grammar statement."
+#define GAME_MODIFIED "Game file modified, reloading.\n"
+#define NOT_INTEGER "In function \"%s\", \"%s\" command requires integer parameter."
+#define NO_NAME_FUNCTION "In line %d, a function must have at least one name."
+#define MAXIMUM_ATTRIBUTES_ERR "In line %d, unable to create attribute \"%s\", maximum number of attributes already defined."
+#define BAD_PLAYER "In function \"%s\", attempt to use object pointer \"player\" while it does not point to an object (%d)."
+#define BAD_PARENT "In function \"%s\", attempt to use the variable 'here' while the variable 'player' does not have a legal parent."
+#define BAD_POINTER "In function \"%s\", attempt to use object pointer \"%s\" that does not point to an object (%d)."
+#define ILLEGAL_LABEL "In line %d, reserved word \"%s\" used as label."
+#define USED_LABEL_INT "In line %d, \"%s\" is already used as a variable label."
+#define USED_LABEL_CINT "In line %d, \"%s\" is already used as an integer constant label."
+#define USED_LABEL_STR "In line %d, \"%s\" is already used as a string label."
+#define USED_LABEL_CSTR "In line %d, \"%s\" is already used as a string constant label."
+#define USED_LABEL_ATT "In line %d, \"%s\" is already used as an attribute label."
+#define USED_LABEL_OBJ "In line %d, \"%s\" is already used as an object or location label."
+#define NO_OBJECT_ERR "In line %d, property \"%s\" defined before first object or location."
+#define BAD_INCLUDE "'#include' directive must be followed by file name enclosed in double quotes."
+#define BAD_PARAMETER "Unknown or inappropriate type of container '%s' associated with parameter '%s'."
+#define BAD_VALUE "Value '%s' cannot be stored in container '%s'."
+#define NO_MEDIA "WebJACL: Media file \"%s\" not found, external media support disabled.\n"
+#define MEDIA_REGISTERED "WebJACL: Registered %d media.\n"
+#define CLEANING_UP "WebJACL: Cleaning up...\n"
+#define NO_GAME "No game file specified, can't continue."
+#define NO_PORT "WebJACL: No port number specified (-p <number>), using default port %d.\n"
+#define WEBJACL_CONFIGURED "WebJACL server configured on %s:%d\n"
+#define NOT_FOUND "Unable to open game file, can't continue."
+#define CANT_OPEN "Unable to open processed file \"%s\", can't continue."
+#define CANT_RUN "A JACL game must contain at least one object (to represent the player), and at least one location (for the player to start in).^"
+#define NO_PLAYER "The object pointer 'player' does not point to an object.^"
+#define SELF_REFERENCE "In function \"%s\", reference to object \"%s\" whose parent is itself."
+#define EXECUTING "Executing function \"%s\".\n"
+#define NO_WHILE "In function \"%s\", 'endwhile' command without matching 'while' command."
+#define NO_ITERATE "In function \"%s\", 'enditerate' command without matching 'iterate' command."
+#define NO_UPDATE "In function \"%s\", 'endupdate' command without matching 'update' command."
+#define NO_REPEAT "In function \"%s\", 'until' command without matching 'repeat' command."
+#define NO_LOOP "In function \"%s\", 'endloop' command without matching 'loop' command."
+#define UNDEFINED_FUNCTION "In function \"%s\", attempt to execute undefined function \"%s\"."
+#define DIVIDE_BY_ZERO "In function \"%s\", division by zero error."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define UNKNOWN_COMMAND "In function \"%s\", unknown command \"%s\"."
+#define STACK_OVERFLOW "Stack overflow."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define OUT_OF_RANGE "In function \"%s\", element \"%s\" out of range (%d)."
+#define GLOBAL_SELF "Reference to 'self' from global function \"%s\"."
+#define NON_GLOBAL_FIRST "In line %d, non-global function before object or location."
+#define MAXIMUM_EXCEEDED "Maximum number of objects exceeded, can't continue."
+#define ERROR_DETECTED "1 error detected."
+#define ERRORS_DETECTED "%d errors detected."
+#define UNKOWN_OBJECT_RUN "In function \"%s\", reference to unknown object \"%s\"."
+#define UNKNOWN_FUNCTION_RUN "Attempt to execute unknown function \"%s\"."
+#define UNKNOWN_KEYWORD_ERR "In line %d, unknown keyword \"%s\"."
+#define UNKNOWN_ATTRIBUTE_ERR "In line %d, unknown attribute \"%s\"."
+#define UNKNOWN_VALUE_ERR "In line %d, unable to resolve value \"%s\"."
+#define UNKNOWN_ATTRIBUTE_RUN "In function \"%s\", reference to unknown attribute \"%s\"."
+#define INSUFFICIENT_PARAMETERS_RUN "In function \"%s\", \"%s\" command with insufficient parameters."
+#define INSUFFICIENT_PARAMETERS_ERR "In line %d, \"%s\" keyword with insufficient parameters."
+#define UNDEFINED_ITEM_ERR "In line %d, reference to undefined item \"%s\"."
+#define UNDEFINED_ITEM_RUN "In function \"%s\", reference to undefined object \"%s\"."
+#define UNDEFINED_DIRECTION_RUN "In function \"%s\", reference to undefined direction \"%s\"."
+#define UNKNOWN_SCOPE_RUN "In function \"%s\", reference to unknown scope \"%s\"."
+#define UNDEFINED_STRING_RUN "In function \"%s\", reference to undefined string \"%s\"."
+#define UNDEFINED_CONTAINER_RUN "In function \"%s\", reference to undefined container \"%s\"."
+#define OUT_OF_MEMORY "Out of memory, can't continue."
+#define CANT_OPEN_PROCESSED "Unable to open output file \"%s\" for writing, can't continue."
+#define CANT_OPEN_OR "Unable to open source file \"%s\" or \"%s\", can't continue."
+#define CANT_OPEN_SOURCE "Unable to open source file \"%s\", can't continue."
+#endif
+
+#if NATIVE_LANGUAGE==FRENCH
+/* GAME MESSAGES */
+#define COMMENT_IGNORED "Pas de transcription en cours, commentaire ignoré.^"
+#define COMMENT_RECORDED "Commentaire enregistré.^"
+#define YES_WORD "oui"
+#define NO_WORD "no"
+#define YES_OR_NO "^Merci d'entrer ~oui~ ou ~non~: "
+#define INVALID_SELECTION "Sélection invalide.^"
+#define RESTARTING "^En train de recommencer...^"
+#define RETURN_GAME "^Retour au jeu.^"
+#define SCRIPTING_ON "Début de transcription.^"
+#define SCRIPTING_OFF "Fin de transcription.^"
+#define SCRIPTING_ALREADY_OFF "Transcription déjà terminée.^"
+#define SCRIPTING_ALREADY_ON "Transcription déjà en cours.^"
+#define CANT_WRITE_SCRIPT "Impossible d'écrire le fichier de transcription.^"
+#define ERROR_READING_WALKTHRU "Erreur lors de la lecture du fichier de solution.^"
+#define BAD_OOPS "Vous devez faire suivre la commande ~oops~ par le mot que vous souhaitez remplacer.^"
+#define CANT_CORRECT "Désolé, je ne peux corriger la dernière commande en utilisant ~oops~.^"
+#define SURE_QUIT "Êtes-vous certain de vouloir quitter ?^"
+#define SURE_RESTART "Êtes-vous certain de vouloir recommencer ?^"
+#define NOT_CLEVER "Ce n'était pas si intelligent au point de vouloir répéter cela.^"
+#define NO_MOVES "Mais vous n'avez rien fait pour le moment !^"
+#define TYPE_NUMBER "^Entrez un nombre entre %d et %d: "
+#define BY "By ~"
+#define REFERRING_TO "Faites-vous référence à :^"
+#define WALKTHRU_WORD "solution"
+#define INFO_WORD "info"
+#define RESTART_WORD "recommencer"
+#define AGAIN_WORD "encore"
+#define SCRIPT_WORD "script"
+#define UNSCRIPT_WORD "unscript"
+#define QUIT_WORD "quitter"
+#define UNDO_WORD "annuler"
+#define OOPS_WORD "oops"
+#define FROM_WORD "depuis"
+#define EXCEPT_WORD "excepté"
+#define FOR_WORD "pour"
+#define BUT_WORD "mais"
+#define AND_WORD "et"
+#define THEN_WORD "puis"
+#define OF_WORD "de"
+#define SHE_WORD "elle"
+#define HE_WORD "il"
+#define THAT_WORD "ce"
+#define THEM_WORD "ces"
+#define THOSE_WORD "ceux"
+#define THEY_WORD "ils"
+#define IT_WORD "il"
+#define ITSELF_WORD "lui-même"
+#define HIM_WORD "him"
+#define HIMSELF_WORD "lui-même"
+#define HER_WORD "her"
+#define HERSELF_WORD "elle-même"
+#define THEMSELVES_WORD "eux-même"
+#define YOU_WORD "you"
+#define YOURSELF_WORD "yourself"
+#define ONES_WORD "ceux"
+#define NO_MULTI_VERB "Vous ne pouvez vous référer à de multiples objets après le mot \"%s\".^"
+#define NO_MULTI_START "Vous ne pouvez vous référer à de multiples objets au début d'une commande.^"
+#define PERSON_CONCEALING "%s ne semble par porter cela.^"
+#define PERSON_POSSESSIVE "%s ne vous laissera pas lui prendre ses affaires.^"
+#define CONTAINER_CLOSED "%s est fermé.^"
+#define CONTAINER_CLOSED_FEM "%s est fermé.^"
+#define FROM_NON_CONTAINER "Le mot \"%s\" doit être suivi par un contenant.^"
+#define DOUBLE_EXCEPT "Vous ne pouvez utiliser le mot \"%s\" qu'une fois par référence d'objet.^"
+#define NONE_HELD "Vous ne portez rien de cela.^"
+#define NO_OBJECTS "Je ne comprends pas ce à quoi vous vous réferez.^"
+#define NO_FILENAME "Les commandes de sauvegarde et lecture doivent être suivies par un nom de fichier.^"
+#define MOVE_UNDONE "Le tour précédent a été annulé.^^"
+#define NO_UNDO "Il n'y a rien à annuler.^"
+#define CANT_SAVE "Impossible de sauvegarder l'état du jeu sur fichier.^"
+#define CANT_RESTORE "Impossible de récupérer l'état du jeu depuis le fichier.^"
+#define GAME_SAVED "Jeu sauvegardé.^"
+#define INCOMPLETE_SENTENCE "La phrase que vous avez tapée n'est pas complète.^"
+#define UNKNOWN_OBJECT "Vous ne pouvez voir ~"
+#define UNKNOWN_OBJECT_END "~.^"
+#define CANT_USE_WORD "Vous ne pouvez utiliser le mot ~"
+#define IN_CONTEXT "~ dans ce contexte.^"
+#define DONT_SEE "Vous ne voyez pas "
+#define HERE_WORD " ici.^"
+#define BAD_SAVED_GAME "Ficher de sauvegarde incompatible."
+#define ARENT "ne sont pas"
+#define ISNT "n'est pas"
+#define ARE "sont"
+#define IS "est"
+#define DONT "ne font pas"
+#define DOESNT "ne fait pas"
+#define DO "font"
+#define DOES "fait"
+#define SCORE_UP "^[VOTRE SCORE VIENT D'AUGMENTER DE "
+#define POINT " POINT]^"
+#define POINTS " POINTS]^"
+#define STARTING "Démarrage."
+#define NO_IT "Vous devez préalablement avoir fait référence à un nom reconnu pour pouvoir utiliser le mot ~"
+#define NO_IT_END "~.^"
+#define BACK_REFERENCE "Vous devez préalablement avoir fait référence à un nom reconnu dans la même phrase pour pouvoir utiliser le mot ~"
+#define BACK_REFERENCE_END "~.^"
+#define WHEN_YOU_SAY "When you say ~"
+#define MUST_SPECIFY "~, vous devez spécifier si vous voulez dire "
+#define OR_WORD " ou "
+
+/* SYSTEM MESSAGES */
+#define READ_ERROR "Erreur de lecture du fichier de jeu."
+#define OLD_INTERPRETER "La version de l'interpréteur est plus ancienne que le fichier de jeu (v%d), impossible de continuer."
+#define BAD_CURSOR "You can only use the ~cursor~ command in the status window.^"
+#define INCOMPLETE_GRAMMAR "Incomplete grammar statement."
+#define GAME_MODIFIED "Game file modified, reloading.\n"
+#define NOT_INTEGER "In function \"%s\", \"%s\" command requires integer parameter."
+#define NO_NAME_FUNCTION "In line %d, a function must have at least one name."
+#define MAXIMUM_ATTRIBUTES_ERR "In line %d, unable to create attribute \"%s\", maximum number of attributes already defined."
+#define BAD_PLAYER "In function \"%s\", attempt to use object pointer \"player\" while it does not point to an object (%d)."
+#define BAD_PARENT "In function \"%s\", attempt to use the variable 'here' while the variable 'player' does not have a legal parent."
+#define BAD_POINTER "In function \"%s\", attempt to use object pointer \"%s\" that does not point to an object (%d)."
+#define ILLEGAL_LABEL "In line %d, reserved word \"%s\" used as label."
+#define USED_LABEL_INT "In line %d, \"%s\" is already used as a variable label."
+#define USED_LABEL_CINT "In line %d, \"%s\" is already used as an integer constant label."
+#define USED_LABEL_STR "In line %d, \"%s\" is already used as a string label."
+#define USED_LABEL_CSTR "In line %d, \"%s\" is already used as a string constant label."
+#define USED_LABEL_ATT "In line %d, \"%s\" is already used as an attribute label."
+#define USED_LABEL_OBJ "In line %d, \"%s\" is already used as an object or location label."
+#define NO_OBJECT_ERR "In line %d, property \"%s\" defined before first object or location."
+#define BAD_INCLUDE "'#include' directive must be followed by file name enclosed in double quotes."
+#define BAD_PARAMETER "Unknown or inappropriate type of container '%s' associated with parameter '%s'."
+#define BAD_VALUE "Value '%s' cannot be stored in container '%s'."
+#define NO_MEDIA "WebJACL: Media file \"%s\" not found, external media support disabled.\n"
+#define MEDIA_REGISTERED "WebJACL: Registered %d media.\n"
+#define CLEANING_UP "WebJACL: Cleaning up...\n"
+#define NO_GAME "No game file specified, can't continue."
+#define NO_PORT "WebJACL: No port number specified (-p <number>), using default port %d.\n"
+#define WEBJACL_CONFIGURED "WebJACL server configured on %s:%d\n"
+#define NOT_FOUND "Unable to open game file, can't continue."
+#define CANT_OPEN "Unable to open processed file \"%s\", can't continue."
+#define CANT_RUN "A JACL game must contain at least one object (to represent the player), and at least one location (for the player to start in).^"
+#define NO_PLAYER "The object pointer 'player' does not point to an object.^"
+#define SELF_REFERENCE "In function \"%s\", reference to object \"%s\" whose parent is itself."
+#define EXECUTING "Executing function \"%s\".\n"
+#define NO_WHILE "In function \"%s\", 'endwhile' command without matching 'while' command."
+#define NO_ITERATE "In function \"%s\", 'enditerate' command without matching 'iterate' command."
+#define NO_UPDATE "In function \"%s\", 'endupdate' command without matching 'update' command."
+#define NO_REPEAT "In function \"%s\", 'until' command without matching 'repeat' command."
+#define NO_LOOP "In function \"%s\", 'endloop' command without matching 'loop' command."
+#define UNDEFINED_FUNCTION "In function \"%s\", attempt to execute undefined function \"%s\"."
+#define DIVIDE_BY_ZERO "In function \"%s\", division by zero error."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define UNKNOWN_COMMAND "In function \"%s\", unknown command \"%s\"."
+#define STACK_OVERFLOW "Stack overflow."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define OUT_OF_RANGE "In function \"%s\", element \"%s\" out of range (%d)."
+#define GLOBAL_SELF "Reference to 'self' from global function \"%s\"."
+#define NON_GLOBAL_FIRST "In line %d, non-global function before object or location."
+#define MAXIMUM_EXCEEDED "Maximum number of objects exceeded, can't continue."
+#define ERROR_DETECTED "1 error detected."
+#define ERRORS_DETECTED "%d errors detected."
+#define UNKOWN_OBJECT_RUN "In function \"%s\", reference to unknown object \"%s\"."
+#define UNKNOWN_FUNCTION_RUN "Attempt to execute unknown function \"%s\"."
+#define UNKNOWN_KEYWORD_ERR "In line %d, unknown keyword \"%s\"."
+#define UNKNOWN_ATTRIBUTE_ERR "In line %d, unknown attribute \"%s\"."
+#define UNKNOWN_VALUE_ERR "In line %d, unable to resolve value \"%s\"."
+#define UNKNOWN_ATTRIBUTE_RUN "In function \"%s\", reference to unknown attribute \"%s\"."
+#define INSUFFICIENT_PARAMETERS_RUN "In function \"%s\", \"%s\" command with insufficient parameters."
+#define INSUFFICIENT_PARAMETERS_ERR "In line %d, \"%s\" keyword with insufficient parameters."
+#define UNDEFINED_ITEM_ERR "In line %d, reference to undefined item \"%s\"."
+#define UNDEFINED_ITEM_RUN "In function \"%s\", reference to undefined object \"%s\"."
+#define UNDEFINED_DIRECTION_RUN "In function \"%s\", reference to undefined direction \"%s\"."
+#define UNKNOWN_SCOPE_RUN "In function \"%s\", reference to unknown scope \"%s\"."
+#define UNDEFINED_STRING_RUN "In function \"%s\", reference to undefined string \"%s\"."
+#define UNDEFINED_CONTAINER_RUN "In function \"%s\", reference to undefined container \"%s\"."
+#define OUT_OF_MEMORY "Out of memory, can't continue."
+#define CANT_OPEN_PROCESSED "Unable to open output file \"%s\" for writing, can't continue."
+#define CANT_OPEN_OR "Unable to open source file \"%s\" or \"%s\", can't continue."
+#define CANT_OPEN_SOURCE "Unable to open source file \"%s\", can't continue."
+#endif
+
+#if NATIVE_LANGUAGE==GERMAN
+/* GAME MESSAGES */
+#define COMMENT_IGNORED "No transcript running, comment ignored.^"
+#define COMMENT_RECORDED "Comment recorded.^"
+#define YES_WORD "yes"
+#define NO_WORD "no"
+#define YES_OR_NO "^Please enter ~yes~ or ~no~: "
+#define YES_WORD "yes"
+#define NO_WORD "no"
+#define INVALID_SELECTION "Invalid selection.^"
+#define RESTARTING "^Restarting...^"
+#define RETURN_GAME "^Returning to game.^"
+#define SCRIPTING_ON "Scripting on.^"
+#define SCRIPTING_OFF "Scripting off.^"
+#define SCRIPTING_ALREADY_OFF "Scripting already off.^"
+#define SCRIPTING_ALREADY_ON "Scripting already off.^"
+#define CANT_WRITE_SCRIPT "Unable to write to script file.^"
+#define ERROR_READING_WALKTHRU "Error reading walkthru file.^"
+#define BAD_OOPS "You must follow the ~oops~ command with the word you wish to use instead.^"
+#define CANT_CORRECT "I can't correct the last command using ~oops~, sorry.^"
+#define SURE_QUIT "Are you sure you want to quit?^"
+#define SURE_RESTART "Are you sure you want to restart?^"
+#define NOT_CLEVER "It wasn't so clever as to be worth repeating.^"
+#define NO_MOVES "But you haven't done anything yet!^"
+#define TYPE_NUMBER "^Type a number between %d and %d: "
+#define BY "By ~"
+#define REFERRING_TO "~, are you referring to:^"
+#define WALKTHRU_WORD "walkthru"
+#define INFO_WORD "info"
+#define RESTART_WORD "restart"
+#define AGAIN_WORD "again"
+#define SCRIPT_WORD "script"
+#define UNSCRIPT_WORD "unscript"
+#define QUIT_WORD "quit"
+#define UNDO_WORD "undo"
+#define OOPS_WORD "oops"
+#define FROM_WORD "from"
+#define EXCEPT_WORD "except"
+#define FOR_WORD "for"
+#define BUT_WORD "but"
+#define AND_WORD "and"
+#define THEN_WORD "then"
+#define OF_WORD "of"
+#define SHE_WORD "she"
+#define HE_WORD "he"
+#define THAT_WORD "that"
+#define THEM_WORD "them"
+#define THOSE_WORD "those"
+#define THEY_WORD "they"
+#define IT_WORD "it"
+#define ITSELF_WORD "itself"
+#define HIM_WORD "him"
+#define HIMSELF_WORD "himself"
+#define HER_WORD "her"
+#define HERSELF_WORD "herself"
+#define THEMSELVES_WORD "themselves"
+#define YOU_WORD "you"
+#define YOURSELF_WORD "yourself"
+#define ONES_WORD "ones"
+#define NO_MULTI_VERB "You can't refer to multiple objects directly after the word ~%s~.^"
+#define NO_MULTI_START "You can't refer to multiple objects at the start of a command.^"
+#define PERSON_CONCEALING "%s doesn't seem to be carrying any such thing.^"
+#define PERSON_POSSESSIVE "%s isn't about to let you take anything of theirs.^"
+#define CONTAINER_CLOSED "%s is closed.^"
+#define CONTAINER_CLOSED_FEM "%s is closed.^"
+#define FROM_NON_CONTAINER "The word ~%s~ must be followed by a container.^"
+#define DOUBLE_EXCEPT "You can only use the word ~%s~ once per object reference.^"
+#define NONE_HELD "You are not holding anything like that.^"
+#define NO_OBJECTS "I don't see what you are referring to.^"
+#define NO_FILENAME "Save and restore commands must be followed by a filename.^"
+#define MOVE_UNDONE "Previous move undone.^^"
+#define NO_UNDO "Nothing to undo.^"
+#define CANT_SAVE "Unable to save game state to file.^"
+#define CANT_RESTORE "Unable to restore game state from file.^"
+#define GAME_SAVED "Game saved.^"
+#define INCOMPLETE_SENTENCE "The sentence you typed was incomplete.^"
+#define UNKNOWN_OBJECT "You can't see any such thing as ~"
+#define UNKNOWN_OBJECT_END "~.^"
+#define CANT_USE_WORD "You can't use the word ~"
+#define IN_CONTEXT "~ in that context.^"
+#define DONT_SEE "You don't see "
+#define HERE_WORD " here.^"
+#define BAD_SAVED_GAME "Attempt to restore incompatible saved-game file."
+#define ARENT "aren't"
+#define ISNT "isn't"
+#define ARE "are"
+#define IS "is"
+#define DONT "don't"
+#define DOESNT "doesn't"
+#define DO "do"
+#define DOES "does"
+#define SCORE_UP "^[YOUR SCORE JUST WENT UP BY "
+#define POINT " POINT]^"
+#define POINTS " POINTS]^"
+#define STARTING "Starting."
+#define NO_IT "You must have referred to an appropriate noun previously to use the word ~"
+#define NO_IT_END "~.^"
+#define BACK_REFERENCE "You must have referred to a noun previously in the same sentence to use the word ~"
+#define BACK_REFERENCE_END "~.^"
+#define WHEN_YOU_SAY "When you say ~"
+#define MUST_SPECIFY "~, you must specify whether you mean "
+#define OR_WORD " or "
+
+/* SYSTEM MESSAGES */
+#define READ_ERROR "Error reading game file."
+#define OLD_INTERPRETER "Interpreter version is older than game file (v%d), can't continue."
+#define BAD_CURSOR "You can only use the ~cursor~ command in the status window.^"
+#define INCOMPLETE_GRAMMAR "Incomplete grammar statement."
+#define GAME_MODIFIED "Game file modified, reloading.\n"
+#define NOT_INTEGER "In function \"%s\", \"%s\" command requires integer parameter."
+#define NO_NAME_FUNCTION "In line %d, a function must have at least one name."
+#define MAXIMUM_ATTRIBUTES_ERR "In line %d, unable to create attribute \"%s\", maximum number of attributes already defined."
+#define BAD_PLAYER "In function \"%s\", attempt to use object pointer \"player\" while it does not point to an object (%d)."
+#define BAD_PARENT "In function \"%s\", attempt to use the variable 'here' while the variable 'player' does not have a legal parent."
+#define BAD_POINTER "In function \"%s\", attempt to use object pointer \"%s\" that does not point to an object (%d)."
+#define ILLEGAL_LABEL "In line %d, reserved word \"%s\" used as label."
+#define USED_LABEL_INT "In line %d, \"%s\" is already used as a variable label."
+#define USED_LABEL_CINT "In line %d, \"%s\" is already used as an integer constant label."
+#define USED_LABEL_STR "In line %d, \"%s\" is already used as a string label."
+#define USED_LABEL_CSTR "In line %d, \"%s\" is already used as a string constant label."
+#define USED_LABEL_ATT "In line %d, \"%s\" is already used as an attribute label."
+#define USED_LABEL_OBJ "In line %d, \"%s\" is already used as an object or location label."
+#define NO_OBJECT_ERR "In line %d, property \"%s\" defined before first object or location."
+#define BAD_INCLUDE "'#include' directive must be followed by file name enclosed in double quotes."
+#define BAD_PARAMETER "Unknown or inappropriate type of container '%s' associated with parameter '%s'."
+#define BAD_VALUE "Value '%s' cannot be stored in container '%s'."
+#define NO_MEDIA "WebJACL: Media file \"%s\" not found, external media support disabled.\n"
+#define MEDIA_REGISTERED "WebJACL: Registered %d media.\n"
+#define CLEANING_UP "WebJACL: Cleaning up...\n"
+#define NO_GAME "No game file specified, can't continue."
+#define NO_PORT "WebJACL: No port number specified (-p <number>), using default port %d.\n"
+#define WEBJACL_CONFIGURED "WebJACL server configured on %s:%d\n"
+#define NOT_FOUND "Unable to open game file, can't continue."
+#define CANT_OPEN "Unable to open processed file \"%s\", can't continue."
+#define CANT_RUN "A JACL game must contain at least one object (to represent the player), and at least one location (for the player to start in).^"
+#define NO_PLAYER "The object pointer 'player' does not point to an object.^"
+#define SELF_REFERENCE "In function \"%s\", reference to object \"%s\" whose parent is itself."
+#define EXECUTING "Executing function \"%s\".\n"
+#define NO_WHILE "In function \"%s\", 'endwhile' command without matching 'while' command."
+#define NO_ITERATE "In function \"%s\", 'enditerate' command without matching 'iterate' command."
+#define NO_UPDATE "In function \"%s\", 'endupdate' command without matching 'update' command."
+#define NO_REPEAT "In function \"%s\", 'until' command without matching 'repeat' command."
+#define NO_LOOP "In function \"%s\", 'endloop' command without matching 'loop' command."
+#define UNDEFINED_FUNCTION "In function \"%s\", attempt to execute undefined function \"%s\"."
+#define DIVIDE_BY_ZERO "In function \"%s\", division by zero error."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define UNKNOWN_COMMAND "In function \"%s\", unknown command \"%s\"."
+#define STACK_OVERFLOW "Stack overflow."
+#define ILLEGAL_OPERATOR "In function \"%s\", illegal operator \"%s\"."
+#define OUT_OF_RANGE "In function \"%s\", element \"%s\" out of range (%d)."
+#define GLOBAL_SELF "Reference to 'self' from global function \"%s\"."
+#define NON_GLOBAL_FIRST "In line %d, non-global function before object or location."
+#define MAXIMUM_EXCEEDED "Maximum number of objects exceeded, can't continue."
+#define ERROR_DETECTED "1 error detected."
+#define ERRORS_DETECTED "%d errors detected."
+#define UNKOWN_OBJECT_RUN "In function \"%s\", reference to unknown object \"%s\"."
+#define UNKNOWN_FUNCTION_RUN "Attempt to execute unknown function \"%s\"."
+#define UNKNOWN_KEYWORD_ERR "In line %d, unknown keyword \"%s\"."
+#define UNKNOWN_ATTRIBUTE_ERR "In line %d, unknown attribute \"%s\"."
+#define UNKNOWN_VALUE_ERR "In line %d, unable to resolve value \"%s\"."
+#define UNKNOWN_ATTRIBUTE_RUN "In function \"%s\", reference to unknown attribute \"%s\"."
+#define INSUFFICIENT_PARAMETERS_RUN "In function \"%s\", \"%s\" command with insufficient parameters."
+#define INSUFFICIENT_PARAMETERS_ERR "In line %d, \"%s\" keyword with insufficient parameters."
+#define UNDEFINED_ITEM_ERR "In line %d, reference to undefined item \"%s\"."
+#define UNDEFINED_ITEM_RUN "In function \"%s\", reference to undefined object \"%s\"."
+#define UNDEFINED_DIRECTION_RUN "In function \"%s\", reference to undefined direction \"%s\"."
+#define UNKNOWN_SCOPE_RUN "In function \"%s\", reference to unknown scope \"%s\"."
+#define UNDEFINED_STRING_RUN "In function \"%s\", reference to undefined string \"%s\"."
+#define UNDEFINED_CONTAINER_RUN "In function \"%s\", reference to undefined container \"%s\"."
+#define OUT_OF_MEMORY "Out of memory, can't continue."
+#define CANT_OPEN_PROCESSED "Unable to open output file \"%s\" for writing, can't continue."
+#define CANT_OPEN_OR "Unable to open source file \"%s\" or \"%s\", can't continue."
+#define CANT_OPEN_SOURCE "Unable to open source file \"%s\", can't continue."
+#endif
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/libcsv.cpp b/engines/glk/jacl/libcsv.cpp
new file mode 100644
index 0000000..408e60b
--- /dev/null
+++ b/engines/glk/jacl/libcsv.cpp
@@ -0,0 +1,529 @@
+/* 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/jacl/csv.h"
+
+namespace Glk {
+namespace JACL {
+
+#define VERSION "3.0.0"
+
+//#define SIZE_MAX ((size_t)-1)
+
+#define ROW_NOT_BEGUN 0
+#define FIELD_NOT_BEGUN 1
+#define FIELD_BEGUN 2
+#define FIELD_MIGHT_HAVE_ENDED 3
+
+/*
+ Explanation of states
+ ROW_NOT_BEGUN There have not been any fields encountered for this row
+ FIELD_NOT_BEGUN There have been fields but we are currently not in one
+ FIELD_BEGUN We are in a field
+ FIELD_MIGHT_HAVE_ENDED
+ We encountered a double quote inside a quoted field, the
+ field is either ended or the quote is literal
+*/
+
+#define MEM_BLK_SIZE 128
+
+#define SUBMIT_FIELD(p) \
+ do { \
+ if (!quoted) \
+ entry_pos -= spaces; \
+ if (p->options & CSV_APPEND_NULL) \
+ ((p)->entry_buf[entry_pos+1]) = '\0'; \
+ if (cb1) \
+ cb1(p->entry_buf, entry_pos, data); \
+ pstate = FIELD_NOT_BEGUN; \
+ entry_pos = quoted = spaces = 0; \
+ } while (0)
+
+#define SUBMIT_ROW(p, c) \
+ do { \
+ if (cb2) \
+ cb2(c, data); \
+ pstate = ROW_NOT_BEGUN; \
+ entry_pos = quoted = spaces = 0; \
+ } while (0)
+
+#define SUBMIT_CHAR(p, c) ((p)->entry_buf[entry_pos++] = (c))
+
+static char *csv_errors[] = {"success",
+ "error parsing data while strict checking enabled",
+ "memory exhausted while increasing buffer size",
+ "data size too large",
+ "invalid status code"
+ };
+
+int csv_error(struct csv_parser *p) {
+ /* Return the current status of the parser */
+ return p->status;
+}
+
+char *csv_strerror(int status) {
+ /* Return a textual description of status */
+ if (status >= CSV_EINVALID || status < 0)
+ return csv_errors[CSV_EINVALID];
+ else
+ return csv_errors[status];
+}
+
+int csv_get_opts(struct csv_parser *p) {
+ /* Return the currently set options of parser */
+ if (p == NULL)
+ return -1;
+
+ return p->options;
+}
+
+int csv_set_opts(struct csv_parser *p, unsigned char options) {
+ /* Set the options */
+ if (p == NULL)
+ return -1;
+
+ p->options = options;
+ return 0;
+}
+
+int csv_init(struct csv_parser *p, unsigned char options) {
+ /* Initialize a csv_parser object returns 0 on success, -1 on error */
+ if (p == NULL)
+ return -1;
+
+ p->entry_buf = NULL;
+ p->pstate = ROW_NOT_BEGUN;
+ p->quoted = 0;
+ p->spaces = 0;
+ p->entry_pos = 0;
+ p->entry_size = 0;
+ p->status = 0;
+ p->options = options;
+ p->quote_char = CSV_QUOTE;
+ p->delim_char = CSV_COMMA;
+ p->is_space = NULL;
+ p->is_term = NULL;
+ p->blk_size = MEM_BLK_SIZE;
+ p->malloc_func = NULL;
+ p->realloc_func = realloc;
+ p->free_func = free;
+
+ return 0;
+}
+
+void csv_free(struct csv_parser *p) {
+ /* Free the entry_buffer of csv_parser object */
+ if (p == NULL)
+ return;
+
+ if (p->entry_buf)
+ p->free_func(p->entry_buf);
+
+ p->entry_buf = NULL;
+ p->entry_size = 0;
+
+ return;
+}
+
+int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int c, void *), void *data) {
+ /* Finalize parsing. Needed, for example, when file does not end in a newline */
+ int quoted = p->quoted;
+ int pstate = p->pstate;
+ size_t spaces = p->spaces;
+ size_t entry_pos = p->entry_pos;
+
+ if (p == NULL)
+ return -1;
+
+
+ if (p->pstate == FIELD_BEGUN && p->quoted && p->options & CSV_STRICT && p->options & CSV_STRICT_FINI) {
+ /* Current field is quoted, no end-quote was seen, and CSV_STRICT_FINI is set */
+ p->status = CSV_EPARSE;
+ return -1;
+ }
+
+ switch (p->pstate) {
+ case FIELD_MIGHT_HAVE_ENDED:
+ p->entry_pos -= p->spaces + 1; /* get rid of spaces and original quote */
+ /* Fall-through */
+ case FIELD_NOT_BEGUN:
+ case FIELD_BEGUN:
+ quoted = p->quoted, pstate = p->pstate;
+ spaces = p->spaces, entry_pos = p->entry_pos;
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, -1);
+ case ROW_NOT_BEGUN: /* Already ended properly */
+ ;
+ }
+
+ /* Reset parser */
+ p->spaces = p->quoted = p->entry_pos = p->status = 0;
+ p->pstate = ROW_NOT_BEGUN;
+
+ return 0;
+}
+
+void csv_set_delim(struct csv_parser *p, unsigned char c) {
+ /* Set the delimiter */
+ if (p) p->delim_char = c;
+}
+
+void csv_set_quote(struct csv_parser *p, unsigned char c) {
+ /* Set the quote character */
+ if (p) p->quote_char = c;
+}
+
+unsigned char csv_get_delim(struct csv_parser *p) {
+ /* Get the delimiter */
+ return p->delim_char;
+}
+
+unsigned char csv_get_quote(struct csv_parser *p) {
+ /* Get the quote character */
+ return p->quote_char;
+}
+
+void csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char)) {
+ /* Set the space function */
+ if (p) p->is_space = f;
+}
+
+void csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char)) {
+ /* Set the term function */
+ if (p) p->is_term = f;
+}
+
+void csv_set_realloc_func(struct csv_parser *p, void *(*f)(void *, size_t)) {
+ /* Set the realloc function used to increase buffer size */
+ if (p && f) p->realloc_func = f;
+}
+
+void csv_set_free_func(struct csv_parser *p, void (*f)(void *)) {
+ /* Set the free function used to free the buffer */
+ if (p && f) p->free_func = f;
+}
+
+void csv_set_blk_size(struct csv_parser *p, size_t size) {
+ /* Set the block size used to increment buffer size */
+ if (p) p->blk_size = size;
+}
+
+size_t csv_get_buffer_size(struct csv_parser *p) {
+ /* Get the size of the entry buffer */
+ if (p)
+ return p->entry_size;
+ return 0;
+}
+
+static int csv_increase_buffer(struct csv_parser *p) {
+ /* Increase the size of the entry buffer. Attempt to increase size by
+ * p->blk_size, if this is larger than SIZE_MAX try to increase current
+ * buffer size to SIZE_MAX. If allocation fails, try to allocate halve
+ * the size and try again until successful or increment size is zero.
+ */
+
+ size_t to_add = p->blk_size;
+ void *vp;
+
+ if (p->entry_size >= SIZE_MAX - to_add)
+ to_add = SIZE_MAX - p->entry_size;
+
+ if (!to_add) {
+ p->status = CSV_ETOOBIG;
+ return -1;
+ }
+
+ while ((vp = p->realloc_func(p->entry_buf, p->entry_size + to_add)) == NULL) {
+ to_add /= 2;
+ if (!to_add) {
+ p->status = CSV_ENOMEM;
+ return -1;
+ }
+ }
+
+ /* Update entry buffer pointer and entry_size if successful */
+ p->entry_buf = (unsigned char *)vp;
+ p->entry_size += to_add;
+ return 0;
+}
+
+size_t csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *),
+ void (*cb2)(int c, void *), void *data) {
+ unsigned const char *us = (unsigned const char *)s; /* Access input data as array of unsigned char */
+ unsigned char c; /* The character we are currently processing */
+ size_t pos = 0; /* The number of characters we have processed in this call */
+
+ /* Store key fields into local variables for performance */
+ unsigned char delim = p->delim_char;
+ unsigned char quote = p->quote_char;
+ int (*is_space)(unsigned char) = p->is_space;
+ int (*is_term)(unsigned char) = p->is_term;
+ int quoted = p->quoted;
+ int pstate = p->pstate;
+ size_t spaces = p->spaces;
+ size_t entry_pos = p->entry_pos;
+
+
+ if (!p->entry_buf && pos < len) {
+ /* Buffer hasn't been allocated yet and len > 0 */
+ if (csv_increase_buffer(p) != 0) {
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+ }
+ }
+
+ while (pos < len) {
+ /* Check memory usage, increase buffer if neccessary */
+ if (entry_pos == ((p->options & CSV_APPEND_NULL) ? p->entry_size - 1 : p->entry_size)) {
+ if (csv_increase_buffer(p) != 0) {
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+ }
+ }
+
+ c = us[pos++];
+
+ switch (pstate) {
+ case ROW_NOT_BEGUN:
+ case FIELD_NOT_BEGUN:
+ if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
+ continue;
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ if (pstate == FIELD_NOT_BEGUN) {
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else { /* ROW_NOT_BEGUN */
+ /* Don't submit empty rows by default */
+ if (p->options & CSV_REPALL_NL) {
+ SUBMIT_ROW(p, (unsigned char)c);
+ }
+ }
+ continue;
+ } else if (c == delim) { /* Comma */
+ SUBMIT_FIELD(p);
+ break;
+ } else if (c == quote) { /* Quote */
+ pstate = FIELD_BEGUN;
+ quoted = 1;
+ } else { /* Anything else */
+ pstate = FIELD_BEGUN;
+ quoted = 0;
+ SUBMIT_CHAR(p, c);
+ }
+ break;
+ case FIELD_BEGUN:
+ if (c == quote) { /* Quote */
+ if (quoted) {
+ SUBMIT_CHAR(p, c);
+ pstate = FIELD_MIGHT_HAVE_ENDED;
+ } else {
+ /* STRICT ERROR - double quote inside non-quoted field */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos - 1;
+ }
+ SUBMIT_CHAR(p, c);
+ spaces = 0;
+ }
+ } else if (c == delim) { /* Comma */
+ if (quoted) {
+ SUBMIT_CHAR(p, c);
+ } else {
+ SUBMIT_FIELD(p);
+ }
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ if (!quoted) {
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else {
+ SUBMIT_CHAR(p, c);
+ }
+ } else if (!quoted && (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB)) { /* Tab or space for non-quoted field */
+ SUBMIT_CHAR(p, c);
+ spaces++;
+ } else { /* Anything else */
+ SUBMIT_CHAR(p, c);
+ spaces = 0;
+ }
+ break;
+ case FIELD_MIGHT_HAVE_ENDED:
+ /* This only happens when a quote character is encountered in a quoted field */
+ if (c == delim) { /* Comma */
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
+ SUBMIT_FIELD(p);
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
+ SUBMIT_CHAR(p, c);
+ spaces++;
+ } else if (c == quote) { /* Quote */
+ if (spaces) {
+ /* STRICT ERROR - unescaped double quote */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos - 1;
+ }
+ spaces = 0;
+ SUBMIT_CHAR(p, c);
+ } else {
+ /* Two quotes in a row */
+ pstate = FIELD_BEGUN;
+ }
+ } else { /* Anything else */
+ /* STRICT ERROR - unescaped double quote */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos - 1;
+ }
+ pstate = FIELD_BEGUN;
+ spaces = 0;
+ SUBMIT_CHAR(p, c);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+}
+
+size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size) {
+ unsigned char *cdest = (unsigned char *)dest;
+ const unsigned char *csrc = (const unsigned char *)src;
+ size_t chars = 0;
+
+ if (src == NULL)
+ return 0;
+
+ if (cdest == NULL)
+ dest_size = 0;
+
+ if (dest_size > 0)
+ *cdest++ = '"';
+ chars++;
+
+ while (src_size) {
+ if (*csrc == '"') {
+ if (dest_size > chars)
+ *cdest++ = '"';
+ if (chars < SIZE_MAX) chars++;
+ }
+ if (dest_size > chars)
+ *cdest++ = *csrc;
+ if (chars < SIZE_MAX) chars++;
+ src_size--;
+ csrc++;
+ }
+
+ if (dest_size > chars)
+ *cdest = '"';
+ if (chars < SIZE_MAX) chars++;
+
+ return chars;
+}
+
+int csv_fwrite(Common::WriteStream *fp, const void *src, size_t src_size) {
+ const unsigned char *csrc = (const unsigned char *)src;
+
+ if (fp == NULL || src == NULL)
+ return 0;
+
+ fp->writeByte('"');
+
+ while (src_size) {
+ if (*csrc == '"') {
+ fp->writeByte('"');
+ }
+ fp->writeByte(*csrc);
+ src_size--;
+ csrc++;
+ }
+
+ fp->writeByte('"');
+ return 0;
+}
+
+size_t csv_write2(void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote) {
+ unsigned char *cdest = (unsigned char *)dest;
+ const unsigned char *csrc = (const unsigned char *)src;
+ size_t chars = 0;
+
+ if (src == NULL)
+ return 0;
+
+ if (dest == NULL)
+ dest_size = 0;
+
+ if (dest_size > 0)
+ *cdest++ = quote;
+ chars++;
+
+ while (src_size) {
+ if (*csrc == quote) {
+ if (dest_size > chars)
+ *cdest++ = quote;
+ if (chars < SIZE_MAX) chars++;
+ }
+ if (dest_size > chars)
+ *cdest++ = *csrc;
+ if (chars < SIZE_MAX) chars++;
+ src_size--;
+ csrc++;
+ }
+
+ if (dest_size > chars)
+ *cdest = quote;
+ if (chars < SIZE_MAX) chars++;
+
+ return chars;
+}
+
+int csv_fwrite2(Common::WriteStream *fp, const void *src, size_t src_size, unsigned char quote) {
+ const unsigned char *csrc = (const unsigned char *)src;
+
+ if (fp == NULL || src == NULL)
+ return 0;
+
+ fp->writeByte(quote);
+
+ while (src_size) {
+ if (*csrc == quote) {
+ fp->writeByte(quote);
+ }
+ fp->writeByte(*csrc);
+ src_size--;
+ csrc++;
+ }
+
+ fp->writeByte(quote);
+ return 0;
+}
+
+} // End of namespace JACL
+} // End of namespace Glk
diff --git a/engines/glk/jacl/loader.cpp b/engines/glk/jacl/loader.cpp
new file mode 100644
index 0000000..345aa18
--- /dev/null
+++ b/engines/glk/jacl/loader.cpp
@@ -0,0 +1,1775 @@
+/* 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/jacl/jacl.h"
+#include "glk/jacl/language.h"
+#include "glk/jacl/types.h"
+#include "glk/jacl/prototypes.h"
+#include "glk/jacl/version.h"
+
+namespace Glk {
+namespace JACL {
+
+/* INDICATES THAT THE CURRENT '.j2' FILE BEING WORKED
+ * WITH IS ENCRYPTED */
+int encrypted = FALSE;
+
+extern char text_buffer[];
+extern char temp_buffer[];
+extern char prefix[];
+extern char error_buffer[];
+extern char *word[];
+extern int quoted[];
+extern int punctuated[];
+extern int wp;
+
+#ifdef GLK
+extern schanid_t sound_channel[];
+#else
+#ifndef __NDS__
+extern struct parameter_type *parameter_table;
+struct parameter_type *current_parameter = NULL;
+struct parameter_type *new_parameter;
+#endif
+#endif
+
+extern struct object_type *object[];
+extern struct integer_type *integer_table;
+extern struct integer_type *integer[];
+extern struct cinteger_type *cinteger_table;
+extern struct string_type *string_table;
+extern struct string_type *cstring_table;
+extern struct attribute_type *attribute_table;
+extern struct function_type *function_table;
+extern struct function_type *executing_function;
+extern struct command_type *completion_list;
+extern struct word_type *grammar_table;
+extern struct synonym_type *synonym_table;
+extern struct filter_type *filter_table;
+
+
+struct string_type *current_string = NULL;
+struct integer_type *current_integer = NULL;
+struct integer_type *last_system_integer = NULL;
+
+extern struct string_type *current_cstring;
+extern struct cinteger_type *current_cinteger;
+
+#ifdef GLK
+extern strid_t game_stream;
+#else
+extern FILE *file;
+#endif
+
+extern int objects;
+extern int integers;
+extern int functions;
+extern int strings;
+extern int player;
+
+extern int it;
+extern int them[];
+extern int her;
+extern int him;
+extern int parent;
+
+extern int noun[];
+
+int value_resolved;
+
+void read_gamefile() {
+ int index,
+ counter,
+ errors;
+#ifdef GLK
+ int result;
+#endif
+ int location_count = 0;
+ int object_count = 0;
+ int line = 0;
+ int self_parent = 0;
+
+ long start_of_file = 0;
+#ifdef GLK
+ glui32 current_file_position;
+#else
+ long current_file_position;
+#endif
+
+ long bit_mask;
+
+ struct filter_type *current_filter = NULL;
+ struct filter_type *new_filter = NULL;
+ struct attribute_type *current_attribute = NULL;
+ struct attribute_type *new_attribute = NULL;
+ struct cinteger_type *resolved_cinteger = NULL;
+ struct synonym_type *current_synonym = NULL;
+ struct synonym_type *new_synonym = NULL;
+ struct function_type *current_function = NULL;
+ struct name_type *current_name = NULL;
+
+ char function_name[81];
+
+ // CREATE SOME SYSTEM VARIABLES
+
+ // THIS IS USED BY JACL FUNCTIONS TO PASS STRING VALUES BACK
+ // TO THE INTERPRETER AS JACL FUNCTION CAN ONLY RETURN
+ // AN INTEGER
+ create_string("return_value", "");
+
+ create_cstring("function_name", "JACL*Internal");
+
+ // THESE ARE THE FIELDS FOR THE CSV PARSER
+ create_cstring("field", "field0");
+ create_cstring("field", "field1");
+ create_cstring("field", "field2");
+ create_cstring("field", "field3");
+ create_cstring("field", "field4");
+ create_cstring("field", "field5");
+ create_cstring("field", "field6");
+ create_cstring("field", "field7");
+ create_cstring("field", "field8");
+ create_cstring("field", "field9");
+ create_cstring("field", "field10");
+ create_cstring("field", "field11");
+ create_cstring("field", "field12");
+ create_cstring("field", "field13");
+ create_cstring("field", "field14");
+ create_cstring("field", "field15");
+ create_cstring("field", "field16");
+ create_cstring("field", "field17");
+ create_cstring("field", "field18");
+ create_cstring("field", "field19");
+
+ create_cinteger("field_count", 0);
+
+ create_integer("compass", 0);
+ // START AT -1 AS TIME PASSES BEFORE THE FIRST PROMPT
+ create_integer("total_moves", -1);
+ create_integer("time", TRUE);
+ create_integer("score", 0);
+ create_integer("display_mode", 0);
+ create_integer("internal_version", J_VERSION);
+ create_integer("max_rand", 100);
+ create_integer("destination", 0);
+ create_integer("interrupted", 0);
+ create_integer("debug", 0);
+ create_integer("graphics_enabled", 0);
+ create_integer("sound_enabled", 0);
+ create_integer("timer_enabled", 0);
+ create_integer("multi_prefix", 0);
+ create_integer("notify", 1);
+ create_integer("debug", 0);
+ create_integer("linebreaks", 1);
+
+ /* STORE THIS SO THE SECOND PASS KNOWS WHERE TO START
+ * SETTING VALUES FROM (EVERYTHING BEFORE THIS IN THE
+ * VARIABLE TABLE IS A SYSTEM VARIABLE */
+ last_system_integer = current_integer;
+
+ /* CREATE SOME SYSTEM CONSTANTS */
+ create_cinteger("graphics_supported", 0);
+ create_cinteger("sound_supported", 0);
+ create_cinteger("timer_supported", 0);
+ create_cinteger("GLK", 0);
+ create_cinteger("CGI", 1);
+ create_cinteger("NDS", 2);
+#ifdef GLK
+ create_cinteger("interpreter", 0);
+#else
+#ifdef __NDS__
+ create_cinteger("interpreter", 2);
+#else
+ create_cinteger("interpreter", 1);
+#endif
+#endif
+
+ /* TEST FOR AVAILABLE FUNCTIONALITY BEFORE EXECUTING ANY JACL CODE */
+
+#ifdef GLK
+ GRAPHICS_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Graphics, 0);
+ GRAPHICS_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Graphics, 0);
+ SOUND_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Sound, 0);
+ SOUND_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Sound, 0);
+ TIMER_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Timer, 0);
+ TIMER_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Timer, 0);
+#else
+ GRAPHICS_SUPPORTED->value = TRUE;
+ GRAPHICS_ENABLED->value = TRUE;
+ SOUND_SUPPORTED->value = TRUE;
+ SOUND_ENABLED->value = TRUE;
+ TIMER_SUPPORTED->value = FALSE;
+ TIMER_ENABLED->value = FALSE;
+#endif
+
+ create_cinteger("true", 1);
+ create_cinteger("false", 0);
+ create_cinteger("null", 0);
+ create_cinteger("nowhere", 0);
+ create_cinteger("heavy", HEAVY);
+ create_cinteger("scenery", SCENERY);
+ create_cinteger("north", NORTH_DIR);
+ create_cinteger("south", SOUTH_DIR);
+ create_cinteger("east", EAST_DIR);
+ create_cinteger("west", WEST_DIR);
+ create_cinteger("northeast", NORTHEAST_DIR);
+ create_cinteger("northwest", NORTHWEST_DIR);
+ create_cinteger("southeast", SOUTHEAST_DIR);
+ create_cinteger("southwest", SOUTHWEST_DIR);
+ create_cinteger("up", UP_DIR);
+ create_cinteger("down", DOWN_DIR);
+ create_cinteger("in", IN_DIR);
+ create_cinteger("out", OUT_DIR);
+ create_cinteger("parent", 0);
+ create_cinteger("quantity", 1);
+ create_cinteger("capacity", 1);
+ create_cinteger("mass", 2);
+ create_cinteger("bearing", 3);
+ create_cinteger("velocity", 4);
+ create_cinteger("next", 5);
+ create_cinteger("previous", 6);
+ create_cinteger("child", 7);
+ create_cinteger("index", 8);
+ create_cinteger("status", 9);
+ create_cinteger("state", 10);
+ create_cinteger("counter", 11);
+ create_cinteger("points", 12);
+ create_cinteger("class", 13);
+ create_cinteger("x", 14);
+ create_cinteger("y", 15);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("volume", 100);
+ create_cinteger("timer", 500);
+
+ set_defaults();
+
+ /* CREATE A DUMMY FUNCTION TO BE USED WHEN AN ERROR MESSAGE
+ IS PRINTED AS A RESULT OF CODE CALLED BY THE INTERPRETER */
+ if ((function_table = (struct function_type *)
+ malloc(sizeof(struct function_type))) == NULL)
+ outofmem();
+ else {
+ current_function = function_table;
+ strcpy(current_function->name, "JACL*Internal");
+ current_function->position = 0;
+ current_function->self = 0;
+ current_function->call_count = 0;
+ current_function->call_count_backup = 0;
+ current_function->next_function = NULL;
+ }
+
+ executing_function = function_table;
+
+ errors = 0;
+ objects = 0;
+ integers = 0;
+ functions = 0;
+ strings = 0;
+
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, start_of_file, seekmode_Start);
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fseek(file, start_of_file, SEEK_SET);
+ fgets(text_buffer, 1024, file);
+#endif
+
+ line++;
+
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+
+ if (encrypted) jacl_decrypt(text_buffer);
+
+#ifdef GLK
+ while (result) {
+#else
+ while (!feof(file)) {
+#endif
+ encapsulate();
+ if (word[0] == NULL);
+ else if (text_buffer[0] == '{') {
+#ifdef GLK
+ while (result) {
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ while (!feof(file)) {
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+ if (encrypted) jacl_decrypt(text_buffer);
+ if (text_buffer[0] == '}')
+ break;
+ }
+ }
+ else {
+ if (!strcmp(word[0], "grammar")) {
+ if (word[++wp] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ if (grammar_table == NULL) {
+ if ((grammar_table = (struct word_type *)
+ malloc(sizeof(struct word_type))) == NULL)
+ outofmem();
+ else {
+ strncpy(grammar_table->word, word[wp], 40);
+ grammar_table->word[40] = 0;
+ grammar_table->next_sibling = NULL;
+ grammar_table->first_child = NULL;
+ build_grammar_table(grammar_table);
+ }
+ } else
+ build_grammar_table(grammar_table);
+ }
+ } else if (!strcmp(word[0], "object")
+ || !strcmp(word[0], "location")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, OBJ_TYPE)) {
+ errors++;
+ } else {
+ objects++;
+
+ if (objects == MAX_OBJECTS) {
+ log_error(MAXIMUM_EXCEEDED, PLUS_STDERR);
+ terminate(47);
+ } else {
+ if ((object[objects] = (struct object_type *)
+ malloc(sizeof(struct object_type))) == NULL)
+ outofmem();
+
+ strncpy(object[objects]->label, word[1], 40);
+
+ object[objects]->label[40] = 0;
+ object[objects]->first_plural = NULL;
+
+ strcpy(object[objects]->described, object[objects]->label);
+ strcpy(object[objects]->inventory, object[objects]->label);
+ strcpy(object[objects]->article, "the");
+ strcpy(object[objects]->definite, "the");
+ object[objects]->attributes = FALSE;
+ object[objects]->user_attributes = FALSE;
+
+ for (counter = 0; counter < 16; counter++)
+ object[objects]->integer[counter] = 0;
+ }
+ object[objects]->nosave = FALSE;
+ }
+ } else if (!strcmp(word[0], "synonym")) {
+ if (word[++wp] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ if ((new_synonym = (struct synonym_type *)
+ malloc(sizeof(struct synonym_type))) == NULL)
+ outofmem();
+ else {
+ if (synonym_table == NULL) {
+ synonym_table = new_synonym;
+ } else {
+ current_synonym->next_synonym = new_synonym;
+ }
+ }
+ current_synonym = new_synonym;
+ strncpy(current_synonym->original, word[wp], 40);
+ current_synonym->original[40] = 0;
+ if (word[++wp] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ strncpy(current_synonym->standard, word[wp], 40);
+ current_synonym->standard[40] = 0;
+ }
+ current_synonym->next_synonym = NULL;
+ }
+ } else if (!strcmp(word[0], "parameter")) {
+#ifndef GLK
+#ifndef __NDS__
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ if ((new_parameter = (struct parameter_type *)
+ malloc(sizeof(struct parameter_type))) == NULL)
+ outofmem();
+ else {
+ if (parameter_table == NULL) {
+ parameter_table = new_parameter;
+ } else {
+ current_parameter->next_parameter =
+ new_parameter;
+ }
+ current_parameter = new_parameter;
+ strncpy(current_parameter->name, word[1], 40);
+ current_parameter->name[40] = 0;
+ strncpy(current_parameter->container, word[2], 40);
+ current_parameter->container[40] = 0;
+ current_parameter->next_parameter = NULL;
+ }
+
+ if (word[4] != NULL) {
+ if (validate(word[3]))
+ current_parameter->low = atoi(word[3]);
+ else
+ current_parameter->low = -65535;
+
+ if (validate(word[4]))
+ current_parameter->high = atoi(word[4]);
+ else
+ current_parameter->high = 65535;
+ } else {
+ current_parameter->low = -65535;
+ current_parameter->high = 65535;
+ }
+
+ }
+#endif
+#endif
+ } else if (!strcmp(word[0], "constant")) {
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ /* CHECK IF MORE THAN ONE VALUE IS SUPPLIED AND CREATE
+ ADDITIONAL CONSTANTS IF REQUIRED */
+ index = 2;
+
+ while (word[index] != NULL && index < MAX_WORDS) {
+ if (quoted[index] == TRUE || !validate(word[index])) {
+ if (legal_label_check(word[1], line, CSTR_TYPE)) {
+ errors++;
+ } else {
+ create_cstring(word[1], word[index]);
+ }
+ } else {
+ if (legal_label_check(word[1], line, CINT_TYPE)) {
+ errors++;
+ } else {
+ create_cinteger(word[1], value_of(word[index])/*, FALSE */);
+ if (!value_resolved) {
+ unkvalerr(line, index);
+ errors++;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ } else if (!strcmp(word[0], "attribute")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, ATT_TYPE)) {
+ errors++;
+ } else if (current_attribute != NULL && current_attribute->value == 1073741824) {
+ maxatterr(line, 1);
+ errors++;
+ } else {
+ if ((new_attribute = (struct attribute_type *)
+ malloc(sizeof(struct attribute_type))) == NULL)
+ outofmem();
+ else {
+ if (attribute_table == NULL) {
+ attribute_table = new_attribute;
+ new_attribute->value = 1;
+ } else {
+ current_attribute->next_attribute = new_attribute;
+ new_attribute->value = current_attribute->value * 2;
+ }
+ current_attribute = new_attribute;
+ strncpy(current_attribute->name, word[1], 40);
+ current_attribute->name[40] = 0;
+ current_attribute->next_attribute = NULL;
+ }
+
+ /* CHECK IF MORE THAN ONE VALUE IS SUPPLIED AND CREATE
+ ADDITIONAL CONSTANTS IF REQUIRED */
+ index = 2;
+ while (word[index] != NULL && index < MAX_WORDS) {
+ if (legal_label_check(word[index], line, ATT_TYPE)) {
+ errors++;
+ } else if (current_attribute != NULL && current_attribute->value == 1073741824) {
+ maxatterr(line, index);
+ errors++;
+ } else {
+ if ((new_attribute = (struct attribute_type *)
+ malloc(sizeof(struct attribute_type))) == NULL)
+ outofmem();
+ else {
+ current_attribute->next_attribute = new_attribute;
+ new_attribute->value = current_attribute->value * 2;
+ current_attribute = new_attribute;
+ strncpy(current_attribute->name, word[index], 40);
+ current_attribute->name[40] = 0;
+ current_attribute->next_attribute = NULL;
+ }
+ }
+ index++;
+ }
+ }
+ } else if (!strcmp(word[0], "string")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, STR_TYPE)) {
+ errors++;
+ } else {
+ if (word[2] == NULL) {
+ create_string(word[1], "");
+ } else {
+ create_string(word[1], word[2]);
+ index = 3;
+ while (word[index] != NULL && index < MAX_WORDS) {
+ create_string(word[1], word[index]);
+ index++;
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "filter")) {
+ if (word[++wp] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ if ((new_filter = (struct filter_type *)
+ malloc(sizeof(struct filter_type))) == NULL)
+ outofmem();
+ else {
+ if (filter_table == NULL) {
+ filter_table = new_filter;
+ } else {
+ current_filter->next_filter = new_filter;
+ }
+ current_filter = new_filter;
+ strncpy(current_filter->word, word[wp], 40);
+ current_filter->word[40] = 0;
+ current_filter->next_filter = NULL;
+ }
+ }
+ } else if (!strcmp(word[0], "string_array")) {
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, STR_TYPE)) {
+ errors++;
+ } else {
+ int x;
+
+ index = value_of(word[2], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 2);
+ errors++;
+ }
+
+ for (x = 0; x < index; x++) {
+ create_string(word[1], word[3]);
+ }
+ }
+ } else if (!strcmp(word[0], "integer_array")) {
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, INT_TYPE)) {
+ errors++;
+ } else {
+ int default_value, x;
+
+ if (word[3] != NULL) {
+ default_value = value_of(word[3], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 3);
+ errors++;
+ }
+ } else {
+ default_value = 0;
+ }
+
+ /* THIS IS THE NUMBER OF ARRAY ELEMENTS TO MAKE */
+ index = value_of(word[2], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 2);
+ errors++;
+ }
+
+ for (x = 0; x < index; x++) {
+ create_integer(word[1], default_value);
+ }
+ }
+ } else if (!strcmp(word[0], "integer")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (legal_label_check(word[1], line, INT_TYPE)) {
+ errors++;
+ } else {
+ create_integer(word[1], 0);
+
+ /* CHECK IF MORE THAN ONE VALUE IS SUPPLIED AND CREATE
+ ADDITIONAL VARIABLES IF REQUIRED */
+ index = 3;
+ while (word[index] != NULL && index < MAX_WORDS) {
+ create_integer(word[1], 0);
+ index++;
+ }
+ }
+ }
+ }
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+ if (encrypted) jacl_decrypt(text_buffer);
+ }
+
+ if (errors) {
+ totalerrs(errors);
+ terminate(48);
+ }
+
+ /*************************************************************************
+ * START OF SECOND PASS *
+ *************************************************************************/
+
+ /* IF NO SIZE IS SPECIFIED FOR THE STATUS WINDOW, SET IT TO 1 */
+ if (integer_resolve("status_window") == NULL) {
+ create_integer("status_window", 1);
+ }
+
+ /* IF NO STRING IS SPECIFIED FOR THE COMMAND PROMPT, SET IT TO "^> " */
+ if (string_resolve("command_prompt") == NULL) {
+ create_string("command_prompt", "^> ");
+ }
+
+ /* IF NO STRING IS SPECIFIED FOR THE GAME_TITLE, SET IT TO THE FILENAME */
+ if (cstring_resolve("game_title") == NULL) {
+ create_cstring("game_title", prefix);
+ }
+
+ create_language_constants();
+
+ /* MUST RE-DETERMINE THE POINT IN THE GAME FILE THAT ENCRYPTION STARTS */
+ encrypted = FALSE;
+
+ /* SET CURRENT VARIABLE TO POINT TO THE FIRST USER VARIABLE THAT WAS
+ * CREATED AFTER THE SYSTEM VARIABLES */
+ current_integer = last_system_integer;
+
+ line = 0;
+#ifdef GLK
+ g_vm->glk_stream_set_position(game_stream, start_of_file, seekmode_Start);
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fseek(file, start_of_file, SEEK_SET);
+ fgets(text_buffer, 1024, file);
+#endif
+
+ line++;
+
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+ if (encrypted) jacl_decrypt(text_buffer);
+
+#ifdef GLK
+ while (result) {
+#else
+ while (!feof(file)) {
+#endif
+ encapsulate();
+ if (word[0] == NULL);
+ else if (text_buffer[0] == '{') {
+ word[wp]++; /* MOVE THE START OF THE FIRST WORD ONLY
+ * TO PAST THE '{'. */
+ if (word[wp][0] == 0) {
+ nofnamerr(line);
+ errors++;
+ } else {
+ while (word[wp] != NULL && wp < MAX_WORDS) {
+ if (word[wp][0] == '+') {
+ strncpy(function_name, word[wp], 80);
+ function_name[80] = 0;
+ self_parent = 0;
+ } else if (word[wp][0] == '*') {
+ char *last_underscore = (char *) NULL;
+
+ /* ALLOW MANUAL NAMING OF ASSOCIATED FUNCTIONS */
+ /* TO GIVE CLASS-LIKE BEHAVIOR */
+ strncpy(function_name, word[wp] + 1, 80);
+ function_name[80] = 0;
+
+ /* LOOK FOR THE FINAL UNDERSCORE AND SEE IF */
+ /* IT IS FOLLOWED BY AN OBJECT LABEL */
+ last_underscore = strrchr(word[wp], '_');
+ if (last_underscore != NULL) {
+ self_parent = object_resolve(last_underscore + 1);
+ } else {
+ self_parent = 0;
+ }
+ } else if (object_count == 0) {
+ nongloberr(line);
+ errors++;
+ } else {
+ strncpy(function_name, word[wp], 59);
+ strcat(function_name, "_");
+ strcat(function_name, object[object_count]->label);
+ self_parent = object_count;
+ }
+ if (function_table == NULL) {
+ if ((function_table = (struct function_type *)
+ malloc(sizeof(struct function_type))) == NULL)
+ outofmem();
+ else {
+ // STORE THE NUMBER OF FUNCTION DEFINED TO
+ // HELP VALIDATE SAVED GAME FILES
+ functions++;
+
+ current_function = function_table;
+ strcpy(current_function->name, function_name);
+#ifdef GLK
+ current_function->position = g_vm->glk_stream_get_position(game_stream);
+#else
+ current_function->position = ftell(file);
+#endif
+ current_function->call_count = 0;
+ current_function->call_count_backup = 0;
+ current_function->self = self_parent;
+ current_function->next_function = NULL;
+ }
+ } else {
+ if ((current_function->next_function =
+ (struct function_type *)
+ malloc(sizeof(struct function_type))) == NULL)
+ outofmem();
+ else {
+ // STORE THE NUMBER OF FUNCTION DEFINED TO
+ // HELP VALIDATE SAVED GAME FILES
+ functions++;
+
+ current_function = current_function->next_function;
+ strcpy(current_function->name, function_name);
+#ifdef GLK
+ current_function->position = g_vm->glk_stream_get_position(game_stream);
+#else
+ current_function->position = ftell(file);
+#endif
+ current_function->call_count = 0;
+ current_function->call_count_backup = 0;
+ current_function->self = self_parent;
+ current_function->next_function = NULL;
+ }
+ }
+ wp++;
+ }
+ }
+
+#ifdef GLK
+ while (result) {
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ while (!feof(file)) {
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+ if (encrypted) jacl_decrypt(text_buffer);
+ if (text_buffer[0] == '}')
+ break;
+ }
+ }
+ else if (!strcmp(word[0], "string_array")) {
+ } else if (!strcmp(word[0], "integer_array")) {
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ int x;
+
+ /* THIS IS THE NUMBER OF ARRAY ELEMENTS TO MAKE */
+ index = value_of(word[2], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 2);
+ errors++;
+ }
+
+ for (x = 0; x < index; x++) {
+ current_integer = current_integer->next_integer;
+ }
+ }
+ } else if (!strcmp(word[0], "integer")) {
+ if (word[2] != NULL) {
+ current_integer = current_integer->next_integer;
+ current_integer->value = value_of(word[2], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 2);
+ errors++;
+ }
+ index = 3;
+ while (word[index] != NULL && index < MAX_WORDS) {
+ current_integer = current_integer->next_integer;
+ current_integer->value = value_of(word[index], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, index);
+ errors++;
+ }
+ index++;
+ }
+ } else {
+ current_integer = current_integer->next_integer;
+ current_integer->value = FALSE;
+ }
+
+ /* CONSUME ALL THESE KEYWORDS TO AVOID AN UNKNOWN KEYWORD */
+ /* ERROR DURING THE SECOND PASS (ALL WORK DONE IN FIRST PASS) */
+ } else if (!strcmp(word[0], "constant"));
+ else if (!strcmp(word[0], "string"));
+ else if (!strcmp(word[0], "attribute"));
+ else if (!strcmp(word[0], "parameter"));
+ else if (!strcmp(word[0], "synonym"));
+ else if (!strcmp(word[0], "grammar"));
+ else if (!strcmp(word[0], "filter"));
+ else if (!strcmp(word[0], "has")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else {
+ for (index = 1; word[index] != NULL && index < MAX_WORDS; index++) {
+ if ((bit_mask = attribute_resolve(word[index]))) {
+ object[object_count]->attributes = object[object_count]->attributes | bit_mask;
+ } else if ((bit_mask = user_attribute_resolve(word[index]))) {
+ object[object_count]->user_attributes = object[object_count]->user_attributes | bit_mask;
+ } else {
+ unkatterr(line, index);
+ errors++;
+ }
+ }
+ }
+ } else if (!strcmp(word[0], "object")
+ || !strcmp(word[0], "location")) {
+ object_count++;
+
+ if (!strcmp(word[0], "object")) {
+ object[object_count]->MASS = SCENERY;
+ if (location_count == 0)
+ object[object_count]->PARENT = 0;
+ else
+ object[object_count]->PARENT = location_count;
+ } else {
+ location_count = object_count;
+ object[object_count]->PARENT = 0;
+ object[object_count]->attributes =
+ object[object_count]->attributes | LOCATION;
+ }
+
+
+ if ((object[object_count]->first_name =
+ (struct name_type *) malloc(sizeof(struct name_type)))
+ == NULL)
+ outofmem();
+ else {
+ current_name = object[object_count]->first_name;
+ if (word[2] != NULL) {
+ strncpy(current_name->name, word[2], 40);
+ } else {
+ strncpy(current_name->name, object[object_count]->label, 40);
+ }
+ current_name->name[40] = 0;
+ current_name->next_name = NULL;
+ }
+
+ wp = 3;
+
+ while (word[wp] != NULL && wp < MAX_WORDS) {
+ if ((current_name->next_name = (struct name_type *)
+ malloc(sizeof(struct name_type))) == NULL)
+ outofmem();
+ else {
+ current_name = current_name->next_name;
+ strncpy(current_name->name, word[wp], 40);
+ current_name->name[40] = 0;
+ current_name->next_name = NULL;
+ }
+ wp++;
+ }
+ } else if (!strcmp(word[0], "plural")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else {
+ if ((object[object_count]->first_plural =
+ (struct name_type *) malloc(sizeof(struct name_type)))
+ == NULL)
+ outofmem();
+ else {
+ current_name = object[object_count]->first_plural;
+ strncpy(current_name->name, word[1], 40);
+ current_name->name[40] = 0;
+ current_name->next_name = NULL;
+ }
+
+ wp = 2;
+
+ while (word[wp] != NULL && wp < MAX_WORDS) {
+ if ((current_name->next_name = (struct name_type *)
+ malloc(sizeof(struct name_type))) == NULL)
+ outofmem();
+ else {
+ current_name = current_name->next_name;
+ strncpy(current_name->name, word[wp], 40);
+ current_name->name[40] = 0;
+ current_name->next_name = NULL;
+ }
+ wp++;
+ }
+ }
+ } else if (!strcmp(word[0], "static")) {
+ if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else
+ object[object_count]->nosave = TRUE;
+ } else if (!strcmp(word[0], "player")) {
+ if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else
+ player = object_count;
+ } else if (!strcmp(word[0], "short")) {
+ if (word[2] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else {
+ strncpy(object[object_count]->article, word[1], 10);
+ object[object_count]->article[10] = 0;
+ strncpy(object[object_count]->inventory, word[2], 40);
+ object[object_count]->inventory[40] = 0;
+ }
+ } else if (!strcmp(word[0], "definite")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else {
+ strncpy(object[object_count]->definite, word[1], 10);
+ object[object_count]->definite[10] = 0;
+ }
+ } else if (!strcmp(word[0], "long")) {
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else {
+ strncpy(object[object_count]->described, word[1], 80);
+ object[object_count]->described[80] = 0;
+ }
+ } else if ((resolved_cinteger = cinteger_resolve(word[0])) != NULL) {
+ index = resolved_cinteger->value;
+ if (word[1] == NULL) {
+ noproperr(line);
+ errors++;
+ } else if (object_count == 0) {
+ noobjerr(line);
+ errors++;
+ } else if (!strcmp(word[1], "here")) {
+ object[object_count]->integer[index] = location_count;
+ } else {
+ object[object_count]->integer[index] = value_of(word[1], FALSE);
+ if (!value_resolved) {
+ unkvalerr(line, 1);
+ errors++;
+ }
+ }
+ } else {
+ unkkeyerr(line, 0);
+ errors++;
+ }
+
+#ifdef GLK
+ current_file_position = g_vm->glk_stream_get_position(game_stream);
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ current_file_position = ftell(file);
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+
+ if (!encrypted && strstr(text_buffer, "#encrypted")) {
+ encrypted = TRUE;
+#ifdef GLK
+ result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+#else
+ fgets(text_buffer, 1024, file);
+#endif
+ line++;
+ }
+ if (encrypted) jacl_decrypt(text_buffer);
+ }
+
+ /* CREATE THE CONSTANT THE RECORDS THE TOTAL NUMBER OF OBJECTS */
+ create_cinteger("objects", objects);
+
+ /* LOOP THROUGH ALL THE OBJECTS AND CALL THEIR CONSTRUCTORS
+ for (index = 1; index <= objects; index++) {
+ strcpy (function_name, "constructor_");
+ strcat (function_name, object[index]->label);
+ execute (function_name);
+ }
+ */
+
+ if (errors) {
+ totalerrs(errors);
+ terminate(48);
+ }
+}
+
+void build_grammar_table(struct word_type *pointer) {
+ do {
+ if (!strcmp(word[wp], pointer->word)) {
+ if (pointer->first_child == NULL && word[wp + 1] != NULL) {
+ if ((pointer->first_child = (struct word_type *)
+ malloc(sizeof(struct word_type)))
+ == NULL)
+ outofmem();
+ else {
+ pointer = pointer->first_child;
+ strncpy(pointer->word, word[++wp], 40);
+ pointer->word[40] = 0;
+ pointer->next_sibling = NULL;
+ pointer->first_child = NULL;
+ }
+ } else {
+ pointer = pointer->first_child;
+ wp++;
+ }
+ } else {
+ if (pointer->next_sibling == NULL) {
+ if ((pointer->next_sibling = (struct word_type *)
+ malloc(sizeof(struct word_type)))
+ == NULL)
+ outofmem();
+ else {
+ pointer = pointer->next_sibling;
+ strncpy(pointer->word, word[wp], 40);
+ pointer->word[40] = 0;
+ pointer->next_sibling = NULL;
+ pointer->first_child = NULL;
+ }
+ } else
+ pointer = pointer->next_sibling;
+ }
+ } while (word[wp] != NULL && wp < MAX_WORDS);
+}
+
+int legal_label_check(char *word, int line, int type) {
+ struct integer_type *integer_pointer = integer_table;
+ struct cinteger_type *cinteger_pointer = cinteger_table;
+ struct string_type *string_pointer = string_table;
+ struct string_type *cstring_pointer = cstring_table;
+ struct attribute_type *attribute_pointer = attribute_table;
+
+ int index;
+
+ if (!strcmp(word, "here") ||
+ !strcmp(word, "player") ||
+ !strcmp(word, "integer") ||
+ !strcmp(word, "arg") ||
+ !strcmp(word, "string_arg") ||
+ !strcmp(word, "arg") ||
+ !strcmp(word, "$word") ||
+ !strcmp(word, "self") ||
+ !strcmp(word, "this") ||
+ !strcmp(word, "noun1") ||
+ !strcmp(word, "noun2") ||
+ !strcmp(word, "noun3") ||
+ !strcmp(word, "noun4") ||
+ !strcmp(word, "objects") ||
+ validate(word)) {
+ sprintf(error_buffer, ILLEGAL_LABEL, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ }
+
+ if (type == CSTR_TYPE) {
+ if (!strcmp(word, "command_prompt")) {
+ sprintf(error_buffer, USED_LABEL_STR, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ }
+ }
+
+ while (integer_pointer != NULL && type != INT_TYPE) {
+ if (!strcmp(word, integer_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_INT, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ } else
+ integer_pointer = integer_pointer->next_integer;
+ }
+
+
+ while (cinteger_pointer != NULL && type != CINT_TYPE) {
+ if (!strcmp(word, cinteger_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_CINT, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ } else
+ cinteger_pointer = cinteger_pointer->next_cinteger;
+ }
+
+ while (string_pointer != NULL && type != STR_TYPE) {
+ if (!strcmp(word, string_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_STR, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ } else
+ string_pointer = string_pointer->next_string;
+ }
+
+ while (cstring_pointer != NULL && type != CSTR_TYPE) {
+ if (!strcmp(word, cstring_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_CSTR, line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ } else
+ cstring_pointer = cstring_pointer->next_string;
+ }
+
+ /* DON'T CHECK FOR ATT_TYPE AS YOU CAN'T HAVE ATTRIBUTE ARRAYS. */
+ while (attribute_pointer != NULL) {
+ if (!strcmp(word, attribute_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_ATT, line, word);
+ write_text(error_buffer);
+
+ return (TRUE);
+ } else
+ attribute_pointer = attribute_pointer->next_attribute;
+ }
+
+ for (index = 1; index <= objects; index++) {
+ if (!strcmp(word, object[index]->label)) {
+ sprintf(error_buffer, USED_LABEL_OBJ,
+ line, word);
+ log_error(error_buffer, PLUS_STDERR);
+
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+void restart_game() {
+ int index;
+
+ struct integer_type *current_integer;
+ struct integer_type *previous_integer;
+ struct synonym_type *current_synonym;
+ struct synonym_type *previous_synonym;
+ struct name_type *current_name;
+ struct name_type *next_name;
+ struct function_type *current_function;
+ struct function_type *previous_function;
+ struct string_type *current_string;
+ struct string_type *previous_string;
+ struct attribute_type *current_attribute;
+ struct attribute_type *previous_attribute;
+ struct cinteger_type *previous_cinteger;
+ struct filter_type *current_filter;
+ struct filter_type *previous_filter;
+
+#ifdef GLK
+ if (SOUND_SUPPORTED->value) {
+ /* STOP ALL SOUNDS AND SET VOLUMES BACK TO 100% */
+ for (index = 0; index < 4; index++) {
+ g_vm->glk_schannel_stop(sound_channel[index]);
+ g_vm->glk_schannel_set_volume(sound_channel[index], 65535);
+
+ /* STORE A COPY OF THE CURRENT VOLUME FOR ACCESS
+ * FROM JACL CODE */
+ sprintf(temp_buffer, "volume[%d]", index);
+ cinteger_resolve(temp_buffer)->value = 100;
+ }
+ }
+#endif
+
+ /* FREE ALL OBJECTS */
+ for (index = 1; index <= objects; index++) {
+ current_name = object[index]->first_name;
+ while (current_name->next_name != NULL) {
+ next_name = current_name->next_name;
+ free(current_name);
+ current_name = next_name;
+ }
+ free(current_name);
+ free(object[index]);
+ }
+
+ /* FREE ALL VARIABLES */
+
+ if (integer_table != NULL) {
+ if (integer_table->next_integer != NULL) {
+ do {
+ current_integer = integer_table;
+ previous_integer = integer_table;
+ while (current_integer->next_integer != NULL) {
+ previous_integer = current_integer;
+ current_integer = current_integer->next_integer;
+ }
+ free(current_integer);
+ previous_integer->next_integer = NULL;
+ } while (previous_integer != integer_table);
+ }
+
+ free(integer_table);
+ integer_table = NULL;
+ }
+
+ /* FREE ALL FUNCTIONS */
+ if (function_table != NULL) {
+ if (function_table->next_function != NULL) {
+ do {
+ current_function = function_table;
+ previous_function = function_table;
+ while (current_function->next_function != NULL) {
+ previous_function = current_function;
+ current_function = current_function->next_function;
+ }
+ free(current_function);
+ previous_function->next_function = NULL;
+ } while (previous_function != function_table);
+ }
+
+ free(function_table);
+ function_table = NULL;
+ }
+
+ /* FREE ALL FILTERS */
+ if (filter_table != NULL) {
+ if (filter_table->next_filter != NULL) {
+ do {
+ current_filter = filter_table;
+ previous_filter = filter_table;
+ while (current_filter->next_filter != NULL) {
+ previous_filter = current_filter;
+ current_filter = current_filter->next_filter;
+ }
+ free(current_filter);
+ previous_filter->next_filter = NULL;
+ } while (previous_filter != filter_table);
+ }
+
+ free(filter_table);
+ filter_table = NULL;
+ }
+
+ /* FREE ALL STRINGS */
+ if (string_table != NULL) {
+ if (string_table->next_string != NULL) {
+ do {
+ current_string = string_table;
+ previous_string = string_table;
+ while (current_string->next_string != NULL) {
+ previous_string = current_string;
+ current_string = current_string->next_string;
+ }
+ free(current_string);
+ previous_string->next_string = NULL;
+ } while (previous_string != string_table);
+ }
+
+ free(string_table);
+ string_table = NULL;
+ }
+
+ /* FREE ALL ATTRIBUTES */
+ if (attribute_table != NULL) {
+ if (attribute_table->next_attribute != NULL) {
+ do {
+ current_attribute = attribute_table;
+ previous_attribute = attribute_table;
+ while (current_attribute->next_attribute != NULL) {
+ previous_attribute = current_attribute;
+ current_attribute = current_attribute->next_attribute;
+ }
+ free(current_attribute);
+ previous_attribute->next_attribute = NULL;
+ } while (previous_attribute != attribute_table);
+ }
+
+ free(attribute_table);
+ attribute_table = NULL;
+ }
+
+ /* FREE ALL CONSTANTS */
+ if (cinteger_table != NULL) {
+ if (cinteger_table->next_cinteger != NULL) {
+ do {
+ current_cinteger = cinteger_table;
+ previous_cinteger = cinteger_table;
+ while (current_cinteger->next_cinteger != NULL) {
+ previous_cinteger = current_cinteger;
+ current_cinteger = current_cinteger->next_cinteger;
+ }
+ free(current_cinteger);
+ previous_cinteger->next_cinteger = NULL;
+ } while (previous_cinteger != cinteger_table);
+ }
+
+ free(cinteger_table);
+ cinteger_table = NULL;
+ }
+
+ if (cstring_table != NULL) {
+ if (cstring_table->next_string != NULL) {
+ do {
+ current_string = cstring_table;
+ previous_string = cstring_table;
+ while (current_string->next_string != NULL) {
+ previous_string = current_string;
+ current_string = current_string->next_string;
+ }
+ free(current_string);
+ previous_string->next_string = NULL;
+ } while (previous_string != cstring_table);
+ }
+
+ free(cstring_table);
+ cstring_table = NULL;
+ }
+
+ /* FREE ALL SYNONYMS */
+ if (synonym_table != NULL) {
+ if (synonym_table->next_synonym != NULL) {
+ do {
+ current_synonym = synonym_table;
+ previous_synonym = synonym_table;
+ while (current_synonym->next_synonym != NULL) {
+ previous_synonym = current_synonym;
+ current_synonym = current_synonym->next_synonym;
+ }
+ free(current_synonym);
+ previous_synonym->next_synonym = NULL;
+ } while (previous_synonym != synonym_table);
+ }
+ free(synonym_table);
+ synonym_table = NULL;
+ }
+
+ free_from(grammar_table);
+ grammar_table = NULL;
+
+ read_gamefile();
+}
+
+void free_from(struct word_type *x) {
+ if (x) {
+ free_from(x->first_child);
+ free_from(x->next_sibling);
+ free(x);
+ }
+}
+
+void set_defaults() {
+ /* RESET THE BACK-REFERENCE VARIABLES */
+ them[0] = 0;
+ it = 0;
+ her = 0;
+ him = 0;
+}
+
+void create_cinteger(char *name, int value) {
+ struct cinteger_type *new_cinteger = NULL;
+
+ if ((new_cinteger = (struct cinteger_type *)
+ malloc(sizeof(struct cinteger_type))) == NULL) {
+ outofmem();
+ } else {
+ if (cinteger_table == NULL) {
+ cinteger_table = new_cinteger;
+ } else {
+ current_cinteger->next_cinteger = new_cinteger;
+ }
+
+ current_cinteger = new_cinteger;
+ strncpy(current_cinteger->name, name, 40);
+ current_cinteger->name[40] = 0;
+ current_cinteger->value = value;
+ current_cinteger->next_cinteger = NULL;
+ }
+}
+
+void create_integer(char *name, int value) {
+ struct integer_type *new_integer = NULL;
+
+ if ((new_integer = (struct integer_type *)
+ malloc(sizeof(struct integer_type))) == NULL) {
+ outofmem();
+ } else {
+ /* KEEP A COUNT OF HOW MANY INTEGERS ARE DEFINED TO
+ * VALIDATE SAVED GAMES */
+ integers++;
+
+ if (integer_table == NULL) {
+ integer_table = new_integer;
+ } else {
+ current_integer->next_integer = new_integer;
+ }
+ current_integer = new_integer;
+ strncpy(current_integer->name, name, 40);
+ current_integer->name[40] = 0;
+ current_integer->value = value;
+ current_integer->next_integer = NULL;
+ }
+}
+
+void create_string(char *name, char *value) {
+ struct string_type *new_string = NULL;
+
+ if ((new_string = (struct string_type *)
+ malloc(sizeof(struct string_type))) == NULL) {
+ outofmem();
+ } else {
+ /* KEEP A COUNT OF HOW MANY STRINGS ARE DEFINED TO
+ * VALIDATE SAVED GAMES */
+ strings++;
+
+ if (string_table == NULL) {
+ string_table = new_string;
+ } else {
+ current_string->next_string = new_string;
+ }
+ current_string = new_string;
+ strncpy(current_string->name, name, 40);
+ current_string->name[40] = 0;
+
+ if (value != NULL) {
+ strncpy(current_string->value, value, 255);
+ } else {
+ /* IF NO VALUE IS SUPPLIED, JUST NULL-TERMINATE
+ * THE STRING */
+ current_string->value[0] = 0;
+ }
+
+ current_string->value[255] = 0;
+ current_string->next_string = NULL;
+ }
+}
+
+void create_cstring(char *name, char *value) {
+ struct string_type *new_string = NULL;
+
+ if ((new_string = (struct string_type *)
+ malloc(sizeof(struct string_type))) == NULL) {
+ outofmem();
+ } else {
+ if (cstring_table == NULL) {
+ cstring_table = new_string;
+ } else {
+ current_cstring->next_string = new_string;
+ }
+ current_cstring = new_string;
+ strncpy(current_cstring->name, name, 40);
+ current_cstring->name[40] = 0;
+
+ if (value != NULL) {
+ strncpy(current_cstring->value, value, 255);
+ } else {
+ /* IF NO VALUE IS SUPPLIED, JUST NULL-TERMINATE
+ * THE STRING */
+ current_cstring->value[0] = 0;
+ }
+
+ current_cstring->value[255] = 0;
+ current_cstring->next_string = NULL;
+ }
+}
+
+void create_language_constants() {
+ /* SET THE DEFAULT LANGUAGE CONSTANTS IF ANY OR ALL OF THEM
+ * ARE MISSING FROM THE GAME THAT IS BEING LOADED. DEFAULT
+ * TO THE NATIVE_LANGUAGE SETTING IN language.h */
+
+ if (cstring_resolve("COMMENT_IGNORED") == NULL)
+ create_cstring("COMMENT_IGNORED", COMMENT_IGNORED);
+ if (cstring_resolve("COMMENT_RECORDED") == NULL)
+ create_cstring("COMMENT_RECORDED", COMMENT_RECORDED);
+ if (cstring_resolve("YES_WORD") == NULL)
+ create_cstring("YES_WORD", YES_WORD);
+ if (cstring_resolve("NO_WORD") == NULL)
+ create_cstring("NO_WORD", NO_WORD);
+ if (cstring_resolve("YES_OR_NO") == NULL)
+ create_cstring("YES_OR_NO", YES_OR_NO);
+ if (cstring_resolve("INVALID_SELECTION") == NULL)
+ create_cstring("INVALID_SELECTION", INVALID_SELECTION);
+ if (cstring_resolve("RESTARTING") == NULL)
+ create_cstring("RESTARTING", RESTARTING);
+ if (cstring_resolve("RETURN_GAME") == NULL)
+ create_cstring("RETURN_GAME", RETURN_GAME);
+ if (cstring_resolve("SCRIPTING_ON") == NULL)
+ create_cstring("SCRIPTING_ON", SCRIPTING_ON);
+ if (cstring_resolve("SCRIPTING_OFF") == NULL)
+ create_cstring("SCRIPTING_OFF", SCRIPTING_OFF);
+ if (cstring_resolve("SCRIPTING_ALREADY_OFF") == NULL)
+ create_cstring("SCRIPTING_ALREADY_OFF", SCRIPTING_ALREADY_OFF);
+ if (cstring_resolve("SCRIPTING_ALREADY_ON") == NULL)
+ create_cstring("SCRIPTING_ALREADY_OFF", SCRIPTING_ALREADY_OFF);
+ if (cstring_resolve("CANT_WRITE_SCRIPT") == NULL)
+ create_cstring("CANT_WRITE_SCRIPT", CANT_WRITE_SCRIPT);
+ if (cstring_resolve("ERROR_READING_WALKTHRU") == NULL)
+ create_cstring("ERROR_READING_WALKTHRU", ERROR_READING_WALKTHRU);
+ if (cstring_resolve("BAD_OOPS") == NULL)
+ create_cstring("BAD_OOPS", BAD_OOPS);
+ if (cstring_resolve("CANT_CORRECT") == NULL)
+ create_cstring("CANT_CORRECT", CANT_CORRECT);
+ if (cstring_resolve("SURE_QUIT") == NULL)
+ create_cstring("SURE_QUIT", SURE_QUIT);
+ if (cstring_resolve("SURE_RESTART") == NULL)
+ create_cstring("SURE_RESTART", SURE_RESTART);
+ if (cstring_resolve("NOT_CLEVER") == NULL)
+ create_cstring("NOT_CLEVER", NOT_CLEVER);
+ if (cstring_resolve("NO_MOVES") == NULL)
+ create_cstring("NO_MOVES", NO_MOVES);
+ if (cstring_resolve("TYPE_NUMBER") == NULL)
+ create_cstring("TYPE_NUMBER", TYPE_NUMBER);
+ if (cstring_resolve("BY") == NULL)
+ create_cstring("BY", BY);
+ if (cstring_resolve("REFERRING_TO") == NULL)
+ create_cstring("REFERRING_TO", REFERRING_TO);
+ if (cstring_resolve("WALKTHRU_WORD") == NULL)
+ create_cstring("WALKTHRU_WORD", WALKTHRU_WORD);
+ if (cstring_resolve("INFO_WORD") == NULL)
+ create_cstring("INFO_WORD", INFO_WORD);
+ if (cstring_resolve("RESTART_WORD") == NULL)
+ create_cstring("RESTART_WORD", RESTART_WORD);
+ if (cstring_resolve("AGAIN_WORD") == NULL)
+ create_cstring("AGAIN_WORD", AGAIN_WORD);
+ if (cstring_resolve("SCRIPT_WORD") == NULL)
+ create_cstring("SCRIPT_WORD", SCRIPT_WORD);
+ if (cstring_resolve("UNSCRIPT_WORD") == NULL)
+ create_cstring("UNSCRIPT_WORD", UNSCRIPT_WORD);
+ if (cstring_resolve("QUIT_WORD") == NULL)
+ create_cstring("QUIT_WORD", QUIT_WORD);
+ if (cstring_resolve("UNDO_WORD") == NULL)
+ create_cstring("UNDO_WORD", UNDO_WORD);
+ if (cstring_resolve("OOPS_WORD") == NULL)
+ create_cstring("OOPS_WORD", OOPS_WORD);
+ if (cstring_resolve("FROM_WORD") == NULL)
+ create_cstring("FROM_WORD", FROM_WORD);
+ if (cstring_resolve("EXCEPT_WORD") == NULL)
+ create_cstring("EXCEPT_WORD", EXCEPT_WORD);
+ if (cstring_resolve("FOR_WORD") == NULL)
+ create_cstring("FOR_WORD", FOR_WORD);
+ if (cstring_resolve("BUT_WORD") == NULL)
+ create_cstring("BUT_WORD", BUT_WORD);
+ if (cstring_resolve("AND_WORD") == NULL)
+ create_cstring("AND_WORD", AND_WORD);
+ if (cstring_resolve("THEN_WORD") == NULL)
+ create_cstring("THEN_WORD", THEN_WORD);
+ if (cstring_resolve("OF_WORD") == NULL)
+ create_cstring("OF_WORD", OF_WORD);
+ if (cstring_resolve("SHE_WORD") == NULL)
+ create_cstring("SHE_WORD", SHE_WORD);
+ if (cstring_resolve("HE_WORD") == NULL)
+ create_cstring("HE_WORD", HE_WORD);
+ if (cstring_resolve("THAT_WORD") == NULL)
+ create_cstring("THAT_WORD", THAT_WORD);
+ if (cstring_resolve("THEM_WORD") == NULL)
+ create_cstring("THEM_WORD", THEM_WORD);
+ if (cstring_resolve("THOSE_WORD") == NULL)
+ create_cstring("THOSE_WORD", THOSE_WORD);
+ if (cstring_resolve("THEY_WORD") == NULL)
+ create_cstring("THEY_WORD", THEY_WORD);
+ if (cstring_resolve("IT_WORD") == NULL)
+ create_cstring("IT_WORD", IT_WORD);
+ if (cstring_resolve("ITSELF_WORD") == NULL)
+ create_cstring("ITSELF_WORD", ITSELF_WORD);
+ if (cstring_resolve("HIM_WORD") == NULL)
+ create_cstring("HIM_WORD", HIM_WORD);
+ if (cstring_resolve("HIMSELF_WORD") == NULL)
+ create_cstring("HIMSELF_WORD", HIMSELF_WORD);
+ if (cstring_resolve("HER_WORD") == NULL)
+ create_cstring("HER_WORD", HER_WORD);
+ if (cstring_resolve("HERSELF_WORD") == NULL)
+ create_cstring("HERSELF_WORD", HERSELF_WORD);
+ if (cstring_resolve("THEMSELVES_WORD") == NULL)
+ create_cstring("THEMSELVES_WORD", THEMSELVES_WORD);
+ if (cstring_resolve("YOU_WORD") == NULL)
+ create_cstring("YOU_WORD", YOU_WORD);
+ if (cstring_resolve("YOURSELF_WORD") == NULL)
+ create_cstring("YOURSELF_WORD", YOURSELF_WORD);
+ if (cstring_resolve("ONES_WORD") == NULL)
Commit: 66468fa2fe18daff4d8dc664886b5e23f9436672
https://github.com/scummvm/scummvm/commit/66468fa2fe18daff4d8dc664886b5e23f9436672
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: gcc compilation fixes
Changed paths:
engines/glk/jacl/csv.h
engines/glk/jacl/display.cpp
engines/glk/jacl/encapsulate.cpp
engines/glk/jacl/errors.cpp
engines/glk/jacl/interpreter.cpp
engines/glk/jacl/jacl.cpp
engines/glk/jacl/jacl_main.cpp
engines/glk/jacl/jpp.cpp
engines/glk/jacl/libcsv.cpp
engines/glk/jacl/loader.cpp
engines/glk/jacl/logging.cpp
engines/glk/jacl/parser.cpp
engines/glk/jacl/prototypes.h
engines/glk/jacl/resolvers.cpp
engines/glk/jacl/types.h
engines/glk/jacl/utils.cpp
diff --git a/engines/glk/jacl/csv.h b/engines/glk/jacl/csv.h
index f979f00..80fe402 100644
--- a/engines/glk/jacl/csv.h
+++ b/engines/glk/jacl/csv.h
@@ -81,7 +81,7 @@ int csv_init(struct csv_parser *p, unsigned char options);
int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
void csv_free(struct csv_parser *p);
int csv_error(struct csv_parser *p);
-char *csv_strerror(int error);
+const char *csv_strerror(int error);
size_t csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size);
int csv_fwrite(Common::WriteStream *fp, const void *src, size_t src_size);
diff --git a/engines/glk/jacl/display.cpp b/engines/glk/jacl/display.cpp
index db59efb..2562401 100644
--- a/engines/glk/jacl/display.cpp
+++ b/engines/glk/jacl/display.cpp
@@ -34,7 +34,7 @@ extern char function_name[];
extern struct object_type *object[];
extern struct variable_type *variable[];
-extern char *word[];
+extern const char *word[];
extern int player;
extern int wp;
diff --git a/engines/glk/jacl/encapsulate.cpp b/engines/glk/jacl/encapsulate.cpp
index 8e65ba3..8daba29 100644
--- a/engines/glk/jacl/encapsulate.cpp
+++ b/engines/glk/jacl/encapsulate.cpp
@@ -34,9 +34,9 @@ char text_buffer[1024];
/* THIS IS A STRING CONSTANT TO POINT TO WHENEVER A COMMA IS
* USED IN THE PLAYER'S INPUT */
-char *comma = "comma\0";
-char *then = "then\0";
-char *word[MAX_WORDS];
+const char *comma = "comma\0";
+const char *then = "then\0";
+const char *word[MAX_WORDS];
int quoted[MAX_WORDS];
int percented[MAX_WORDS];
int wp;
diff --git a/engines/glk/jacl/errors.cpp b/engines/glk/jacl/errors.cpp
index fc791ad..4956a1d 100644
--- a/engines/glk/jacl/errors.cpp
+++ b/engines/glk/jacl/errors.cpp
@@ -29,7 +29,7 @@ namespace Glk {
namespace JACL {
extern struct function_type *executing_function;
-extern char *word[];
+extern const char *word[];
extern char error_buffer[];
@@ -44,7 +44,7 @@ void notintrun() {
log_error(error_buffer, PLUS_STDERR);
}
-void unkfunrun(char *name) {
+void unkfunrun(const char *name) {
sprintf(error_buffer, UNKNOWN_FUNCTION_RUN, name);
log_error(error_buffer, PLUS_STDOUT);
}
@@ -130,22 +130,22 @@ void badplrrun(int value) {
log_error(error_buffer, PLUS_STDOUT);
}
-void badptrrun(char *name, int value) {
+void badptrrun(const char *name, int value) {
sprintf(error_buffer, BAD_POINTER, executing_function->name, name, value);
log_error(error_buffer, PLUS_STDOUT);
}
-void unkvarrun(char *variable) {
+void unkvarrun(const char *variable) {
sprintf(error_buffer, UNDEFINED_CONTAINER_RUN, executing_function->name, arg_text_of(variable));
log_error(error_buffer, PLUS_STDOUT);
}
-void unkstrrun(char *variable) {
+void unkstrrun(const char *variable) {
sprintf(error_buffer, UNDEFINED_STRING_RUN, executing_function->name, variable);
log_error(error_buffer, PLUS_STDOUT);
}
-void unkscorun(char *scope) {
+void unkscorun(const char *scope) {
sprintf(error_buffer, UNKNOWN_SCOPE_RUN, executing_function->name, scope);
log_error(error_buffer, PLUS_STDOUT);
}
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
index 47c07c8..94fa45f 100644
--- a/engines/glk/jacl/interpreter.cpp
+++ b/engines/glk/jacl/interpreter.cpp
@@ -30,7 +30,6 @@
namespace Glk {
namespace JACL {
-#ifdef WIN32
struct flock {
short l_type;
short l_whence;
@@ -55,10 +54,9 @@ struct flock {
int fcntl(int __fd, int __cmd, ...) {
return 0;
}
-#endif /* WIN32 */
#ifndef strcasestr
-char *strcasestr(const char *s, const char *find) {
+const char *strcasestr(const char *s, const char *find) {
char c, sc;
size_t len;
@@ -73,28 +71,28 @@ char *strcasestr(const char *s, const char *find) {
} while (scumm_strnicmp(s, find, len) != 0);
s--;
}
- return ((char *)s);
+ return s;
}
#endif
#define MAX_TRY 10
-struct flock read_lck;
+flock read_lck;
int read_fd;
-struct flock write_lck;
+flock write_lck;
int write_fd;
char *url_encode(char *str);
char to_hex(char code);
-char *location_attributes[] = {
+const char *location_attributes[] = {
"VISITED ", "DARK ", "ON_WATER ", "UNDER_WATER ", "WITHOUT_AIR ", "OUTDOORS ",
"MID_AIR ", "TIGHT_ROPE ", "POLLUTED ", "SOLVED ", "MID_WATER ", "DARKNESS ",
"MAPPED ", "KNOWN ",
NULL
};
-char *object_attributes[] = {
+const char *object_attributes[] = {
"CLOSED ", "LOCKED ", "DEAD ", "IGNITABLE ", "WORN ", "CONCEALING ",
"LUMINOUS ", "WEARABLE ", "CLOSABLE ", "LOCKABLE ", "ANIMATE ", "LIQUID ",
"CONTAINER ", "SURFACE ", "PLURAL ", "FLAMMABLE ", "BURNING ", "LOCATION ",
@@ -103,13 +101,13 @@ char *object_attributes[] = {
"NOT_IMPORTANT ", NULL
};
-char *object_elements[] = {
+const char *object_elements[] = {
"parent", "capacity", "mass", "bearing", "velocity", "next", "previous",
"child", "index", "status", "state", "counter", "points", "class", "x", "y",
NULL
};
-char *location_elements[] = {
+const char *location_elements[] = {
"north", "south", "east", "west", "northeast", "northwest", "southeast",
"southwest", "up", "down", "in", "out", "points", "class", "x", "y",
NULL
@@ -211,13 +209,13 @@ extern char user_id[];
extern char prefix[];
extern char text_buffer[];
extern char chunk_buffer[];
-extern char *word[];
+extern const char *word[];
extern char bookmark[];
extern char file_prompt[];
/* CONTAINED IN PARSER.C */
-extern int object_list[4][MAX_WORDS];
+extern int object_list[4][MAX_OBJECTS];
extern int list_size[];
extern int max_size[];
@@ -244,7 +242,7 @@ extern char error_buffer[];
extern char proxy_buffer[];
extern char default_function[];
-extern char override[];
+extern char override_[];
extern int noun[];
extern int wp;
@@ -268,7 +266,7 @@ extern char margin_string[];
char integer_buffer[16];
char called_name[1024];
char scope_criterion[24];
-char *output;
+const char *output;
void terminate(int code) {
// FREE ANY EXTRA RAM ALLOCATED BY THE CSV PARSER
@@ -325,7 +323,7 @@ void build_proxy() {
void cb1(void *s, size_t i, void *not_used) {
struct string_type *resolved_cstring;
- //sprintf (temp_buffer, "Trying to set field %d to equal %s^", field_no, (char *) s);
+ //sprintf (temp_buffer, "Trying to set field %d to equal %s^", field_no, (const char *) s);
//write_text(temp_buffer);
sprintf(temp_buffer, "field[%d]", field_no);
@@ -336,7 +334,7 @@ void cb1(void *s, size_t i, void *not_used) {
//write_text("^");
strncpy(resolved_cstring->value, (const char *)s, i);
resolved_cstring->value[i] = 0;
- //sprintf(temp_buffer, "Setting field %d to ~%s~^", field_no, (char *) s);
+ //sprintf(temp_buffer, "Setting field %d to ~%s~^", field_no, (const char *) s);
//write_text(temp_buffer);
// INCREMENT THE FIELD NUMBER SO THE NEXT ONE GETS STORED IN THE RIGHT CONSTANT
field_no++;
@@ -357,7 +355,7 @@ void cb2(int c, void *not_used) {
}
}
-int execute(char *funcname) {
+int execute(const char *funcname) {
int index;
int counter;
int *container;
@@ -373,7 +371,6 @@ int execute(char *funcname) {
/* THESE ARE USED AS FILE POINTER OFFSETS TO RETURN TO FIXED
* POINTS IN THE GAME FILE */
#ifdef GLK
- int result;
int before_command = 0;
#else
long before_command = 0;
@@ -421,7 +418,7 @@ int execute(char *funcname) {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, executing_function->position, seekmode_Start);
before_command = executing_function->position;
- result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ //result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fseek(file, executing_function->position, SEEK_SET);
before_command = executing_function->position;
@@ -602,7 +599,7 @@ int execute(char *funcname) {
}
if (infile == NULL) {
- sprintf(error_buffer, "Failed to open file %s: %s\n", temp_buffer, strerror(errno));
+ sprintf(error_buffer, "Failed to open file %s\n", temp_buffer);
log_error(error_buffer, LOG_ONLY);
infile = NULL;
} else {
@@ -684,7 +681,7 @@ int execute(char *funcname) {
}
if (infile == NULL) {
- sprintf(error_buffer, "Failed to open input CSV file ~%s~: %s\n", in_name, strerror(errno));
+ sprintf(error_buffer, "Failed to open input CSV file ~%s\n", in_name);
log_error(error_buffer, LOG_ONLY);
if (outfile != NULL) {
delete outfile;
@@ -693,7 +690,7 @@ int execute(char *funcname) {
return (exit_function(TRUE));
} else {
if (outfile == NULL) {
- sprintf(error_buffer, "Failed to open output CSV file ~%s~: %s\n", out_name, strerror(errno));
+ sprintf(error_buffer, "Failed to open output CSV file ~%s~\n", out_name);
log_error(error_buffer, LOG_ONLY);
if (infile != NULL) {
delete infile;
@@ -1608,7 +1605,7 @@ int execute(char *funcname) {
* TO EXECUTE IN PLACE OF ANY CODE THAT FOLLOWS THIS LINE.
* THIS COMMAND IS USED EXCLUSIVELY IN GLOBAL FUNCTIONS
* ASSOCIATED WITH GRAMMAR LINES */
- if (execute(override) == TRUE) {
+ if (execute(override_) == TRUE) {
return (exit_function(TRUE));
} else {
if (execute(default_function) == TRUE) {
@@ -2198,7 +2195,7 @@ int execute(char *funcname) {
outfile = File::openForWriting(temp_buffer);
if (outfile == NULL) {
- sprintf(error_buffer, "Failed to open file %s: %s\n", temp_buffer, strerror(errno));
+ sprintf(error_buffer, "Failed to open file %s\n", temp_buffer);
log_error(error_buffer, PLUS_STDOUT);
} else {
for (counter = 2; word[counter] != NULL && counter < MAX_WORDS; counter++) {
@@ -2546,7 +2543,7 @@ int bearing(double x1, double y1, double x2, double y2) {
return ((int) bearing);
}
-void set_arguments(char *function_call) {
+void set_arguments(const char *function_call) {
/* THIS FUNCTION CREATES AN ARRAY OF JACL INTEGER CONSTANTS TO
REPRESENT THE ARGUMENTS PASSED TO A JACL FUNCTION */
int index,
@@ -2670,7 +2667,7 @@ void pop_stack() {
/* RESTORE THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
* 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
- strncpy(override, backup[stack].override, 80);
+ strncpy(override_, backup[stack]._override, 80);
strncpy(default_function, backup[stack].default_function, 80);
/* RESTORE ALL THE WORD POINTERS */
@@ -2753,7 +2750,7 @@ void push_stack(int32 file_pointer) {
/* COPY THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
* 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
- strncpy(backup[stack].override, override, 80);
+ strncpy(backup[stack]._override, override_, 80);
strncpy(backup[stack].default_function, default_function, 80);
/* PUSH ALL THE WORD POINTERS ONTO THE STACK */
@@ -3091,8 +3088,8 @@ int and_strcondition() {
}
int str_test(int first) {
- char *index;
- char *compare;
+ const char *index;
+ const char *compare;
// GET THE TWO STRING VALUES TO COMPARE
@@ -3150,7 +3147,7 @@ int str_test(int first) {
}
}
-void add_cinteger(char *name, int value) {
+void add_cinteger(const char *name, int value) {
/* THIS FUNCTION ADDS A NEW JACL CONSTANT TO THE LIST */
if ((new_cinteger = (struct cinteger_type *)
@@ -3174,7 +3171,7 @@ void add_cinteger(char *name, int value) {
}
}
-void clear_cinteger(char *name) {
+void clear_cinteger(const char *name) {
/* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
//printf("--- clear integer %s\n", name);
@@ -3208,7 +3205,7 @@ void clear_cinteger(char *name) {
//printf("--- leaving clear integer\n");
}
-void add_cstring(char *name, char *value) {
+void add_cstring(const char *name, const char *value) {
/* ADD A STRING CONSTANT WITH THE SUPPLIED NAME AND VALUE */
if ((new_string = (struct string_type *)
@@ -3233,7 +3230,7 @@ void add_cstring(char *name, char *value) {
}
}
-void clear_cstring(char *name) {
+void clear_cstring(const char *name) {
/* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
if (cstring_table != NULL) {
current_cstring = cstring_table;
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
index c967a88..c053033 100644
--- a/engines/glk/jacl/jacl.cpp
+++ b/engines/glk/jacl/jacl.cpp
@@ -27,6 +27,8 @@ namespace Glk {
namespace JACL {
JACL *g_vm;
+extern strid_t game_stream;
+extern void glk_main();
JACL::JACL(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
_saveSlot(-1) {
@@ -37,6 +39,10 @@ void JACL::runGame() {
// Check for savegame
_saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+ // Open up the game file as a stream, and play the game
+ game_stream = _streams->openStream(&_gameFile);
+ glk_main();
+ glk_stream_close(game_stream);
}
bool JACL::initialize() {
diff --git a/engines/glk/jacl/jacl_main.cpp b/engines/glk/jacl/jacl_main.cpp
index 6b77f85..00fa706 100644
--- a/engines/glk/jacl/jacl_main.cpp
+++ b/engines/glk/jacl/jacl_main.cpp
@@ -43,7 +43,7 @@ event_t *cancelled_event;
extern struct csv_parser parser_csv;
extern char text_buffer[];
-extern char *word[];
+extern const char *word[];
extern short int quoted[];
extern short int punctuated[];
extern int wp;
@@ -75,7 +75,7 @@ char walkthru[81] = "\0";
char function_name[81];
extern char default_function[84];
-char override[81];
+char override_[81];
char temp_buffer[1024];
char error_buffer[1024];
@@ -88,8 +88,8 @@ char proxy_buffer[1024];
char oops_buffer[1024];
char oopsed_current[1024];
char last_command[1024];
-char *blank_command = "blankjacl\0";
-char *current_command = (char *) NULL;
+const char *blank_command = "blankjacl\0";
+const char *current_command = (const char *)NULL;
char command_buffer[1024];
#ifndef NOUNICODE
glui32 command_buffer_uni[1024];
@@ -174,9 +174,8 @@ static void version_info();
void glk_main() {
int index;
- frefid_t blorb_file;
- override[0] = 0;
+ override_[0] = 0;
/* ALLOC AN EVENT TO STORE A CANCELLED EVENT IN */
if ((cancelled_event = (event_t *) malloc(sizeof(event_t))) == NULL)
@@ -217,26 +216,6 @@ void glk_main() {
terminate(200);
}
- /* OPEN THE BLORB FILE IF ONE EXISTS */
-#ifndef WINGLK
- blorb_file = g_vm->glk_fileref_create_by_name(fileusage_BinaryMode, blorb, 0);
-#else
- strcpy(temp_buffer, game_path);
- strcat(temp_buffer, blorb);
- strcpy(blorb, temp_buffer);
- blorb_file = wing_vm->glk_fileref_create_by_name(fileusage_BinaryMode, blorb, 0, 0);
-#endif
-
-#ifdef UNUSED
- if (blorb_file != NULL && g_vm->glk_fileref_does_file_exist(blorb_file)) {
- blorb_stream = g_vm->glk_stream_open_file(blorb_file, filemode_Read, 0);
-
- if (blorb_stream != NULL) {
- /* IF THE FILE EXISTS, SET THE RESOURCE MAP */
- giblorb_set_resource_map(blorb_stream);
- }
- }
-#endif
// INTIALISE THE CSV PARSER
csv_init(&parser_csv, CSV_APPEND_NULL);
@@ -363,6 +342,9 @@ void glk_main() {
* STATUS WINDOW. */
status_line();
break;
+
+ default:
+ break;
}
}
@@ -534,7 +516,7 @@ void word_check() {
command_encapsulate();
//printf("--- trying to replace %s with %s\n", word[oops_word], oops_buffer);
jacl_truncate();
- word[oops_word] = (char *) &oops_buffer;
+ word[oops_word] = (char *)&oops_buffer;
/* BUILD A PLAIN STRING REPRESENTING THE NEW COMMAND */
oopsed_current[0] = 0;
@@ -667,7 +649,7 @@ void save_game_state() {
noun3_backup = noun[3];
}
-int save_interaction(char *filename) {
+int save_interaction(const char *filename) {
frefid_t saveref;
jacl_set_window(inputwin);
@@ -742,7 +724,7 @@ void restore_game_state() {
TIME->value = FALSE;
}
-void write_text(char *string_buffer) {
+void write_text(const char *string_buffer) {
int index,
length;
@@ -840,9 +822,7 @@ void newline() {
write_text("\n");
}
-void more(char *message) {
- int character;
-
+void more(const char *message) {
jacl_set_window(inputwin);
if (inputwin == promptwin) {
@@ -854,7 +834,7 @@ void more(char *message) {
write_text(message);
g_vm->glk_set_style(style_Normal);
- character = get_key();
+ (void)get_key();
if (inputwin == mainwin) newline();
}
@@ -864,8 +844,7 @@ int get_key() {
g_vm->glk_request_char_event(inputwin);
- while (1) {
-
+ while (!g_vm->shouldQuit()) {
g_vm->glk_select(&ev);
switch (ev.type) {
@@ -874,9 +853,13 @@ int get_key() {
return (ev.val1);
}
break;
+
+ default:
+ break;
}
}
+ return 0;
}
int get_number(int insist, int low, int high) {
@@ -904,8 +887,7 @@ int get_number(int insist, int low, int high) {
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
gotline = FALSE;
- while (!gotline) {
-
+ while (!gotline && g_vm->shouldQuit()) {
g_vm->glk_select(&ev);
switch (ev.type) {
@@ -918,6 +900,9 @@ int get_number(int insist, int low, int high) {
case evtype_Arrange:
status_line();
break;
+
+ default:
+ break;
}
}
@@ -959,8 +944,7 @@ void get_string(char *string_buffer) {
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
gotline = FALSE;
- while (!gotline) {
-
+ while (!gotline && !g_vm->shouldQuit()) {
g_vm->glk_select(&ev);
switch (ev.type) {
@@ -973,6 +957,9 @@ void get_string(char *string_buffer) {
case evtype_Arrange:
status_line();
break;
+
+ default:
+ break;
}
}
@@ -1005,7 +992,7 @@ int get_yes_or_no() {
g_vm->glk_request_line_event(inputwin, commandbuf, 255, 0);
gotline = FALSE;
- while (!gotline) {
+ while (!gotline && !g_vm->shouldQuit()) {
g_vm->glk_select(&ev);
@@ -1019,6 +1006,9 @@ int get_yes_or_no() {
case evtype_Arrange:
status_line();
break;
+
+ default:
+ break;
}
}
@@ -1038,7 +1028,7 @@ int get_yes_or_no() {
}
}
-char get_character(char *message) {
+char get_character(const char *message) {
char *cx;
char commandbuf[256];
int gotline;
@@ -1048,7 +1038,7 @@ char get_character(char *message) {
/* THIS LOOP IS IDENTICAL TO THE MAIN COMMAND LOOP IN g_vm->glk_main(). */
- while (1) {
+ while (!g_vm->shouldQuit()) {
if (inputwin == promptwin) {
g_vm->glk_window_clear(promptwin);
jacl_set_window(inputwin);
@@ -1059,7 +1049,7 @@ char get_character(char *message) {
jacl_set_window(mainwin);
gotline = FALSE;
- while (!gotline) {
+ while (!gotline && !g_vm->shouldQuit()) {
g_vm->glk_select(&ev);
@@ -1073,6 +1063,9 @@ char get_character(char *message) {
case evtype_Arrange:
status_line();
break;
+
+ default:
+ break;
}
}
@@ -1081,6 +1074,9 @@ char get_character(char *message) {
return (*cx);
}
+
+
+ return '\0';
}
strid_t open_glk_file(uint usage, uint mode, char *filename) {
@@ -1239,7 +1235,7 @@ void walking_thru() {
walkthru_running = FALSE;
}
-int restore_interaction(char *filename) {
+int restore_interaction(const char *filename) {
frefid_t saveref;
jacl_set_window(inputwin);
@@ -1297,11 +1293,11 @@ void jacl_set_window(winid_t new_window) {
}
#ifdef READLINE
-char **command_completion(char *text, int start, int end) {
+char **command_completion(const char *text, int start, int end) {
/* READLINE TAB COMPLETION CODE */
char **options;
- options = (char **) NULL;
+ options = (const char **) NULL;
if (start == 0)
options = completion_matches(text, verb_generator);
@@ -1312,7 +1308,7 @@ char **command_completion(char *text, int start, int end) {
}
#endif
-char *object_generator(char *text, int state) {
+const char *object_generator(const char *text, int state) {
static int len;
static struct command_type *now;
struct command_type *to_send;
@@ -1348,15 +1344,15 @@ char *object_generator(char *text, int state) {
if (!strncmp(text, now->word, len)) {
to_send = now;
now = now->next;
- return ((char *) to_send->word);
+ return ((const char *)to_send->word);
}
now = now->next;
}
- return (char *) NULL;
+ return (const char *)NULL;
}
-char *verb_generator(char *text, int state) {
+const char *verb_generator(const char *text, int state) {
static int len;
static struct command_type *now;
struct command_type *to_send;
@@ -1388,17 +1384,17 @@ char *verb_generator(char *text, int state) {
now = now->next;
/* MALLOC A COPY AND RETURN A POINTER TO THE COPY */
- return ((char *) to_send->word);
+ return ((const char *)to_send->word);
}
now = now->next;
}
- return (char *) NULL;
+ return (const char *)NULL;
}
/* ADD A COPY OF STRING TO A LIST OF STRINGS IF IT IS NOT
ALREADY IN THE LIST. THIS IS FOR THE USE OF READLINE */
-void add_word(char *newWord) {
+void add_word(const char *newWord) {
static struct command_type *current_word = NULL;
struct command_type *previous_word = NULL;
diff --git a/engines/glk/jacl/jpp.cpp b/engines/glk/jacl/jpp.cpp
index f036b75..a8db6a0 100644
--- a/engines/glk/jacl/jpp.cpp
+++ b/engines/glk/jacl/jpp.cpp
@@ -28,7 +28,7 @@ namespace JACL {
extern char text_buffer[];
extern char temp_buffer[];
-extern char *word[];
+extern const char *word[];
extern short int quoted[];
extern short int punctuated[];
extern int wp;
@@ -126,7 +126,7 @@ int jpp() {
}
}
- if (process_file(game_file, (char *) NULL) == FALSE) {
+ if (process_file(game_file, (const char *) NULL) == FALSE) {
return (FALSE);
}
@@ -139,7 +139,7 @@ int jpp() {
return (TRUE);
}
-int process_file(char *sourceFile1, char *sourceFile2) {
+int process_file(const char *sourceFile1, char *sourceFile2) {
char temp_buffer1[1025];
char temp_buffer2[1025];
Common::File *srcFile = NULL;
diff --git a/engines/glk/jacl/libcsv.cpp b/engines/glk/jacl/libcsv.cpp
index 408e60b..ccb90b8 100644
--- a/engines/glk/jacl/libcsv.cpp
+++ b/engines/glk/jacl/libcsv.cpp
@@ -28,13 +28,15 @@ namespace JACL {
#define VERSION "3.0.0"
-//#define SIZE_MAX ((size_t)-1)
+//#define MAX_INT ((size_t)-1)
#define ROW_NOT_BEGUN 0
#define FIELD_NOT_BEGUN 1
#define FIELD_BEGUN 2
#define FIELD_MIGHT_HAVE_ENDED 3
+#define MAX_INT 0x7fff
+
/*
Explanation of states
ROW_NOT_BEGUN There have not been any fields encountered for this row
@@ -69,7 +71,7 @@ namespace JACL {
#define SUBMIT_CHAR(p, c) ((p)->entry_buf[entry_pos++] = (c))
-static char *csv_errors[] = {"success",
+static const char *csv_errors[] = {"success",
"error parsing data while strict checking enabled",
"memory exhausted while increasing buffer size",
"data size too large",
@@ -81,7 +83,7 @@ int csv_error(struct csv_parser *p) {
return p->status;
}
-char *csv_strerror(int status) {
+const char *csv_strerror(int status) {
/* Return a textual description of status */
if (status >= CSV_EINVALID || status < 0)
return csv_errors[CSV_EINVALID];
@@ -179,6 +181,7 @@ int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*c
/* Reset parser */
p->spaces = p->quoted = p->entry_pos = p->status = 0;
p->pstate = ROW_NOT_BEGUN;
+ (void)pstate;
return 0;
}
@@ -237,16 +240,16 @@ size_t csv_get_buffer_size(struct csv_parser *p) {
static int csv_increase_buffer(struct csv_parser *p) {
/* Increase the size of the entry buffer. Attempt to increase size by
- * p->blk_size, if this is larger than SIZE_MAX try to increase current
- * buffer size to SIZE_MAX. If allocation fails, try to allocate halve
+ * p->blk_size, if this is larger than MAX_INT try to increase current
+ * buffer size to MAX_INT. If allocation fails, try to allocate halve
* the size and try again until successful or increment size is zero.
*/
size_t to_add = p->blk_size;
void *vp;
- if (p->entry_size >= SIZE_MAX - to_add)
- to_add = SIZE_MAX - p->entry_size;
+ if (p->entry_size >= MAX_INT - to_add)
+ to_add = MAX_INT - p->entry_size;
if (!to_add) {
p->status = CSV_ETOOBIG;
@@ -432,18 +435,18 @@ size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size)
if (*csrc == '"') {
if (dest_size > chars)
*cdest++ = '"';
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
}
if (dest_size > chars)
*cdest++ = *csrc;
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
src_size--;
csrc++;
}
if (dest_size > chars)
*cdest = '"';
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
return chars;
}
@@ -488,18 +491,18 @@ size_t csv_write2(void *dest, size_t dest_size, const void *src, size_t src_size
if (*csrc == quote) {
if (dest_size > chars)
*cdest++ = quote;
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
}
if (dest_size > chars)
*cdest++ = *csrc;
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
src_size--;
csrc++;
}
if (dest_size > chars)
*cdest = quote;
- if (chars < SIZE_MAX) chars++;
+ if (chars < MAX_INT) chars++;
return chars;
}
diff --git a/engines/glk/jacl/loader.cpp b/engines/glk/jacl/loader.cpp
index 345aa18..d4da488 100644
--- a/engines/glk/jacl/loader.cpp
+++ b/engines/glk/jacl/loader.cpp
@@ -37,7 +37,7 @@ extern char text_buffer[];
extern char temp_buffer[];
extern char prefix[];
extern char error_buffer[];
-extern char *word[];
+extern const char *word[];
extern int quoted[];
extern int punctuated[];
extern int wp;
@@ -109,23 +109,17 @@ void read_gamefile() {
int self_parent = 0;
long start_of_file = 0;
-#ifdef GLK
- glui32 current_file_position;
-#else
- long current_file_position;
-#endif
-
long bit_mask;
- struct filter_type *current_filter = NULL;
- struct filter_type *new_filter = NULL;
- struct attribute_type *current_attribute = NULL;
- struct attribute_type *new_attribute = NULL;
- struct cinteger_type *resolved_cinteger = NULL;
- struct synonym_type *current_synonym = NULL;
- struct synonym_type *new_synonym = NULL;
- struct function_type *current_function = NULL;
- struct name_type *current_name = NULL;
+ filter_type *current_filter = NULL;
+ filter_type *new_filter = NULL;
+ attribute_type *current_attribute = NULL;
+ attribute_type *new_attribute = NULL;
+ cinteger_type *resolved_cinteger = NULL;
+ synonym_type *current_synonym = NULL;
+ synonym_type *new_synonym = NULL;
+ function_type *current_function = NULL;
+ name_type *current_name = NULL;
char function_name[81];
@@ -750,7 +744,7 @@ void read_gamefile() {
function_name[80] = 0;
self_parent = 0;
} else if (word[wp][0] == '*') {
- char *last_underscore = (char *) NULL;
+ const char *last_underscore = (char *)NULL;
/* ALLOW MANUAL NAMING OF ASSOCIATED FUNCTIONS */
/* TO GIVE CLASS-LIKE BEHAVIOR */
@@ -1063,10 +1057,8 @@ void read_gamefile() {
}
#ifdef GLK
- current_file_position = g_vm->glk_stream_get_position(game_stream);
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
- current_file_position = ftell(file);
fgets(text_buffer, 1024, file);
#endif
line++;
@@ -1138,7 +1130,7 @@ void build_grammar_table(struct word_type *pointer) {
} while (word[wp] != NULL && wp < MAX_WORDS);
}
-int legal_label_check(char *word, int line, int type) {
+int legal_label_check(const char *label_word, int line, int type) {
struct integer_type *integer_pointer = integer_table;
struct cinteger_type *cinteger_pointer = cinteger_table;
struct string_type *string_pointer = string_table;
@@ -1147,30 +1139,30 @@ int legal_label_check(char *word, int line, int type) {
int index;
- if (!strcmp(word, "here") ||
- !strcmp(word, "player") ||
- !strcmp(word, "integer") ||
- !strcmp(word, "arg") ||
- !strcmp(word, "string_arg") ||
- !strcmp(word, "arg") ||
- !strcmp(word, "$word") ||
- !strcmp(word, "self") ||
- !strcmp(word, "this") ||
- !strcmp(word, "noun1") ||
- !strcmp(word, "noun2") ||
- !strcmp(word, "noun3") ||
- !strcmp(word, "noun4") ||
- !strcmp(word, "objects") ||
- validate(word)) {
- sprintf(error_buffer, ILLEGAL_LABEL, line, word);
+ if (!strcmp(label_word, "here") ||
+ !strcmp(label_word, "player") ||
+ !strcmp(label_word, "integer") ||
+ !strcmp(label_word, "arg") ||
+ !strcmp(label_word, "string_arg") ||
+ !strcmp(label_word, "arg") ||
+ !strcmp(label_word, "$label_word") ||
+ !strcmp(label_word, "self") ||
+ !strcmp(label_word, "this") ||
+ !strcmp(label_word, "noun1") ||
+ !strcmp(label_word, "noun2") ||
+ !strcmp(label_word, "noun3") ||
+ !strcmp(label_word, "noun4") ||
+ !strcmp(label_word, "objects") ||
+ validate(label_word)) {
+ sprintf(error_buffer, ILLEGAL_LABEL, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
}
if (type == CSTR_TYPE) {
- if (!strcmp(word, "command_prompt")) {
- sprintf(error_buffer, USED_LABEL_STR, line, word);
+ if (!strcmp(label_word, "command_prompt")) {
+ sprintf(error_buffer, USED_LABEL_STR, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1178,8 +1170,8 @@ int legal_label_check(char *word, int line, int type) {
}
while (integer_pointer != NULL && type != INT_TYPE) {
- if (!strcmp(word, integer_pointer->name)) {
- sprintf(error_buffer, USED_LABEL_INT, line, word);
+ if (!strcmp(label_word, integer_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_INT, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1189,8 +1181,8 @@ int legal_label_check(char *word, int line, int type) {
while (cinteger_pointer != NULL && type != CINT_TYPE) {
- if (!strcmp(word, cinteger_pointer->name)) {
- sprintf(error_buffer, USED_LABEL_CINT, line, word);
+ if (!strcmp(label_word, cinteger_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_CINT, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1199,8 +1191,8 @@ int legal_label_check(char *word, int line, int type) {
}
while (string_pointer != NULL && type != STR_TYPE) {
- if (!strcmp(word, string_pointer->name)) {
- sprintf(error_buffer, USED_LABEL_STR, line, word);
+ if (!strcmp(label_word, string_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_STR, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1209,8 +1201,8 @@ int legal_label_check(char *word, int line, int type) {
}
while (cstring_pointer != NULL && type != CSTR_TYPE) {
- if (!strcmp(word, cstring_pointer->name)) {
- sprintf(error_buffer, USED_LABEL_CSTR, line, word);
+ if (!strcmp(label_word, cstring_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_CSTR, line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1220,8 +1212,8 @@ int legal_label_check(char *word, int line, int type) {
/* DON'T CHECK FOR ATT_TYPE AS YOU CAN'T HAVE ATTRIBUTE ARRAYS. */
while (attribute_pointer != NULL) {
- if (!strcmp(word, attribute_pointer->name)) {
- sprintf(error_buffer, USED_LABEL_ATT, line, word);
+ if (!strcmp(label_word, attribute_pointer->name)) {
+ sprintf(error_buffer, USED_LABEL_ATT, line, label_word);
write_text(error_buffer);
return (TRUE);
@@ -1230,9 +1222,9 @@ int legal_label_check(char *word, int line, int type) {
}
for (index = 1; index <= objects; index++) {
- if (!strcmp(word, object[index]->label)) {
+ if (!strcmp(label_word, object[index]->label)) {
sprintf(error_buffer, USED_LABEL_OBJ,
- line, word);
+ line, label_word);
log_error(error_buffer, PLUS_STDERR);
return (TRUE);
@@ -1245,7 +1237,7 @@ int legal_label_check(char *word, int line, int type) {
void restart_game() {
int index;
- struct integer_type *current_integer;
+ struct integer_type *curr_integer;
struct integer_type *previous_integer;
struct synonym_type *current_synonym;
struct synonym_type *previous_synonym;
@@ -1253,7 +1245,7 @@ void restart_game() {
struct name_type *next_name;
struct function_type *current_function;
struct function_type *previous_function;
- struct string_type *current_string;
+ struct string_type *curr_string;
struct string_type *previous_string;
struct attribute_type *current_attribute;
struct attribute_type *previous_attribute;
@@ -1293,13 +1285,13 @@ void restart_game() {
if (integer_table != NULL) {
if (integer_table->next_integer != NULL) {
do {
- current_integer = integer_table;
+ curr_integer = integer_table;
previous_integer = integer_table;
- while (current_integer->next_integer != NULL) {
- previous_integer = current_integer;
- current_integer = current_integer->next_integer;
+ while (curr_integer->next_integer != NULL) {
+ previous_integer = curr_integer;
+ curr_integer = curr_integer->next_integer;
}
- free(current_integer);
+ free(curr_integer);
previous_integer->next_integer = NULL;
} while (previous_integer != integer_table);
}
@@ -1350,13 +1342,13 @@ void restart_game() {
if (string_table != NULL) {
if (string_table->next_string != NULL) {
do {
- current_string = string_table;
+ curr_string = string_table;
previous_string = string_table;
- while (current_string->next_string != NULL) {
- previous_string = current_string;
- current_string = current_string->next_string;
+ while (curr_string->next_string != NULL) {
+ previous_string = curr_string;
+ curr_string = curr_string->next_string;
}
- free(current_string);
+ free(curr_string);
previous_string->next_string = NULL;
} while (previous_string != string_table);
}
@@ -1406,13 +1398,13 @@ void restart_game() {
if (cstring_table != NULL) {
if (cstring_table->next_string != NULL) {
do {
- current_string = cstring_table;
+ curr_string = cstring_table;
previous_string = cstring_table;
- while (current_string->next_string != NULL) {
- previous_string = current_string;
- current_string = current_string->next_string;
+ while (curr_string->next_string != NULL) {
+ previous_string = curr_string;
+ curr_string = curr_string->next_string;
}
- free(current_string);
+ free(curr_string);
previous_string->next_string = NULL;
} while (previous_string != cstring_table);
}
@@ -1461,7 +1453,7 @@ void set_defaults() {
him = 0;
}
-void create_cinteger(char *name, int value) {
+void create_cinteger(const char *name, int value) {
struct cinteger_type *new_cinteger = NULL;
if ((new_cinteger = (struct cinteger_type *)
@@ -1482,7 +1474,7 @@ void create_cinteger(char *name, int value) {
}
}
-void create_integer(char *name, int value) {
+void create_integer(const char *name, int value) {
struct integer_type *new_integer = NULL;
if ((new_integer = (struct integer_type *)
@@ -1506,7 +1498,7 @@ void create_integer(char *name, int value) {
}
}
-void create_string(char *name, char *value) {
+void create_string(const char *name, const char *value) {
struct string_type *new_string = NULL;
if ((new_string = (struct string_type *)
@@ -1539,7 +1531,7 @@ void create_string(char *name, char *value) {
}
}
-void create_cstring(char *name, char *value) {
+void create_cstring(const char *name, const char *value) {
struct string_type *new_string = NULL;
if ((new_string = (struct string_type *)
diff --git a/engines/glk/jacl/logging.cpp b/engines/glk/jacl/logging.cpp
index 97376c5..789c12d 100644
--- a/engines/glk/jacl/logging.cpp
+++ b/engines/glk/jacl/logging.cpp
@@ -31,7 +31,7 @@ namespace JACL {
extern char user_id[];
extern char prefix[];
-void log_error(char *message, int console) {
+void log_error(const char *message, int console) {
/* LOG A MESSAGE TO THE CONSOLE */
char consoleMessage[256];
diff --git a/engines/glk/jacl/parser.cpp b/engines/glk/jacl/parser.cpp
index b9787c8..d37f4d1 100644
--- a/engines/glk/jacl/parser.cpp
+++ b/engines/glk/jacl/parser.cpp
@@ -77,7 +77,7 @@ char *expected_scope[3];
int from_objects[MAX_OBJECTS];
int after_from;
-char *from_word;
+const char *from_word;
int object_expected = FALSE;
@@ -93,8 +93,8 @@ extern char text_buffer[];
extern char function_name[];
extern char temp_buffer[];
extern char error_buffer[];
-extern char override[];
-extern char *word[];
+extern char override_[];
+extern const char *word[];
extern int quoted[];
@@ -194,7 +194,7 @@ void parser() {
}
// STORE THE EXPECTED SCOPE FOR LATER CHECKING
- expected_scope[current_noun] = (char *) &matched_word->word;
+ expected_scope[current_noun] = (char *)&matched_word->word;
//printf("--- expected scope for noun%d is %s\n", current_noun, expected_scope[current_noun]);
// THE NEXT MATCH OR GROUP OF MATCHES SHOULD BE IN THE SECOND
@@ -377,7 +377,7 @@ int first_available(int list_number) {
return (0);
}
-void call_functions(char *base_name) {
+void call_functions(const char *base_name) {
/* THIS FUNCTION CALLS ALL THE APPROPRIATE JACL FUNCTIONS TO RESPOND
* TO A PLAYER'S COMMAND GIVEN A BASE FUNCTION NAME AND THE CURRENT
* VALUE OF noun1 AND noun2 */
@@ -389,7 +389,7 @@ void call_functions(char *base_name) {
strncpy(base_function, base_name + 1, 80);
strcat(base_function, "_");
- strncpy(override, base_function, 80);
+ strncpy(override_, base_function, 80);
strcpy(before_function, "+before_");
strcat(before_function, base_name + 1);
@@ -439,8 +439,8 @@ void call_functions(char *base_name) {
/* PREPARE THE OVERRIDE FUNCTION NAME IN CASE IT
* IS NEEDED */
- strcat(override, "override_");
- strcat(override, object[HERE]->label);
+ strcat(override_, "override_");
+ strcat(override_, object[HERE]->label);
/* CREATE THE FUNCTION NAME '+func' */
strcpy(base_function, "+");
@@ -465,8 +465,8 @@ void call_functions(char *base_name) {
/* PREPARE THE OVERRIDE FUNCTION NAME IN CASE IT
* IS NEEDED */
- strcat(override, "override_");
- strcat(override, object[noun[0]]->label);
+ strcat(override_, "override_");
+ strcat(override_, object[noun[0]]->label);
/* CREATE THE FUNCTION NAME '+func' */
strcpy(base_function, "+");
@@ -495,9 +495,9 @@ void call_functions(char *base_name) {
/* PREPARE THE OVERRIDE FUNCTION NAME IN CASE IT
* IS NEEDED */
- strcat(override, object[noun[1]]->label);
- strcat(override, "_override_");
- strcat(override, object[noun[0]]->label);
+ strcat(override_, object[noun[1]]->label);
+ strcat(override_, "_override_");
+ strcat(override_, object[noun[0]]->label);
/* CREATE THE FUNCTION NAME '+func' */
strcpy(base_function, "+");
@@ -638,7 +638,7 @@ int build_object_list(struct word_type *scope_word, int noun_number) {
int index, counter;
int resolved_object;
- char *except_word;
+ const char *except_word;
//printf("--- entering build object list starting at %s with a scope_word of %s\n", word[wp], scope_word->word);
/* LOOK AHEAD FOR A FROM CLAUSE AND STORE from_object IF SO */
@@ -835,10 +835,9 @@ void set_them(int noun_number) {
}
void add_all(struct word_type *scope_word, int noun_number) {
- int index, counter;
+ int index;
//printf("--- trying to add all\n");
- counter = 0;
for (index = 1; index <= objects; index++) {
if ((object[index]->MASS < HEAVY) &&
@@ -1744,7 +1743,7 @@ void diagnose() {
TIME->value = FALSE;
}
-int scope(int index, char *expected, int restricted) {
+int scope(int index, const char *expected, int restricted) {
/* THIS FUNCTION DETERMINES IF THE SPECIFIED OBJECT IS IN THE SPECIFIED
* SCOPE - IT RETURNS TRUE IF SO, FALSE IF NOT. */
@@ -1860,7 +1859,7 @@ int find_parent(int index) {
}
}
-int parent_of(int parent, int child, int restricted) {
+int parent_of(int parent_, int child, int restricted) {
/* THIS FUNCTION WILL CLIMB THE OBJECT TREE STARTING AT 'CHILD' UNTIL
* 'PARENT' IS REACHED (RETURN TRUE), OR THE TOP OF THE TREE OR A CLOSED
* OR CONCEALING OBJECT IS REACHED (RETURN FALSE). */
@@ -1871,33 +1870,33 @@ int parent_of(int parent, int child, int restricted) {
int index;
- //printf("--- parent is %s, child is %s\n", object[parent]->label, object[child]->label);
- if (child == parent) {
+ //printf("--- parent_ is %s, child is %s\n", object[parent_]->label, object[child]->label);
+ if (child == parent_) {
return (TRUE);
} else if (!(object[child]->attributes & LOCATION) &&
object[child]->PARENT != NOWHERE) {
/* STORE THE CHILDS PARENT OBJECT */
index = object[child]->PARENT;
- //printf("--- %s is the parent of %s\n", object[index]->label, object[child]->label);
+ //printf("--- %s is the parent_ of %s\n", object[index]->label, object[child]->label);
if (index == child) {
/* THIS CHILD HAS IT'S PARENT SET TO ITSELF */
sprintf(error_buffer, SELF_REFERENCE, executing_function->name, object[index]->label);
log_error(error_buffer, PLUS_STDOUT);
- //printf("--- self parent.\n");
+ //printf("--- self parent_.\n");
return (FALSE);
} else if (!(object[index]->attributes & LOCATION)
&& ((object[index]->attributes & CLOSED && object[index]->attributes & CONTAINER)
|| object[index]->attributes & CONCEALING)) {
/* THE CHILDS PARENT IS CLOSED OR CONCEALING - CANT BE SEEN */
- //printf("--- parent %s is closed\n", object[index]->label);
+ //printf("--- parent_ %s is closed\n", object[index]->label);
return (FALSE);
- } else if (restricted && object[index]->MASS < HEAVY && index != parent) {
+ } else if (restricted && object[index]->MASS < HEAVY && index != parent_) {
//printf("--- scenery object.\n");
return (FALSE);
} else {
- //printf("--- comparing %s with %s\n", object[index]->label, object[parent]->label);
- if (index == parent) {
+ //printf("--- comparing %s with %s\n", object[index]->label, object[parent_]->label);
+ if (index == parent_) {
/* YES, IS PARENT OF CHILD */
return (TRUE);
} else if (object[index]->attributes & LOCATION) {
@@ -1905,7 +1904,7 @@ int parent_of(int parent, int child, int restricted) {
} else {
/* KEEP LOOKING UP THE TREE TILL THE CHILD HAS NO MORE
* PARENTS */
- return (parent_of(parent, index, restricted));
+ return (parent_of(parent_, index, restricted));
}
}
} else {
diff --git a/engines/glk/jacl/prototypes.h b/engines/glk/jacl/prototypes.h
index dabfb9d..66416f1 100644
--- a/engines/glk/jacl/prototypes.h
+++ b/engines/glk/jacl/prototypes.h
@@ -24,177 +24,177 @@ namespace Glk {
namespace JACL {
#ifdef GLK
-strid_t open_glk_file(uint usage, uint mode, char *filename);
-glui32 glk_get_bin_line_stream(strid_t file_stream, char *buffer, glui32 max_length);
-glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen);
-void convert_to_utf8(glui32 *text, int len);
-glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen);
+extern strid_t open_glk_file(uint usage, uint mode, char *filename);
+extern glui32 glk_get_bin_line_stream(strid_t file_stream, char *buffer, glui32 max_length);
+extern glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen);
+extern void convert_to_utf8(glui32 *text, int len);
+extern glui32 parse_utf8(unsigned char *buf, glui32 buflen, glui32 *out, glui32 outlen);
#else
-void update_parameters();
+extern void update_parameters();
#endif
-int bearing(double x1, double y1, double x2, double y2);
-int distance(double x1, double y1, double x2, double y2);
-int strcondition();
-int and_strcondition();
-int logic_test(int first);
-int str_test(int first);
-int first_available(int list_number);
-int validate(char *string);
-int noun_resolve(struct word_type *scope_word, int finding_from, int noun_number);
-int get_from_object(struct word_type *scope_word, int noun_number);
-int is_direct_child_of_from(int child);
-int is_child_of_from(int child);
-int verify_from_object(int from_object);
-int find_parent(int index);
-int scope(int index, char *expected, int restricted = 0);
-int object_element_resolve(char *textstring);
-int execute(char *funcname);
-int object_resolve(char object_string[]);
-int random_number();
-void log_error(char *message, int console);
-int parent_of(int parent, int child, int restricted);
-int grand_of(int child, int objs_only);
-int check_light(int where);
-int find_route(int fromRoom, int toRoom, int known);
-int exit_function(int return_code);
-int count_resolve(char *textstring);
-void jacl_set_window(winid_t new_window);
-void create_cstring(char *name, char *value);
-void create_string(char *name, char *value);
-void create_integer(char *name, int value);
-void create_cinteger(char *name, int value);
-void scripting();
-void undoing();
-void walking_thru();
-void create_paths(char *full_path);
-int get_key();
-char get_character(char *message);
-int get_yes_or_no();
-void get_string(char *string_buffer);
-int get_number(int insist, int low, int high);
-int save_interaction(char *filename);
-int restore_interaction(char *filename);
-void jacl_encrypt(char *string);
-void jacl_decrypt(char *string);
-void log_message(char *message, int console);
-void set_them(int noun_number);
-void preparse();
-void inspect(int object_num);
-void add_all(struct word_type *scope_word, int noun_number);
-void add_to_list(int noun_number, int resolved_object);
-void call_functions(char *base_name);
-int build_object_list(struct word_type *scope_word, int noun_number);
-long value_of(char *value, int run_time = 0);
-long attribute_resolve(char *attribute);
-long user_attribute_resolve(char *name);
-struct word_type *exact_match(struct word_type *pointer);
-struct word_type *object_match(struct word_type *iterator, int noun_number);
-struct integer_type *integer_resolve(char *name);
-struct integer_type *integer_resolve_indexed(char *name, int index);
-struct function_type *function_resolve(char *name);
-struct string_type *string_resolve(char *name);
-struct string_type *string_resolve_indexed(char *name, int index);
-struct string_type *cstring_resolve(char *name);
-struct string_type *cstring_resolve_indexed(char *name, int index);
-struct cinteger_type *cinteger_resolve(char *name);
-struct cinteger_type *cinteger_resolve_indexed(char *name, int index);
-int array_length_resolve(char *textstring);
-int legal_label_check(char *word, int line, int type);
-char *object_names(int object_index, char *names_buffer);
-char *arg_text_of(char *string);
-char *arg_text_of_word(int wordnumber);
-char *var_text_of_word(int wordnumber);
-char *text_of(char *string);
-char *text_of_word(int wordnumber);
-char *expand_function(char *name);
-int *container_resolve(char *container_name);
-int condition();
-int and_condition();
-void free_from(struct word_type *x);
-void eachturn();
-int jacl_whitespace(char character);
-int get_here();
-char *stripwhite(char *string);
-void command_encapsulate();
-void encapsulate();
-void jacl_truncate();
-void parser();
-void diagnose();
-void look_around();
-char *macro_resolve(char *textstring);
-char *plain_output(int index, int capital);
-char *sub_output(int index, int capital);
-char *obj_output(int index, int capital);
-char *that_output(int index, int capital);
-char *sentence_output(int index, int capital);
-char *isnt_output(int index, bool unused = false);
-char *is_output(int index, bool unused = false);
-char *it_output(int index, bool unused = false);
-char *doesnt_output(int index, bool unused = false);
-char *does_output(int index, bool unused = false);
-char *list_output(int index, int capital);
-char *long_output(int index);
-void terminate(int code);
-void set_arguments(char *function_call);
-void pop_stack();
-void push_stack(int32 file_pointer);
-void pop_proxy();
-void push_proxy();
-void write_text(char *string_buffer);
-void status_line();
-void newline();
-int save_game(frefid_t saveref);
-int restore_game(frefid_t saveref, int warn);
-void write_integer(strid_t stream, int x);
-int read_integer(strid_t stream);
-void write_long(strid_t stream, long x);
-long read_long(strid_t stream);
-void save_game_state();
-void restore_game_state();
-void add_cstring(char *name, char *value);
-void clear_cstring(char *name);
-void add_cinteger(char *name, int value);
-void clear_cinteger(char *name);
-void restart_game();
-void read_gamefile();
-void new_position(double x1, double y1, double bearing, double velocity);
-void build_grammar_table(struct word_type *pointer);
-void unkvalerr(int line, int wordno);
-void totalerrs(int errors);
-void unkatterr(int line, int wordno);
-void unkfunrun(char *name);
-void nofnamerr(int line);
-void nongloberr(int line);
-void unkkeyerr(int line, int wordno);
-void maxatterr(int line, int wordno);
-void unkattrun(int wordno);
-void badptrrun(char *name, int value);
-void badplrrun(int value);
-void badparrun();
-void notintrun();
-void noproprun(int unused = 0);
-void noproperr(int line);
-void noobjerr(int line);
-void unkobjerr(int line, int wordno);
-void unkobjrun(int wordno);
-void unkdirrun(int wordno);
-void unkscorun(char *scope);
-void unkstrrun(char *variable);
-void unkvarrun(char *variable);
-void outofmem();
-void set_defaults();
-void no_it();
-void more(char *message);
-int jpp();
-int process_file(char *sourceFile1, char *sourceFile2);
-char *strip_return(char *string);
-char *object_generator(char *text, int state);
-char *verb_generator(char *text, int state);
-void add_word(char *word);
-void create_language_constants();
-int select_next();
-void jacl_sleep(unsigned int mseconds);
+extern int bearing(double x1, double y1, double x2, double y2);
+extern int distance(double x1, double y1, double x2, double y2);
+extern int strcondition();
+extern int and_strcondition();
+extern int logic_test(int first);
+extern int str_test(int first);
+extern int first_available(int list_number);
+extern int validate(const char *string);
+extern int noun_resolve(struct word_type *scope_word, int finding_from, int noun_number);
+extern int get_from_object(struct word_type *scope_word, int noun_number);
+extern int is_direct_child_of_from(int child);
+extern int is_child_of_from(int child);
+extern int verify_from_object(int from_object);
+extern int find_parent(int index);
+extern int scope(int index, const char *expected, int restricted = 0);
+extern int object_element_resolve(const char *textstring);
+extern int execute(const char *funcname);
+extern int object_resolve(const char *object_string);
+extern int random_number();
+extern void log_error(const char *message, int console);
+extern int parent_of(int parent_, int child, int restricted);
+extern int grand_of(int child, int objs_only);
+extern int check_light(int where);
+extern int find_route(int fromRoom, int toRoom, int known);
+extern int exit_function(int return_code);
+extern int count_resolve(const char *textstring);
+extern void jacl_set_window(winid_t new_window);
+extern void create_cstring(const char *name, const char *value);
+extern void create_string(const char *name, const char *value);
+extern void create_integer(const char *name, int value);
+extern void create_cinteger(const char *name, int value);
+extern void scripting();
+extern void undoing();
+extern void walking_thru();
+extern void create_paths(char *full_path);
+extern int get_key();
+extern char get_character(const char *message);
+extern int get_yes_or_no();
+extern void get_string(char *string_buffer);
+extern int get_number(int insist, int low, int high);
+extern int save_interaction(const char *filename);
+extern int restore_interaction(const char *filename);
+extern void jacl_encrypt(char *string);
+extern void jacl_decrypt(char *string);
+extern void log_message(const char *message, int console);
+extern void set_them(int noun_number);
+extern void preparse();
+extern void inspect(int object_num);
+extern void add_all(struct word_type *scope_word, int noun_number);
+extern void add_to_list(int noun_number, int resolved_object);
+extern void call_functions(const char *base_name);
+extern int build_object_list(struct word_type *scope_word, int noun_number);
+extern long value_of(const char *value, int run_time = 0);
+extern long attribute_resolve(const char *attribute);
+extern long user_attribute_resolve(const char *name);
+extern struct word_type *exact_match(struct word_type *pointer);
+extern struct word_type *object_match(struct word_type *iterator, int noun_number);
+extern struct integer_type *integer_resolve(const char *name);
+extern struct integer_type *integer_resolve_indexed(const char *name, int index);
+extern struct function_type *function_resolve(const char *name);
+extern struct string_type *string_resolve(const char *name);
+extern struct string_type *string_resolve_indexed(const char *name, int index);
+extern struct string_type *cstring_resolve(const char *name);
+extern struct string_type *cstring_resolve_indexed(const char *name, int index);
+extern struct cinteger_type *cinteger_resolve(const char *name);
+extern struct cinteger_type *cinteger_resolve_indexed(const char *name, int index);
+extern int array_length_resolve(const char *textstring);
+extern int legal_label_check(const char *word, int line, int type);
+extern char *object_names(int object_index, char *names_buffer);
+extern const char *arg_text_of(const char *string);
+extern const char *arg_text_of_word(int wordnumber);
+extern const char *var_text_of_word(int wordnumber);
+extern const char *text_of(const char *string);
+extern const char *text_of_word(int wordnumber);
+extern const char *expand_function(const char *name);
+extern int *container_resolve(const char *container_name);
+extern int condition();
+extern int and_condition();
+extern void free_from(struct word_type *x);
+extern void eachturn();
+extern int jacl_whitespace(char character);
+extern int get_here();
+extern char *stripwhite(char *string);
+extern void command_encapsulate();
+extern void encapsulate();
+extern void jacl_truncate();
+extern void parser();
+extern void diagnose();
+extern void look_around();
+extern char *macro_resolve(const char *textstring);
+extern char *plain_output(int index, int capital);
+extern char *sub_output(int index, int capital);
+extern char *obj_output(int index, int capital);
+extern char *that_output(int index, int capital);
+extern char *sentence_output(int index, int capital);
+extern char *isnt_output(int index, bool unused = false);
+extern char *is_output(int index, bool unused = false);
+extern char *it_output(int index, bool unused = false);
+extern char *doesnt_output(int index, bool unused = false);
+extern char *does_output(int index, bool unused = false);
+extern char *list_output(int index, int capital);
+extern char *long_output(int index);
+extern void terminate(int code);
+extern void set_arguments(const char *function_call);
+extern void pop_stack();
+extern void push_stack(int32 file_pointer);
+extern void pop_proxy();
+extern void push_proxy();
+extern void write_text(const char *string_buffer);
+extern void status_line();
+extern void newline();
+extern int save_game(frefid_t saveref);
+extern int restore_game(frefid_t saveref, int warn);
+extern void write_integer(strid_t stream, int x);
+extern int read_integer(strid_t stream);
+extern void write_long(strid_t stream, long x);
+extern long read_long(strid_t stream);
+extern void save_game_state();
+extern void restore_game_state();
+extern void add_cstring(const char *name, const char *value);
+extern void clear_cstring(const char *name);
+extern void add_cinteger(const char *name, int value);
+extern void clear_cinteger(const char *name);
+extern void restart_game();
+extern void read_gamefile();
+extern void new_position(double x1, double y1, double bearing, double velocity);
+extern void build_grammar_table(struct word_type *pointer);
+extern void unkvalerr(int line, int wordno);
+extern void totalerrs(int errors);
+extern void unkatterr(int line, int wordno);
+extern void unkfunrun(const char *name);
+extern void nofnamerr(int line);
+extern void nongloberr(int line);
+extern void unkkeyerr(int line, int wordno);
+extern void maxatterr(int line, int wordno);
+extern void unkattrun(int wordno);
+extern void badptrrun(const char *name, int value);
+extern void badplrrun(int value);
+extern void badparrun();
+extern void notintrun();
+extern void noproprun(int unused = 0);
+extern void noproperr(int line);
+extern void noobjerr(int line);
+extern void unkobjerr(int line, int wordno);
+extern void unkobjrun(int wordno);
+extern void unkdirrun(int wordno);
+extern void unkscorun(const char *scope);
+extern void unkstrrun(const char *variable);
+extern void unkvarrun(const char *variable);
+extern void outofmem();
+extern void set_defaults();
+extern void no_it();
+extern void more(const char *message);
+extern int jpp();
+extern int process_file(const char *sourceFile1, char *sourceFile2);
+extern char *strip_return(char *string);
+extern const char *object_generator(const char *text, int state);
+extern const char *verb_generator(const char *text, int state);
+extern void add_word(const char *word);
+extern void create_language_constants();
+extern int select_next();
+extern void jacl_sleep(unsigned int mseconds);
} // End of namespace JACL
} // End of namespace Glk
diff --git a/engines/glk/jacl/resolvers.cpp b/engines/glk/jacl/resolvers.cpp
index cf42911..6d119de 100644
--- a/engines/glk/jacl/resolvers.cpp
+++ b/engines/glk/jacl/resolvers.cpp
@@ -67,7 +67,7 @@ extern char user_id[];
extern int noun[];
extern int quoted[];
extern int percented[];
-extern char *word[];
+extern const char *word[];
extern int resolved_attribute;
@@ -83,7 +83,7 @@ extern int value_resolved;
char macro_function[84];
int value_has_been_resolved;
-int *container_resolve(char *container_name) {
+int *container_resolve(const char *container_name) {
container_name = arg_text_of(container_name);
/* IN JACL, A 'CONTAINER' IS ANYTHING THAT CAN STORE AN INTEGER */
@@ -109,8 +109,8 @@ int *container_resolve(char *container_name) {
return ((int *) NULL);
}
-char *var_text_of_word(int wordnumber) {
- char *value;
+const char *var_text_of_word(int wordnumber) {
+ const char *value;
if (percented[wordnumber] == FALSE) {
return (word[wordnumber]);
@@ -126,8 +126,8 @@ char *var_text_of_word(int wordnumber) {
}
}
-char *arg_text_of_word(int wordnumber) {
- char *value;
+const char *arg_text_of_word(int wordnumber) {
+ const char *value;
if (quoted[wordnumber] == 1) {
return (word[wordnumber]);
@@ -143,8 +143,8 @@ char *arg_text_of_word(int wordnumber) {
}
}
-char *text_of_word(int wordnumber) {
- char *value;
+const char *text_of_word(int wordnumber) {
+ const char *value;
if (quoted[wordnumber] == 1) {
return (word[wordnumber]);
@@ -160,7 +160,7 @@ char *text_of_word(int wordnumber) {
}
}
-char *text_of(char *string) {
+const char *text_of(const char *string) {
struct integer_type *resolved_integer;
struct cinteger_type *resolved_cinteger;
struct string_type *resolved_string;
@@ -221,7 +221,7 @@ char *text_of(char *string) {
}
}
-char *arg_text_of(char *string) {
+const char *arg_text_of(const char *string) {
struct string_type *resolved_string;
struct string_type *resolved_cstring;
char *macro_text;
@@ -242,7 +242,7 @@ char *arg_text_of(char *string) {
}
}
-int validate(char *string) {
+int validate(const char *string) {
int index,
count;
@@ -265,7 +265,7 @@ int validate(char *string) {
return (TRUE);
}
-long value_of(char *value, int run_time) {
+long value_of(const char *value, int run_time) {
long compare;
value_resolved = TRUE;
@@ -347,7 +347,7 @@ long value_of(char *value, int run_time) {
}
}
-struct integer_type *integer_resolve(char *name) {
+struct integer_type *integer_resolve(const char *name) {
int index,
iterator,
counter;
@@ -408,7 +408,7 @@ struct integer_type *integer_resolve(char *name) {
}
}
-struct integer_type *integer_resolve_indexed(char *name, int index) {
+struct integer_type *integer_resolve_indexed(const char *name, int index) {
struct integer_type *pointer = integer_table;
if (pointer == NULL)
@@ -432,7 +432,7 @@ struct integer_type *integer_resolve_indexed(char *name, int index) {
return (NULL);
}
-struct cinteger_type *cinteger_resolve(char *name) {
+struct cinteger_type *cinteger_resolve(const char *name) {
int index,
iterator,
counter;
@@ -493,7 +493,7 @@ struct cinteger_type *cinteger_resolve(char *name) {
}
}
-struct cinteger_type *cinteger_resolve_indexed(char *name, int index) {
+struct cinteger_type *cinteger_resolve_indexed(const char *name, int index) {
struct cinteger_type *pointer = cinteger_table;
if (pointer == NULL)
@@ -517,7 +517,7 @@ struct cinteger_type *cinteger_resolve_indexed(char *name, int index) {
return (NULL);
}
-struct string_type *string_resolve(char *name) {
+struct string_type *string_resolve(const char *name) {
int index,
iterator,
counter;
@@ -569,7 +569,7 @@ struct string_type *string_resolve(char *name) {
return (NULL);
}
-struct string_type *string_resolve_indexed(char *name, int index) {
+struct string_type *string_resolve_indexed(const char *name, int index) {
struct string_type *pointer = string_table;
if (pointer == NULL)
@@ -593,7 +593,7 @@ struct string_type *string_resolve_indexed(char *name, int index) {
return (NULL);
}
-struct string_type *cstring_resolve(char *name) {
+struct string_type *cstring_resolve(const char *name) {
int index,
iterator,
counter;
@@ -645,7 +645,7 @@ struct string_type *cstring_resolve(char *name) {
return (NULL);
}
-struct string_type *cstring_resolve_indexed(char *name, int index) {
+struct string_type *cstring_resolve_indexed(const char *name, int index) {
struct string_type *pointer = cstring_table;
if (pointer == NULL)
@@ -669,8 +669,8 @@ struct string_type *cstring_resolve_indexed(char *name, int index) {
return (NULL);
}
-struct function_type *function_resolve(char *name) {
- char *full_name;
+struct function_type *function_resolve(const char *name) {
+ const char *full_name;
char core_name[84];
int index;
@@ -691,9 +691,8 @@ struct function_type *function_resolve(char *name) {
}
core_name[index] = 0;
- /* GET A POINTER TO A STRING THAT REPRESENTS THE EXPANDED NAME OF
- * THE FUNCTION */
- full_name = (char *) expand_function(core_name);
+ /* GET A POINTER TO A STRING THAT REPRESENTS THE EXPANDED NAME OF THE FUNCTION */
+ full_name = (const char *)expand_function(core_name);
/* LOOP THROUGH ALL THE FUNCTIONS LOOKING FOR A FUNCTION THAT
* HAS THIS EXPANDED FULL NAME */
@@ -708,7 +707,7 @@ struct function_type *function_resolve(char *name) {
return (NULL);
}
-char *expand_function(char *name) {
+const char *expand_function(const char *name) {
/* THIS FUNCTION TAKES A SCOPE FUNCTION CALL SUCH AS noun1.function
* AND REOLVE THE ACTUAL FUNCTION NAME SUCH AS function_key */
int index,
@@ -739,7 +738,7 @@ char *expand_function(char *name) {
index = value_of(expression, TRUE);
if (index < 1 || index > objects) {
- return ((char *) name);
+ return ((const char *) name);
}
if (cinteger_resolve(&expression[delimiter]) != NULL ||
@@ -754,10 +753,10 @@ char *expand_function(char *name) {
strcat(function_name, "_");
strcat(function_name, object[index]->label);
- return ((char *) function_name);
+ return ((const char *) function_name);
}
-char *macro_resolve(char *testString) {
+char *macro_resolve(const char *testString) {
int index,
counter;
int delimiter = 0;
@@ -988,7 +987,7 @@ char *macro_resolve(char *testString) {
return (NULL);
}
-int count_resolve(char *testString) {
+int count_resolve(const char *testString) {
struct function_type *resolved_function = NULL;
if (*(testString + 1) == 0) {
@@ -1002,9 +1001,9 @@ int count_resolve(char *testString) {
}
}
-int array_length_resolve(char *testString) {
+int array_length_resolve(const char *testString) {
int counter = 0;
- char *array_name = &testString[1];
+ const char *array_name = &testString[1];
struct integer_type *integer_pointer = integer_table;
struct cinteger_type *cinteger_pointer = cinteger_table;
@@ -1071,7 +1070,7 @@ int array_length_resolve(char *testString) {
return (0);
}
-int object_element_resolve(char *testString) {
+int object_element_resolve(const char *testString) {
int index,
iterator,
counter;
@@ -1161,7 +1160,7 @@ int object_element_resolve(char *testString) {
}
}
-int object_resolve(char object_string[]) {
+int object_resolve(const char *object_string) {
int index;
if (!strcmp(object_string, "noun1"))
@@ -1195,7 +1194,7 @@ int object_resolve(char object_string[]) {
return (-1);
}
-long attribute_resolve(char *attribute) {
+long attribute_resolve(const char *attribute) {
long bit_mask;
if (!strcmp(attribute, "VISITED"))
@@ -1299,7 +1298,7 @@ long attribute_resolve(char *attribute) {
return (0);
}
-long user_attribute_resolve(char *name) {
+long user_attribute_resolve(const char *name) {
struct attribute_type *pointer = attribute_table;
if (pointer == NULL)
diff --git a/engines/glk/jacl/types.h b/engines/glk/jacl/types.h
index 3cfb2af..a2290e0 100644
--- a/engines/glk/jacl/types.h
+++ b/engines/glk/jacl/types.h
@@ -57,10 +57,10 @@ struct stack_type {
char str_arguments[MAX_WORDS][256];
char text_buffer[1024];
char called_name[1024];
- char override[84];
+ char _override[84];
char scope_criterion[24];
char default_function[84];
- char *word[MAX_WORDS];
+ const char *word[MAX_WORDS];
int quoted[MAX_WORDS];
int wp;
int argcount;
diff --git a/engines/glk/jacl/utils.cpp b/engines/glk/jacl/utils.cpp
index 700d64c..f951322 100644
--- a/engines/glk/jacl/utils.cpp
+++ b/engines/glk/jacl/utils.cpp
@@ -99,7 +99,7 @@ char *strip_return(char *string) {
}
}
- return (char *) string;
+ return string;
}
int random_number() {
@@ -107,15 +107,15 @@ int random_number() {
}
void create_paths(char *full_path) {
- int index;
- char *last_slash;
+ int index;
+ char *last_slash;
/* SAVE A COPY OF THE SUPPLIED GAMEFILE NAME */
strcpy(game_file, full_path);
/* FIND THE LAST SLASH IN THE SPECIFIED GAME PATH AND REMOVE THE GAME
* FILE SUFFIX IF ANY EXISTS */
- last_slash = (char *) NULL;
+ last_slash = (char *)NULL;
/* GET A POINTER TO THE LAST SLASH IN THE FULL PATH */
last_slash = strrchr(full_path, DIR_SEPARATOR);
@@ -132,7 +132,7 @@ void create_paths(char *full_path) {
}
/* STORE THE GAME PATH AND THE GAME FILENAME PARTS SEPARATELY */
- if (last_slash == (char *) NULL) {
+ if (last_slash == (const char *) NULL) {
/* GAME MUST BE IN CURRENT DIRECTORY SO THERE WILL BE NO GAME PATH */
strcpy(prefix, full_path);
game_path[0] = 0;
@@ -182,7 +182,7 @@ void create_paths(char *full_path) {
}
}
-int jacl_whitespace(int character) {
+int jacl_whitespace(char character) {
/* CHECK IF A CHARACTER IS CONSIDERED WHITE SPACE IN THE JACL LANGUAGE */
switch (character) {
case ':':
Commit: fecf1b3834cca049c82bdbb764dffdd50a22d031
https://github.com/scummvm/scummvm/commit/fecf1b3834cca049c82bdbb764dffdd50a22d031
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Cleanup of loader code
Changed paths:
engines/glk/jacl/loader.cpp
diff --git a/engines/glk/jacl/loader.cpp b/engines/glk/jacl/loader.cpp
index d4da488..c969fac 100644
--- a/engines/glk/jacl/loader.cpp
+++ b/engines/glk/jacl/loader.cpp
@@ -42,15 +42,7 @@ extern int quoted[];
extern int punctuated[];
extern int wp;
-#ifdef GLK
extern schanid_t sound_channel[];
-#else
-#ifndef __NDS__
-extern struct parameter_type *parameter_table;
-struct parameter_type *current_parameter = NULL;
-struct parameter_type *new_parameter;
-#endif
-#endif
extern struct object_type *object[];
extern struct integer_type *integer_table;
@@ -74,11 +66,7 @@ struct integer_type *last_system_integer = NULL;
extern struct string_type *current_cstring;
extern struct cinteger_type *current_cinteger;
-#ifdef GLK
extern strid_t game_stream;
-#else
-extern FILE *file;
-#endif
extern int objects;
extern int integers;
@@ -100,9 +88,7 @@ void read_gamefile() {
int index,
counter,
errors;
-#ifdef GLK
int result;
-#endif
int location_count = 0;
int object_count = 0;
int line = 0;
@@ -187,33 +173,17 @@ void read_gamefile() {
create_cinteger("GLK", 0);
create_cinteger("CGI", 1);
create_cinteger("NDS", 2);
-#ifdef GLK
+
create_cinteger("interpreter", 0);
-#else
-#ifdef __NDS__
- create_cinteger("interpreter", 2);
-#else
- create_cinteger("interpreter", 1);
-#endif
-#endif
/* TEST FOR AVAILABLE FUNCTIONALITY BEFORE EXECUTING ANY JACL CODE */
-#ifdef GLK
GRAPHICS_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Graphics, 0);
GRAPHICS_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Graphics, 0);
SOUND_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Sound, 0);
SOUND_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Sound, 0);
TIMER_SUPPORTED->value = (int)g_vm->glk_gestalt(gestalt_Timer, 0);
TIMER_ENABLED->value = (int)g_vm->glk_gestalt(gestalt_Timer, 0);
-#else
- GRAPHICS_SUPPORTED->value = TRUE;
- GRAPHICS_ENABLED->value = TRUE;
- SOUND_SUPPORTED->value = TRUE;
- SOUND_ENABLED->value = TRUE;
- TIMER_SUPPORTED->value = FALSE;
- TIMER_ENABLED->value = FALSE;
-#endif
create_cinteger("true", 1);
create_cinteger("false", 0);
@@ -285,59 +255,38 @@ void read_gamefile() {
functions = 0;
strings = 0;
-#ifdef GLK
g_vm->glk_stream_set_position(game_stream, start_of_file, seekmode_Start);
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fseek(file, start_of_file, SEEK_SET);
- fgets(text_buffer, 1024, file);
-#endif
line++;
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
+
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
-#ifdef GLK
while (result) {
-#else
- while (!feof(file)) {
-#endif
encapsulate();
if (word[0] == NULL);
else if (text_buffer[0] == '{') {
-#ifdef GLK
while (result) {
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- while (!feof(file)) {
- fgets(text_buffer, 1024, file);
-#endif
line++;
+
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
if (text_buffer[0] == '}')
break;
}
- }
- else {
+ } else {
if (!strcmp(word[0], "grammar")) {
if (word[++wp] == NULL) {
noproperr(line);
@@ -420,8 +369,7 @@ void read_gamefile() {
current_synonym->next_synonym = NULL;
}
} else if (!strcmp(word[0], "parameter")) {
-#ifndef GLK
-#ifndef __NDS__
+#ifdef UNUSED
if (word[2] == NULL) {
noproperr(line);
errors++;
@@ -460,7 +408,8 @@ void read_gamefile() {
}
}
-#endif
+#else
+ warning("parameter");
#endif
} else if (!strcmp(word[0], "constant")) {
if (word[2] == NULL) {
@@ -650,20 +599,13 @@ void read_gamefile() {
}
}
}
-#ifdef GLK
+
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
@@ -703,32 +645,19 @@ void read_gamefile() {
current_integer = last_system_integer;
line = 0;
-#ifdef GLK
g_vm->glk_stream_set_position(game_stream, start_of_file, seekmode_Start);
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fseek(file, start_of_file, SEEK_SET);
- fgets(text_buffer, 1024, file);
-#endif
line++;
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
-#ifdef GLK
while (result) {
-#else
- while (!feof(file)) {
-#endif
encapsulate();
if (word[0] == NULL);
else if (text_buffer[0] == '{') {
@@ -779,11 +708,8 @@ void read_gamefile() {
current_function = function_table;
strcpy(current_function->name, function_name);
-#ifdef GLK
+
current_function->position = g_vm->glk_stream_get_position(game_stream);
-#else
- current_function->position = ftell(file);
-#endif
current_function->call_count = 0;
current_function->call_count_backup = 0;
current_function->self = self_parent;
@@ -801,11 +727,8 @@ void read_gamefile() {
current_function = current_function->next_function;
strcpy(current_function->name, function_name);
-#ifdef GLK
+
current_function->position = g_vm->glk_stream_get_position(game_stream);
-#else
- current_function->position = ftell(file);
-#endif
current_function->call_count = 0;
current_function->call_count_backup = 0;
current_function->self = self_parent;
@@ -816,22 +739,13 @@ void read_gamefile() {
}
}
-#ifdef GLK
while (result) {
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- while (!feof(file)) {
- fgets(text_buffer, 1024, file);
-#endif
line++;
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
@@ -1056,20 +970,12 @@ void read_gamefile() {
errors++;
}
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
if (!encrypted && strstr(text_buffer, "#encrypted")) {
encrypted = TRUE;
-#ifdef GLK
result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
-#else
- fgets(text_buffer, 1024, file);
-#endif
line++;
}
if (encrypted) jacl_decrypt(text_buffer);
@@ -1237,23 +1143,22 @@ int legal_label_check(const char *label_word, int line, int type) {
void restart_game() {
int index;
- struct integer_type *curr_integer;
- struct integer_type *previous_integer;
- struct synonym_type *current_synonym;
- struct synonym_type *previous_synonym;
- struct name_type *current_name;
- struct name_type *next_name;
- struct function_type *current_function;
- struct function_type *previous_function;
- struct string_type *curr_string;
- struct string_type *previous_string;
- struct attribute_type *current_attribute;
- struct attribute_type *previous_attribute;
- struct cinteger_type *previous_cinteger;
- struct filter_type *current_filter;
- struct filter_type *previous_filter;
-
-#ifdef GLK
+ integer_type *curr_integer;
+ integer_type *previous_integer;
+ synonym_type *current_synonym;
+ synonym_type *previous_synonym;
+ name_type *current_name;
+ name_type *next_name;
+ function_type *current_function;
+ function_type *previous_function;
+ string_type *curr_string;
+ string_type *previous_string;
+ attribute_type *current_attribute;
+ attribute_type *previous_attribute;
+ cinteger_type *previous_cinteger;
+ filter_type *current_filter;
+ filter_type *previous_filter;
+
if (SOUND_SUPPORTED->value) {
/* STOP ALL SOUNDS AND SET VOLUMES BACK TO 100% */
for (index = 0; index < 4; index++) {
@@ -1266,7 +1171,6 @@ void restart_game() {
cinteger_resolve(temp_buffer)->value = 100;
}
}
-#endif
/* FREE ALL OBJECTS */
for (index = 1; index <= objects; index++) {
Commit: 1a78b67d08d206c58c841e7540eb04bdcd032b6e
https://github.com/scummvm/scummvm/commit/1a78b67d08d206c58c841e7540eb04bdcd032b6e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Graceful exit when error occurs
Changed paths:
engines/glk/jacl/interpreter.cpp
engines/glk/jacl/jacl.cpp
engines/glk/jacl/jacl_main.cpp
engines/glk/jacl/loader.cpp
engines/glk/jacl/utils.cpp
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
index 94fa45f..0488d0a 100644
--- a/engines/glk/jacl/interpreter.cpp
+++ b/engines/glk/jacl/interpreter.cpp
@@ -363,6 +363,9 @@ int execute(const char *funcname) {
int object_1,
object_2;
+ if (g_vm->shouldQuit())
+ return 0;
+
/* THESE VARIABLE KEEP TRACK OF if AND endif COMMANDS TO DECIDE WHETHER
*THE CURRENT LINE OF CODE SHOULD BE EXECUTED OR NOT */
int currentLevel = 0;
@@ -389,6 +392,8 @@ int execute(const char *funcname) {
#ifdef GLK
push_stack(g_vm->glk_stream_get_position(game_stream));
+ if (g_vm->shouldQuit())
+ return FALSE;
#else
push_stack(ftell(file));
#endif
@@ -1163,6 +1168,7 @@ int execute(const char *funcname) {
}
} else if (!strcmp(word[0], "terminate")) {
terminate(0);
+ return 0;
} else if (!strcmp(word[0], "more")) {
if (word[1] == NULL) {
more("[MORE]");
@@ -1295,6 +1301,7 @@ int execute(const char *funcname) {
clrscrn();
} else if (!strcmp(word[0], "terminate")) {
terminate(0);
+ return;
} else if (!strcmp(word[0], "more")) {
if (word[1] == NULL) {
more("[MORE]");
@@ -2355,6 +2362,9 @@ int execute(const char *funcname) {
}
#ifdef GLK
+ if (g_vm->shouldQuit())
+ return 0;
+
before_command = g_vm->glk_stream_get_position(game_stream);
glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
@@ -2716,6 +2726,7 @@ void push_stack(int32 file_pointer) {
if (stack == STACK_SIZE) {
log_error("Stack overflow.", PLUS_STDERR);
terminate(45);
+ return;
} else {
backup[stack].infile = infile;
infile = NULL;
@@ -2851,6 +2862,7 @@ void push_proxy() {
if (proxy_stack == STACK_SIZE) {
log_error("Stack overflow.", PLUS_STDERR);
terminate(45);
+ return;
} else {
proxy_backup[proxy_stack].start_of_this_command = start_of_this_command;
proxy_backup[proxy_stack].start_of_last_command = start_of_last_command;
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
index c053033..86b7c72 100644
--- a/engines/glk/jacl/jacl.cpp
+++ b/engines/glk/jacl/jacl.cpp
@@ -42,7 +42,6 @@ void JACL::runGame() {
// Open up the game file as a stream, and play the game
game_stream = _streams->openStream(&_gameFile);
glk_main();
- glk_stream_close(game_stream);
}
bool JACL::initialize() {
diff --git a/engines/glk/jacl/jacl_main.cpp b/engines/glk/jacl/jacl_main.cpp
index 00fa706..c277f83 100644
--- a/engines/glk/jacl/jacl_main.cpp
+++ b/engines/glk/jacl/jacl_main.cpp
@@ -214,6 +214,7 @@ void glk_main() {
* OPEN GLK WINDOW, OUTPUT THE ERROR MESSAGE AND EXIT */
log_error(error_buffer, FALSE);
terminate(200);
+ return;
}
// INTIALISE THE CSV PARSER
@@ -257,6 +258,7 @@ void glk_main() {
if (object[2] == NULL) {
log_error(CANT_RUN, PLUS_STDERR);
terminate(43);
+ return;
}
/* DUMMY RETRIEVE OF 'HERE' FOR TESTING OF GAME STATE */
@@ -265,7 +267,7 @@ void glk_main() {
eachturn();
/* TOP OF COMMAND LOOP */
- do {
+ while (!g_vm->shouldQuit()) {
int gotline;
event_t ev;
@@ -423,8 +425,7 @@ void glk_main() {
command_encapsulate();
preparse();
}
-
- } while (TRUE);
+ }
}
void preparse() {
@@ -477,6 +478,7 @@ void word_check() {
newline();
execute("+score");
terminate(0);
+ return;
} else {
write_text(cstring_resolve("RETURN_GAME")->value);
}
diff --git a/engines/glk/jacl/loader.cpp b/engines/glk/jacl/loader.cpp
index c969fac..e5ad3d2 100644
--- a/engines/glk/jacl/loader.cpp
+++ b/engines/glk/jacl/loader.cpp
@@ -319,6 +319,7 @@ void read_gamefile() {
if (objects == MAX_OBJECTS) {
log_error(MAXIMUM_EXCEEDED, PLUS_STDERR);
terminate(47);
+ return;
} else {
if ((object[objects] = (struct object_type *)
malloc(sizeof(struct object_type))) == NULL)
@@ -614,6 +615,7 @@ void read_gamefile() {
if (errors) {
totalerrs(errors);
terminate(48);
+ return;
}
/*************************************************************************
@@ -995,6 +997,7 @@ void read_gamefile() {
if (errors) {
totalerrs(errors);
terminate(48);
+ return;
}
}
diff --git a/engines/glk/jacl/utils.cpp b/engines/glk/jacl/utils.cpp
index f951322..48ede2b 100644
--- a/engines/glk/jacl/utils.cpp
+++ b/engines/glk/jacl/utils.cpp
@@ -74,15 +74,14 @@ int get_here() {
if (player < 1 || player > objects) {
badplrrun(player);
terminate(44);
+ return 0;
} else if (object[player]->PARENT < 1 || object[player]->PARENT > objects || object[player]->PARENT == player) {
badparrun();
terminate(44);
+ return 0;
} else {
return (object[player]->PARENT);
}
-
- /* SHOULDN'T GET HERE, JUST TRYING TO KEEP VisualC++ HAPPY */
- return 1;
}
char *strip_return(char *string) {
Commit: 2d2a6746f185549769709071bcb3fdba0353c4a0
https://github.com/scummvm/scummvm/commit/2d2a6746f185549769709071bcb3fdba0353c4a0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Fix game script execution
Changed paths:
engines/glk/jacl/interpreter.cpp
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
index 0488d0a..5fd3827 100644
--- a/engines/glk/jacl/interpreter.cpp
+++ b/engines/glk/jacl/interpreter.cpp
@@ -423,7 +423,7 @@ int execute(const char *funcname) {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, executing_function->position, seekmode_Start);
before_command = executing_function->position;
- //result = glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fseek(file, executing_function->position, SEEK_SET);
before_command = executing_function->position;
Commit: 1342fce6f62c1f125cc827f76d5a12b069cfe0e1
https://github.com/scummvm/scummvm/commit/1342fce6f62c1f125cc827f76d5a12b069cfe0e1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Hooking up savegame code to GMM
Changed paths:
engines/glk/jacl/glk_saver.cpp
engines/glk/jacl/interpreter.cpp
engines/glk/jacl/jacl.cpp
engines/glk/jacl/jacl_main.cpp
engines/glk/jacl/prototypes.h
diff --git a/engines/glk/jacl/glk_saver.cpp b/engines/glk/jacl/glk_saver.cpp
index abd718f..54739d8 100644
--- a/engines/glk/jacl/glk_saver.cpp
+++ b/engines/glk/jacl/glk_saver.cpp
@@ -52,38 +52,25 @@ extern int parent;
extern int noun[];
-int save_game(frefid_t saveref) {
- struct integer_type *current_integer = integer_table;
- struct function_type *current_function = function_table;
- struct string_type *current_string = string_table;
-
- int index, counter;
- strid_t bookmark = NULL;
-
- bookmark = g_vm->glk_stream_open_file(saveref, filemode_Write, 0);
-
- if (bookmark == NULL) {
- return (FALSE);
- }
-
- /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
- * HAS BEEN SUCCESSFULLY OPENED */
- g_vm->glk_fileref_destroy(saveref);
-
- /* THIS IS WRITTEN TO HELP VALIDATE THE SAVED GAME
- * BEFORE CONTINUING TO LOAD IT */
- write_integer(bookmark, objects);
- write_integer(bookmark, integers);
- write_integer(bookmark, functions);
- write_integer(bookmark, strings);
+bool save_game(strid_t save) {
+ integer_type *current_integer = integer_table;
+ function_type *current_function = function_table;
+ string_type *current_string = string_table;
+ int index, counter;
+
+ // This is written to help validate the saved game when it's loaded
+ write_integer(save, objects);
+ write_integer(save, integers);
+ write_integer(save, functions);
+ write_integer(save, strings);
while (current_integer != NULL) {
- write_integer(bookmark, current_integer->value);
+ write_integer(save, current_integer->value);
current_integer = current_integer->next_integer;
}
while (current_function != NULL) {
- write_integer(bookmark, current_function->call_count);
+ write_integer(save, current_function->call_count);
current_function = current_function->next_function;
}
@@ -92,68 +79,50 @@ int save_game(frefid_t saveref) {
continue;
for (counter = 0; counter < 16; counter++) {
- write_integer(bookmark, object[index]->integer[counter]);
+ write_integer(save, object[index]->integer[counter]);
}
- write_long(bookmark, object[index]->attributes);
- write_long(bookmark, object[index]->user_attributes);
+ write_long(save, object[index]->attributes);
+ write_long(save, object[index]->user_attributes);
}
- /* WRITE OUT ALL THE CURRENT VALUES OF THE STRING VARIABLES */
+ // Write out all the current values of the string variables
while (current_string != NULL) {
for (index = 0; index < 255; index++) {
- g_vm->glk_put_char_stream(bookmark, current_string->value[index]);
+ g_vm->glk_put_char_stream(save, current_string->value[index]);
}
current_string = current_string->next_string;
}
- write_integer(bookmark, player);
- write_integer(bookmark, noun[3]);
+ write_integer(save, player);
+ write_integer(save, noun[3]);
- /* SAVE THE CURRENT VOLUME OF EACH OF THE SOUND CHANNELS */
+ // Save the current volume of each of the sound channels
for (index = 0; index < 8; index++) {
sprintf(temp_buffer, "volume[%d]", index);
- write_integer(bookmark, cinteger_resolve(temp_buffer)->value);
+ write_integer(save, cinteger_resolve(temp_buffer)->value);
}
- /* SAVE THE CURRENT VALUE OF THE GLK TIMER */
- write_integer(bookmark, cinteger_resolve("timer")->value);
-
- /* CLOSE THE STREAM */
- g_vm->glk_stream_close(bookmark, NULL);
+ // Save the current value of the GLK timer
+ write_integer(save, cinteger_resolve("timer")->value);
TIME->value = FALSE;
- return (TRUE);
+ return true;
}
-int restore_game(frefid_t saveref, int warn) {
- struct integer_type *current_integer = integer_table;
- struct function_type *current_function = function_table;
- struct string_type *current_string = string_table;
-
- int index, counter;
- int file_objects,
- file_integers,
- file_functions,
- file_strings;
- strid_t bookmark;
+bool restore_game(strid_t save, bool warn) {
+ integer_type *current_integer = integer_table;
+ function_type *current_function = function_table;
+ string_type *current_string = string_table;
- bookmark = g_vm->glk_stream_open_file(saveref, filemode_Read, 0);
+ int index, counter;
+ int file_objects, file_integers, file_functions, file_strings;
- if (!bookmark) {
- return (FALSE);
- }
-
- /* WE'RE DONE WITH THE FILE REFERENCE NOW THAT THE STREAM
- * HAS BEEN SUCCESSFULLY OPENED */
- g_vm->glk_fileref_destroy(saveref);
-
- /* THIS IS WRITTEN TO HELP VALIDATE THE SAVED GAME
- * BEFORE CONTINUING TO LOAD IT */
- file_objects = read_integer(bookmark);
- file_integers = read_integer(bookmark);
- file_functions = read_integer(bookmark);
- file_strings = read_integer(bookmark);
+ // Read properties to validate the savegame is for this game
+ file_objects = read_integer(save);
+ file_integers = read_integer(save);
+ file_functions = read_integer(save);
+ file_strings = read_integer(save);
if (file_objects != objects
|| file_integers != integers
@@ -162,17 +131,17 @@ int restore_game(frefid_t saveref, int warn) {
if (warn == FALSE) {
log_error(cstring_resolve("BAD_SAVED_GAME")->value, PLUS_STDOUT);
}
- g_vm->glk_stream_close(bookmark, NULL);
+ g_vm->glk_stream_close(save, NULL);
return (FALSE);
}
while (current_integer != NULL) {
- current_integer->value = read_integer(bookmark);
+ current_integer->value = read_integer(save);
current_integer = current_integer->next_integer;
}
while (current_function != NULL) {
- current_function->call_count = read_integer(bookmark);
+ current_function->call_count = read_integer(save);
current_function = current_function->next_function;
}
@@ -181,47 +150,44 @@ int restore_game(frefid_t saveref, int warn) {
continue;
for (counter = 0; counter < 16; counter++) {
- object[index]->integer[counter] = read_integer(bookmark);
+ object[index]->integer[counter] = read_integer(save);
}
- object[index]->attributes = read_integer(bookmark);
- object[index]->user_attributes = read_integer(bookmark);
+ object[index]->attributes = read_integer(save);
+ object[index]->user_attributes = read_integer(save);
}
while (current_string != NULL) {
for (index = 0; index < 255; index++) {
- current_string->value[index] = g_vm->glk_get_char_stream(bookmark);
+ current_string->value[index] = g_vm->glk_get_char_stream(save);
}
current_string = current_string->next_string;
}
- player = read_integer(bookmark);
- noun[3] = read_integer(bookmark);
+ player = read_integer(save);
+ noun[3] = read_integer(save);
- /* RESTORE THE CURRENT VOLUME OF EACH OF THE SOUND CHANNELS */
+ // Restore the current volume of each of the sound channels
for (index = 0; index < 8; index++) {
sprintf(temp_buffer, "volume[%d]", index);
- counter = read_integer(bookmark);
+ counter = read_integer(save);
cinteger_resolve(temp_buffer)->value = counter;
if (SOUND_SUPPORTED->value) {
- /* SET THE GLK VOLUME */
+ // Set the GLK volume
g_vm->glk_schannel_set_volume(sound_channel[index], (glui32) counter);
}
}
- /* RESTORE THE CURRENT VALUE OF THE GLK TIMER */
- counter = read_integer(bookmark);
+ // Restore the current value of the GLK timer
+ counter = read_integer(save);
cinteger_resolve("timer")->value = counter;
- /* SET THE GLK TIMER */
+ // Set the GLK timer
g_vm->glk_request_timer_events((glui32) counter);
- /* CLOSE THE STREAM */
- g_vm->glk_stream_close(bookmark, NULL);
-
TIME->value = FALSE;
- return (TRUE);
+ return true;
}
void write_integer(strid_t stream, int x) {
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
index 5fd3827..d0ec04a 100644
--- a/engines/glk/jacl/interpreter.cpp
+++ b/engines/glk/jacl/interpreter.cpp
@@ -1798,11 +1798,7 @@ int execute(const char *funcname) {
unkvarrun(word[1]);
return (exit_function(TRUE));
} else {
- if (word[2] == NULL) {
- *container = save_interaction(NULL);
- } else {
- *container = save_interaction(arg_text_of_word(2));
- }
+ *container = save_interaction();
}
}
} else if (!strcmp(word[0], "restoregame")) {
@@ -1815,11 +1811,7 @@ int execute(const char *funcname) {
unkvarrun(word[1]);
return (exit_function(TRUE));
} else {
- if (word[2] == NULL) {
- *container = restore_interaction(NULL);
- } else {
- *container = restore_interaction(arg_text_of_word(2));
- }
+ *container = restore_interaction();
}
}
} else if (!strcmp(word[0], "restartgame")) {
diff --git a/engines/glk/jacl/jacl.cpp b/engines/glk/jacl/jacl.cpp
index 86b7c72..0e97f59 100644
--- a/engines/glk/jacl/jacl.cpp
+++ b/engines/glk/jacl/jacl.cpp
@@ -21,6 +21,7 @@
*/
#include "glk/jacl/jacl.h"
+#include "glk/jacl/prototypes.h"
#include "common/config-manager.h"
namespace Glk {
@@ -56,7 +57,11 @@ Common::Error JACL::readSaveData(Common::SeekableReadStream *rs) {
}
Common::Error JACL::writeGameData(Common::WriteStream *ws) {
- return Common::kNoError;
+ strid_t data_stream = _streams->openStream(ws);
+ bool success = save_game(data_stream);
+ _streams->deleteStream(data_stream);
+
+ return success ? Common::kNoError : Common::kWritingFailed;
}
} // End of namespace JACL
diff --git a/engines/glk/jacl/jacl_main.cpp b/engines/glk/jacl/jacl_main.cpp
index c277f83..c23bae7 100644
--- a/engines/glk/jacl/jacl_main.cpp
+++ b/engines/glk/jacl/jacl_main.cpp
@@ -651,35 +651,12 @@ void save_game_state() {
noun3_backup = noun[3];
}
-int save_interaction(const char *filename) {
- frefid_t saveref;
-
- jacl_set_window(inputwin);
-
- if (inputwin == promptwin) {
- g_vm->glk_window_clear(promptwin);
- newline();
- }
-
- if (filename == NULL) {
- saveref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame | fileusage_BinaryMode, filemode_Write, 0);
+int save_interaction() {
+ if (g_vm->saveGame().getCode() == Common::kNoError) {
+ return (TRUE);
} else {
- saveref = g_vm->glk_fileref_create_by_name(fileusage_SavedGame | fileusage_BinaryMode, filename, 0);
-
- }
-
- jacl_set_window(mainwin);
-
- if (!saveref) {
write_text(cstring_resolve("CANT_SAVE")->value);
return (FALSE);
- } else {
- if (save_game(saveref)) {
- return (TRUE);
- } else {
- write_text(cstring_resolve("CANT_SAVE")->value);
- return (FALSE);
- }
}
}
@@ -1237,30 +1214,8 @@ void walking_thru() {
walkthru_running = FALSE;
}
-int restore_interaction(const char *filename) {
- frefid_t saveref;
-
- jacl_set_window(inputwin);
-
- if (inputwin == promptwin) {
- g_vm->glk_window_clear(promptwin);
- newline();
- }
-
- if (filename == NULL) {
- saveref = g_vm->glk_fileref_create_by_prompt(fileusage_SavedGame | fileusage_BinaryMode, filemode_Read, 0);
- } else {
- saveref = g_vm->glk_fileref_create_by_name(fileusage_SavedGame | fileusage_BinaryMode, filename, 0);
- }
-
- jacl_set_window(mainwin);
-
- if (!saveref) {
- write_text(cstring_resolve("CANT_RESTORE")->value);
- return (FALSE);
- }
-
- if (restore_game(saveref, TRUE) == FALSE) {
+int restore_interaction() {
+ if (g_vm->loadGame().getCode() != Common::kNoError) {
write_text(cstring_resolve("CANT_RESTORE")->value);
return (FALSE);
} else {
diff --git a/engines/glk/jacl/prototypes.h b/engines/glk/jacl/prototypes.h
index 66416f1..99d2de0 100644
--- a/engines/glk/jacl/prototypes.h
+++ b/engines/glk/jacl/prototypes.h
@@ -73,11 +73,11 @@ extern char get_character(const char *message);
extern int get_yes_or_no();
extern void get_string(char *string_buffer);
extern int get_number(int insist, int low, int high);
-extern int save_interaction(const char *filename);
-extern int restore_interaction(const char *filename);
+extern int save_interaction();
+extern int restore_interaction();
extern void jacl_encrypt(char *string);
extern void jacl_decrypt(char *string);
-extern void log_message(const char *message, int console);
+//extern void log_message(const char *message, int console);
extern void set_them(int noun_number);
extern void preparse();
extern void inspect(int object_num);
@@ -144,8 +144,8 @@ extern void push_proxy();
extern void write_text(const char *string_buffer);
extern void status_line();
extern void newline();
-extern int save_game(frefid_t saveref);
-extern int restore_game(frefid_t saveref, int warn);
+extern bool save_game(strid_t save);
+extern bool restore_game(strid_t save, bool warn = false);
extern void write_integer(strid_t stream, int x);
extern int read_integer(strid_t stream);
extern void write_long(strid_t stream, long x);
Commit: 73271448570887c4721b1f819d2818fad1f3684f
https://github.com/scummvm/scummvm/commit/73271448570887c4721b1f819d2818fad1f3684f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Standardizing on calls to get stream line
Changed paths:
engines/glk/jacl/interpreter.cpp
diff --git a/engines/glk/jacl/interpreter.cpp b/engines/glk/jacl/interpreter.cpp
index d0ec04a..1203f65 100644
--- a/engines/glk/jacl/interpreter.cpp
+++ b/engines/glk/jacl/interpreter.cpp
@@ -490,7 +490,7 @@ int execute(const char *funcname) {
// SKIP THIS BLOCK OF PLAIN TEXT UNTIL IT FINDS A
// LINE THAT STARTS WITH A '.' OR A '}'
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -505,7 +505,7 @@ int execute(const char *funcname) {
// GET THE NEXT LINE
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -916,7 +916,7 @@ int execute(const char *funcname) {
if (*select_integer == 0) {
// THERE ARE NO MATCHING OBJECTS SO JUMP TO THE endselect
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -929,7 +929,7 @@ int execute(const char *funcname) {
break;
}
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -1693,7 +1693,7 @@ int execute(const char *funcname) {
// DISPLAYS A BLOCK OF PLAIN TEXT UNTIL IT FINDS A
// LINE THAT STARTS WITH A '.' OR A '}'
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -1744,7 +1744,7 @@ int execute(const char *funcname) {
// GET THE NEXT LINE
#ifdef GLK
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
@@ -2358,7 +2358,7 @@ int execute(const char *funcname) {
return 0;
before_command = g_vm->glk_stream_get_position(game_stream);
- glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
+ (void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
before_command = ftell(file);
fgets(text_buffer, 1024, file);
Commit: b37201ef76c1de4bffcf1b45ffad42d2183afca7
https://github.com/scummvm/scummvm/commit/b37201ef76c1de4bffcf1b45ffad42d2183afca7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-10-07T19:01:52-07:00
Commit Message:
GLK: JACL: Fix exiting game when game window is closed
Changed paths:
engines/glk/jacl/jacl_main.cpp
diff --git a/engines/glk/jacl/jacl_main.cpp b/engines/glk/jacl/jacl_main.cpp
index c23bae7..7221986 100644
--- a/engines/glk/jacl/jacl_main.cpp
+++ b/engines/glk/jacl/jacl_main.cpp
@@ -304,6 +304,8 @@ void glk_main() {
while (!gotline) {
/* GRAB AN EVENT. */
g_vm->glk_select(&ev);
+ if (g_vm->shouldQuit())
+ return;
switch (ev.type) {
More information about the Scummvm-git-logs
mailing list