aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-29 21:37:31 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commit41b62ab00db1d1730b1d61b77fda0df2c65753c0 (patch)
tree4540fcc66b85971001943211b04bd6f6f62038a9
parent5ab65b0954ba69ed31edfdbd563a549f7da692af (diff)
downloadscummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.tar.gz
scummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.tar.bz2
scummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.zip
GLK: TADS: Add a number of GLK interface methods
-rw-r--r--engines/glk/glk_api.cpp2
-rw-r--r--engines/glk/glk_api.h2
-rw-r--r--engines/glk/module.mk1
-rw-r--r--engines/glk/tads/tads.cpp21
-rw-r--r--engines/glk/tads/tads.h2
-rw-r--r--engines/glk/tads/tads2/ler.cpp69
-rw-r--r--engines/glk/tads/tads2/ler.h49
-rw-r--r--engines/glk/tads/tads2/os.cpp309
-rw-r--r--engines/glk/tads/tads2/os.h334
-rw-r--r--engines/glk/tads/tads2/tads2.cpp39
-rw-r--r--engines/glk/tads/tads2/tads2.h17
11 files changed, 761 insertions, 84 deletions
diff --git a/engines/glk/glk_api.cpp b/engines/glk/glk_api.cpp
index 19f8aef99f..32d6177f9a 100644
--- a/engines/glk/glk_api.cpp
+++ b/engines/glk/glk_api.cpp
@@ -394,7 +394,7 @@ void GlkAPI::glk_put_string_stream(strid_t str, const char *s) {
str->putBuffer(s, strlen(s));
}
-void GlkAPI::glk_put_buffer(char *buf, glui32 len) {
+void GlkAPI::glk_put_buffer(const char *buf, glui32 len) {
_streams->getCurrent()->putBuffer(buf, len);
}
diff --git a/engines/glk/glk_api.h b/engines/glk/glk_api.h
index fe25930cc2..3081ac2b27 100644
--- a/engines/glk/glk_api.h
+++ b/engines/glk/glk_api.h
@@ -100,7 +100,7 @@ public:
void glk_put_char_stream(strid_t str, unsigned char ch);
void glk_put_string(const char *s);
void glk_put_string_stream(strid_t str, const char *s);
- void glk_put_buffer(char *buf, glui32 len);
+ void glk_put_buffer(const char *buf, glui32 len);
void glk_put_buffer_stream(strid_t str, const char *buf, glui32 len);
void glk_set_style(glui32 styl);
void glk_set_style_stream(strid_t str, glui32 styl);
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 9a3aa37edb..89be6a2507 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -46,6 +46,7 @@ MODULE_OBJS := \
tads/detection.o \
tads/tads.o \
tads/tads2/ler.o \
+ tads/tads2/os.o \
tads/tads2/tads2.o \
tads/tads3/tads3.o
diff --git a/engines/glk/tads/tads.cpp b/engines/glk/tads/tads.cpp
index aa309279e7..5dc400b164 100644
--- a/engines/glk/tads/tads.cpp
+++ b/engines/glk/tads/tads.cpp
@@ -31,33 +31,34 @@ TADS::TADS(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam
/*
* GLK Initialization
*/
- mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
- if (!mainwin)
+ // Open the story window
+ story_win = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
+ if (!story_win)
error("fatal: could not open window!\n");
// get default colors for main window
- if (!glk_style_measure(mainwin, style_Normal, stylehint_TextColor, &mainfg))
+ if (!glk_style_measure(story_win, style_Normal, stylehint_TextColor, &mainfg))
mainfg = 0;
- if (!glk_style_measure(mainwin, style_Normal, stylehint_BackColor, &mainbg))
+ if (!glk_style_measure(story_win, style_Normal, stylehint_BackColor, &mainbg))
mainbg = 0;
// get default colors for status window
- statuswin = glk_window_open(mainwin, winmethod_Above | winmethod_Fixed, 1,
+ status_win = glk_window_open(story_win, winmethod_Above | winmethod_Fixed, 1,
wintype_TextGrid, 0);
- if (!glk_style_measure(statuswin, style_Normal, stylehint_TextColor, &statusfg))
+ if (!glk_style_measure(status_win, style_Normal, stylehint_TextColor, &statusfg))
statusfg = 0;
- if (!glk_style_measure(statuswin, style_Normal, stylehint_BackColor, &statusbg))
+ if (!glk_style_measure(status_win, style_Normal, stylehint_BackColor, &statusbg))
statusbg = 0;
// close status window; reopened on request
- glk_window_close(statuswin, 0);
- statuswin = nullptr;
+ glk_window_close(status_win, 0);
+ status_win = nullptr;
- glk_set_window(mainwin);
+ glk_set_window(story_win);
}
Common::Error TADS::loadGameData(strid_t file) {
diff --git a/engines/glk/tads/tads.h b/engines/glk/tads/tads.h
index 0f1565aaa9..ec9ea93f7d 100644
--- a/engines/glk/tads/tads.h
+++ b/engines/glk/tads/tads.h
@@ -34,7 +34,7 @@ namespace TADS {
*/
class TADS : public GlkAPI {
protected:
- winid_t mainwin, statuswin;
+ winid_t story_win, status_win;
glui32 mainfg, mainbg;
glui32 statusfg, statusbg;
public:
diff --git a/engines/glk/tads/tads2/ler.cpp b/engines/glk/tads/tads2/ler.cpp
index 9213d0bc5b..930fdf02a1 100644
--- a/engines/glk/tads/tads2/ler.cpp
+++ b/engines/glk/tads/tads2/ler.cpp
@@ -26,7 +26,9 @@ namespace Glk {
namespace TADS {
namespace TADS2 {
-int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv) {
+#define TRDLOGERR_PREFIX "\n[An error has occurred within TADS: "
+
+int errcxdef::errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv) {
int outlen = 0;
int argi = 0;
int len;
@@ -125,55 +127,26 @@ int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv) {
return outlen;
}
-#if defined(DEBUG) && !defined(ERR_NO_MACRO)
-void errjmp(jmp_buf buf, int e) {
- longjmp(buf, e);
-}
-#endif /* DEBUG */
-
-#ifdef ERR_NO_MACRO
-
-void errsign(errcxdef *ctx, int e, char *facility) {
- strncpy(ctx->errcxptr->errfac, facility, ERRFACMAX);
- ctx->errcxptr->errfac[ERRFACMAX] = '\0';
- ctx->errcxofs = 0;
- longjmp(ctx->errcxptr->errbuf, e);
-}
-
-void errsigf(errcxdef *ctx, char *facility, int e) {
- errargc(ctx, 0);
- errsign(ctx, e, facility);
-}
-
-char *errstr(errcxdef *ctx, const char *str, int len) {
- char *ret = &ctx->errcxbuf[ctx->errcxofs];
-
- memcpy(ret, str, (size_t)len);
- ret[len] = '\0';
- ctx->errcxofs += len + 1;
- return(ret);
+void errcxdef::errcxlog(void *ctx0, char *fac, int err, int argc, erradef *argv) {
+#ifdef TODO
+ errcxdef *ctx = (errcxdef *)ctx0;
+ char buf[256];
+ char msg[256];
+
+ // display the prefix message to the console and log file
+ sprintf(buf, TRDLOGERR_PREFIX, fac, err);
+ trdptf("%s", buf);
+ out_logfile_print(buf, false);
+
+ /* display the error message text to the console and log file */
+ errmsg(ctx, msg, (uint)sizeof(msg), err);
+ errfmt(buf, (int)sizeof(buf), msg, argc, argv);
+ trdptf("%s]\n", buf);
+ out_logfile_print(buf, false);
+ out_logfile_print("]", true);
+#endif
}
-void errrse1(errcxdef *ctx, errdef *fr) {
- errargc(ctx, fr->erraac);
- memcpy(ctx->errcxptr->erraav, fr->erraav,
- (size_t)(fr->erraac * sizeof(erradef)));
- errsign(ctx, fr->errcode, fr->errfac);
-}
-
-void errlogn(errcxdef *ctx, int err, char *facility) {
- ctx->errcxofs = 0;
- (*ctx->errcxlog)(ctx->errcxlgc, facility, err, ctx->errcxptr->erraac,
- ctx->errcxptr->erraav);
-}
-
-void errlogf(errcxdef *ctx, char *facility, int err) {
- errargc(ctx, 0);
- errlogn(ctx, err, facility);
-}
-
-#endif /* ERR_NO_MACRO */
-
} // End of namespace TADS2
} // End of namespace TADS
} // End of namespace Glk
diff --git a/engines/glk/tads/tads2/ler.h b/engines/glk/tads/tads2/ler.h
index 5301a0f53a..000aa093f4 100644
--- a/engines/glk/tads/tads2/ler.h
+++ b/engines/glk/tads/tads2/ler.h
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
+#include "common/algorithm.h"
namespace Glk {
namespace TADS {
@@ -49,26 +50,47 @@ struct errdef {
#define ERRBUFSIZ 512
+class TADS2;
+
// seek location record for an error message by number
struct errmfdef {
uint errmfnum; // error number
size_t errmfseek; // seek location of this message
};
-struct errcxdef {
- errdef *errcxptr; // current error frame
- void (*errcxlog)(void *, char *fac, int err, int argc, erradef *);
- // error logging callback function
+class errcxdef {
+public:
+ errdef *errcxptr; // current error frame
void *errcxlgc; // context for error logging callback
int errcxofs; // offset in argument buffer
char errcxbuf[ERRBUFSIZ]; // space for argument strings
- Common::SeekableReadStream *errcxfp; // message file, if one is being used
+ Common::SeekableReadStream *errcxfp; // message file, if one is being used
errmfdef *errcxseek; // seek locations of messages in file
uint errcxsksz; // size of errcxseek array
size_t errcxbase; // offset in physical file of logical error file
- struct appctxdef *errcxappctx; // host application context
+ TADS2 * errcxappctx; // host application context
+public:
+ /**
+ * Format an error message, sprintf-style, using arguments in an
+ * erradef array (which is passed to the error-logging callback).
+ * Returns the length of the output string, even if the actual
+ * output string was truncated because the outbuf was too short.
+ * (If called with outbufl == 0, nothing will be written out, but
+ * the size of the buffer needed, minus the terminating null byte,
+ * will be computed and returned.)
+ */
+ static int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv);
+ public:
+ errcxdef() : errcxptr(nullptr), errcxlgc(nullptr), errcxofs(0),
+ errcxseek(nullptr), errcxsksz(0), errcxbase(0), errcxappctx(nullptr) {
+ Common::fill(&errcxbuf[0], &errcxbuf[ERRBUFSIZ], '\0');
+ }
+
+ /**
+ * Error logging method
+ */
+ void errcxlog(void *ctx0, char *fac, int err, int argc, erradef *argv);
};
-typedef struct errcxdef errcxdef;
// begin protected code
#define ERRBEGIN(ctx) \
@@ -252,18 +274,7 @@ void errlogf(errcxdef *ctx, char *facility, int err);
(errargv(ctx,0,typ1,arg1),errargv(ctx,1,typ2,arg2),\
errargc(ctx,2),errlogn(ctx,e,fac))
-
-/**
- * Format an error message, sprintf-style, using arguments in an
- * erradef array (which is passed to the error-logging callback).
- * Returns the length of the output string, even if the actual
- * output string was truncated because the outbuf was too short.
- * (If called with outbufl == 0, nothing will be written out, but
- * the size of the buffer needed, minus the terminating null byte,
- * will be computed and returned.)
- */
-extern int errfmt(char *outbuf, int outbufl, char *fmt, int argc, erradef *argv);
-
+
// get the text of an error
void errmsg(errcxdef *ctx, char *outbuf, uint outbufl, uint err);
diff --git a/engines/glk/tads/tads2/os.cpp b/engines/glk/tads/tads2/os.cpp
new file mode 100644
index 0000000000..df7cb423fe
--- /dev/null
+++ b/engines/glk/tads/tads2/os.cpp
@@ -0,0 +1,309 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/tads/tads2/os.h"
+
+namespace Glk {
+namespace TADS {
+namespace TADS2 {
+
+OS::OS(OSystem *syst, const GlkGameDescription &gameDesc) : TADS(syst, gameDesc),
+ status_mode(0) {
+ Common::fill(&status_left[0], &status_left[OSS_STATUS_STRING_LEN], '\0');
+ Common::fill(&status_right[0], &status_right[OSS_STATUS_STRING_LEN], '\0');
+}
+
+void OS::os_terminate(int rc) {
+ glk_exit();
+}
+
+glui32 OS::oss_convert_prompt_type(int type) {
+ if (type == OS_AFP_OPEN)
+ return filemode_Read;
+ return filemode_ReadWrite;
+}
+
+glui32 OS::oss_convert_file_type(int type) {
+ if (type == OSFTSAVE)
+ return fileusage_SavedGame;
+ if (type == OSFTLOG || type == OSFTTEXT)
+ return fileusage_Transcript;
+ return fileusage_Data;
+}
+
+glui32 OS::oss_convert_fileref_to_string(frefid_t file_to_convert, char *buffer, int buf_len) {
+ char temp_string[32];
+ glui32 value, i = 0, digit,
+ digit_flag = false, // Have we put a digit in the string yet?
+ divisor = 1e9; // The max 32-bit integer is 4294967295
+
+ // This could probably be done by using sprintf("%s%ld%s") but I don't want to risk it
+ value = (glui32)file_to_convert;
+ while (divisor != 1) {
+ digit = (char)(value / divisor);
+ if (digit != 0 || digit_flag) { // This lets us handle, eg, 102
+ temp_string[i++] = digit + '0';
+ digit_flag = true;
+ }
+ value = value % divisor;
+ divisor /= 10;
+ }
+ temp_string[i++] = (char)value + '0';
+ temp_string[i] = 0;
+ if (strlen(temp_string) + strlen(OSS_FILEREF_STRING_PREFIX) +
+ strlen(OSS_FILEREF_STRING_SUFFIX) > (size_t)buf_len)
+ return false;
+ sprintf(buffer, "%s%s%s", OSS_FILEREF_STRING_PREFIX,
+ temp_string, OSS_FILEREF_STRING_SUFFIX);
+ return true;
+}
+
+frefid_t OS::oss_convert_string_to_fileref(char *buffer, glui32 usage) {
+ char temp_string[32];
+ glui32 value = 0, i, multiplier = 1;
+
+ // Does the buffer contain a hashed fileref?
+ if (oss_is_string_a_fileref(buffer)) {
+ // If so, we need only decode the string in the middle and return its value
+ strcpy(temp_string, buffer + strlen(OSS_FILEREF_STRING_PREFIX));
+ i = strlen(temp_string) - strlen(OSS_FILEREF_STRING_SUFFIX);
+ temp_string[i] = 0;
+ while (i != 0) {
+ i--;
+ value += ((glui32)(temp_string[i] - '0') * multiplier);
+ multiplier *= 10;
+ }
+ return ((frefid_t)value);
+ }
+
+ // If not, return the new fileref
+ return (glk_fileref_create_by_name(usage, os_get_root_name(buffer), 0));
+}
+
+bool OS::oss_is_string_a_fileref(char *buffer) {
+ if ((strncmp(buffer, OSS_FILEREF_STRING_PREFIX,
+ strlen(OSS_FILEREF_STRING_PREFIX)) == 0) &&
+ (strncmp(buffer + strlen(buffer) - strlen(OSS_FILEREF_STRING_SUFFIX),
+ OSS_FILEREF_STRING_SUFFIX,
+ strlen(OSS_FILEREF_STRING_SUFFIX)) == 0))
+ return true;
+ return false;
+}
+
+unsigned char OS::oss_convert_keystroke_to_tads(glui32 key) {
+ // Characters 0 - 255 we return per normal */
+ if (key <= 255)
+ return ((unsigned char)key);
+ switch (key) {
+ case keycode_Up:
+ return CMD_UP;
+ case keycode_Down:
+ return CMD_DOWN;
+ case keycode_Left:
+ return CMD_LEFT;
+ case keycode_Right:
+ return CMD_RIGHT;
+ case keycode_PageUp:
+ return CMD_PGUP;
+ case keycode_PageDown:
+ return CMD_PGDN;
+ case keycode_Home:
+ return CMD_HOME;
+ case keycode_End:
+ return CMD_END;
+ case keycode_Func1:
+ return CMD_F1;
+ case keycode_Func2:
+ return CMD_F2;
+ case keycode_Func3:
+ return CMD_F3;
+ case keycode_Func4:
+ return CMD_F4;
+ case keycode_Func5:
+ return CMD_F5;
+ case keycode_Func6:
+ return CMD_F6;
+ case keycode_Func7:
+ return CMD_F7;
+ case keycode_Func8:
+ return CMD_F8;
+ case keycode_Func9:
+ return CMD_F9;
+ case keycode_Func10:
+ return CMD_F10;
+ default:
+ return 0;
+ }
+}
+
+bool OS::oss_check_path(char *filename) {
+ return false;
+}
+
+void OS::oss_revert_path() {
+ // No implementation
+}
+
+osfildef *OS::oss_open_stream(char *buffer, glui32 tadsusage, glui32 tbusage,
+ glui32 fmode, glui32 rock) {
+ frefid_t fileref;
+ strid_t osf;
+ int changed_dirs;
+
+ fileref = oss_convert_string_to_fileref(buffer,
+ oss_convert_file_type(tadsusage) | tbusage);
+ changed_dirs = oss_check_path(buffer);
+ osf = glk_stream_open_file(fileref, (FileMode)fmode, rock);
+ if (changed_dirs)
+ oss_revert_path();
+ return *osf;
+}
+
+void OS::oss_put_string_with_hilite(winid_t win, const char *str, size_t len) {
+ glk_set_window(win);
+ glk_put_buffer(str, len);
+}
+
+void OS::oss_draw_status_line(void) {
+ glui32 width, height, division;
+
+ if (status_win == nullptr) return; // In case this is a CheapGlk port
+
+ glk_window_get_size(status_win, &width, &height);
+ if (height == 0) return; // Don't bother if status is invisible
+ division = width - strlen(status_right) - 1;
+ glk_set_window(status_win);
+ glk_window_clear(status_win);
+ oss_put_string_with_hilite(status_win, status_left, strlen(status_left));
+ glk_window_move_cursor(status_win, division, 0);
+ glk_put_string(status_right);
+}
+
+void OS::oss_change_status_string(char *dest, const char *src, size_t len) {
+ if (len > OSS_STATUS_STRING_LEN - 1)
+ len = OSS_STATUS_STRING_LEN - 1;
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+}
+
+void OS::oss_change_status_left(const char *str, size_t len) {
+ oss_change_status_string(status_left, str, len);
+ oss_draw_status_line();
+}
+
+void OS::oss_change_status_right(const char *str) {
+ oss_change_status_string(status_right, str, strlen(str));
+ oss_draw_status_line();
+}
+
+int OS::memicmp(char *s1, char *s2, int len) {
+ char *x1, *x2;
+ int i, result;
+
+ x1 = (char *)malloc(len); x2 = (char *)malloc(len);
+
+ if (!x1 || !x2) {
+ glk_set_window(story_win);
+ glk_put_string("memicmp has run out of memory. Quitting.\n");
+ os_waitc();
+ glk_exit();
+ }
+
+ for (i = 0; i < len; i++) {
+ if (Common::isUpper(s1[i]))
+ x1[i] = glk_char_to_lower((unsigned char)s1[i]);
+ else x1[i] = s1[i];
+
+ if (Common::isUpper(s2[i]))
+ x2[i] = glk_char_to_lower((unsigned char)s2[i]);
+ else x2[i] = s2[i];
+ }
+
+ result = memcmp(x1, x2, len);
+ free(x1);
+ free(x2);
+ return result;
+}
+
+void OS::os_flush() {
+ glk_tick();
+}
+
+void OS::os_print(const char *str, size_t len) {
+ int current_status_mode;
+
+ // Decide what to do based on our status mode
+ current_status_mode = os_get_status();
+ if (current_status_mode == OSS_STATUS_MODE_STORY) {
+ oss_put_string_with_hilite(story_win, str, len);
+ } else if (current_status_mode == OSS_STATUS_MODE_STATUS) {
+ const char *p;
+ size_t rem;
+
+ // The string requires some fiddling for the status window
+ for (p = str, rem = len; rem != 0 && *p == '\n'; p++, --rem);
+ if (rem != 0 && p[rem - 1] == '\n')
+ --rem;
+
+ // if that leaves anything, update the statusline
+ if (rem != 0)
+ oss_change_status_left(p, rem);
+ }
+}
+
+void OS::os_expause() {
+ os_printz("(Strike any key to exit...)");
+ os_flush();
+ os_waitc();
+}
+
+int OS::oss_getc_from_window(winid_t win) {
+ static unsigned char buffered_char = 0;
+ int i;
+ event_t ev;
+
+ if (buffered_char != 0) {
+ i = (int)buffered_char;
+ buffered_char = 0;
+ return i;
+ }
+ glk_request_char_event(win);
+ do {
+ glk_select(&ev);
+ if (ev.type == evtype_Arrange)
+ oss_draw_status_line();
+ } while (ev.type != evtype_CharInput);
+ if (ev.val1 == keycode_Return)
+ ev.val1 = '\n';
+ else if (ev.val1 == keycode_Tab)
+ ev.val1 = '\t';
+ if (ev.val1 <= 255)
+ return ((int)ev.val1);
+
+ // We got a special character, so handle it appropriately
+ buffered_char = oss_convert_keystroke_to_tads(ev.val1);
+ return 0;
+}
+
+} // End of namespace TADS2
+} // End of namespace TADS
+} // End of namespace Glk
diff --git a/engines/glk/tads/tads2/os.h b/engines/glk/tads/tads2/os.h
new file mode 100644
index 0000000000..ba0058d98a
--- /dev/null
+++ b/engines/glk/tads/tads2/os.h
@@ -0,0 +1,334 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_TADS_TADS2_OS
+#define GLK_TADS_TADS2_OS
+
+#include "glk/tads/tads.h"
+
+namespace Glk {
+namespace TADS {
+namespace TADS2 {
+
+/**
+ * The character (or characters) which mark the beginning of a special fileref string.
+ * The important thing is that the string be one that is either not allowed in
+ * filenames on your platform or is unlikely to be the first part of a filename.
+ */
+#define OSS_FILEREF_STRING_PREFIX ":"
+
+/**
+ * The character (or characters) which mark the end of a special fileref string.
+ * Using this and OSS_FILEREF_STRING_PREFIX, you should be able to come up with
+ * something which forms an invalid filename
+ */
+#define OSS_FILEREF_STRING_SUFFIX ""
+
+/**
+ * Maximum length of status line text
+ */
+#define OSS_STATUS_STRING_LEN 80
+
+/**
+ * Important note: do not change these values when porting TADS. These
+ * values can be used by games, so they must be the same on all platforms.
+ */
+enum {
+ OS_AFP_OPEN = 1, ///< choose an existing file to open for reading
+ OS_AFP_SAVE = 2 ///< choose a filename for saving to a file
+};
+
+/**
+ * File types.These type codes are used when opening or creating a file,
+ * so that the OS routine can set appropriate file system metadata
+ * to describe or find the file type.
+ *
+ * The type os_filetype_t is defined for documentary purposes; it's
+ * always just an int.
+ */
+enum os_filetype_t {
+ OSFTGAME = 0, ///< a game data file (.gam)
+ OSFTSAVE = 1, ///< a saved game (.sav)
+ OSFTLOG = 2, ///< a transcript (log) file
+ OSFTSWAP = 3, ///< swap file
+ OSFTDATA = 4, ///< user data file (used with the TADS fopen() call)
+ OSFTCMD = 5, ///< QA command/log file
+ OSFTERRS = 6, ///< error message file
+ OSFTTEXT = 7, ///< text file - used for source files
+ OSFTBIN = 8, ///< binary file of unknown type - resources, etc
+ OSFTCMAP = 9, ///< character mapping file
+ OSFTPREF = 10, ///< preferences file
+ OSFTUNK = 11, ///< unknown - as a filter, matches any file type
+ OSFTT3IMG = 12, ///< T3 image file (.t3 - formerly .t3x)
+ OSFTT3OBJ = 13, ///< T3 object file (.t3o)
+ OSFTT3SYM = 14, ///< T3 symbol export file (.t3s)
+ OSFTT3SAV = 15 ///< T3 saved state file (.t3v)
+};
+
+/**
+ * Constants for os_getc() when returning commands. When used for command line
+ * editing, special keys (arrows, END, etc.) should cause os_getc() to return 0,
+ * and return the appropriate CMD_ value on the NEXT call. Hence, os_getc() must
+ * keep the appropriate information around statically for the next call when a
+ * command key is issued.
+ *
+ * The comments indicate which CMD_xxx codes are "translated" codes and which are
+ * "raw"; the difference is that, when a particular keystroke could be interpreted
+ * as two different CMD_xxx codes, one translated and the other raw, os_getc()
+ * should always return the translated version of the key, and os_getc_raw()
+ * should return the raw version.
+ */
+enum KeyCmd {
+ CMD_UP = 1, ///< move up/up arrow (translated)
+ CMD_DOWN = 2, ///< move down/down arrow (translated)
+ CMD_RIGHT = 3, ///< move right/right arrow (translated)
+ CMD_LEFT = 4, ///< move left/left arrow (translated)
+ CMD_END = 5, ///< move cursor to end of line (translated)
+ CMD_HOME = 6, ///< move cursor to start of line (translated)
+ CMD_DEOL = 7, ///< delete to end of line (translated)
+ CMD_KILL = 8, ///< delete entire line (translated)
+ CMD_DEL = 9, ///< delete current character (translated)
+ CMD_SCR = 10, ///< toggle scrollback mode (translated)
+ CMD_PGUP = 11, ///< page up (translated)
+ CMD_PGDN = 12, ///< page down (translated)
+ CMD_TOP = 13, ///< top of file (translated)
+ CMD_BOT = 14, ///< bottom of file (translated)
+ CMD_F1 = 15, ///< function key F1 (raw)
+ CMD_F2 = 16, ///< function key F2 (raw)
+ CMD_F3 = 17, ///< function key F3 (raw)
+ CMD_F4 = 18, ///< function key F4 (raw)
+ CMD_F5 = 19, ///< function key F5 (raw)
+ CMD_F6 = 20, ///< function key F6 (raw)
+ CMD_F7 = 21, ///< function key F7 (raw)
+ CMD_F8 = 22, ///< function key F8 (raw)
+ CMD_F9 = 23, ///< function key F9 (raw)
+ CMD_F10 = 24, ///< function key F10 (raw)
+ CMD_CHOME = 25, ///< control-home (raw)
+ CMD_TAB = 26, ///< tab (translated)
+ CMD_SF2 = 27, ///< shift-F2 (raw)
+ ///< not used (obsolete) - 28
+ CMD_WORD_LEFT = 29, ///< word left (ctrl-left on dos) (translated)
+ CMD_WORD_RIGHT = 30, ///< word right (ctrl-right on dos) (translated)
+ CMD_WORDKILL = 31, ///< delete word right (translated)
+ CMD_EOF = 32, ///< end-of-file (raw)
+ CMD_BREAK = 33, ///< break (Ctrl-C or local equivalent) (translated)
+ CMD_INS = 34, ///< insert key (raw)
+
+ /**
+ * ALT-keys - add alphabetical code to CMD_ALT: ALT-A == CMD_ALT + 0,
+ * ALT-B == CMD_ALT + 1, ALT-C == CMD_ALT + 2, etc
+ *
+ * These keys are all raw (untranslated).
+ */
+ CMD_ALT = 128 ///< start of ALT keys
+};
+
+/**
+ * Status mode codes
+ */
+enum StatusMode {
+ OSS_STATUS_MODE_STORY = 0,
+ OSS_STATUS_MODE_STATUS = 1
+};
+
+typedef Common::SeekableReadStream osfildef;
+
+/**
+ * Operating system compatibility layer
+ */
+class OS : public TADS {
+protected:
+ char status_left[OSS_STATUS_STRING_LEN];
+ char status_right[OSS_STATUS_STRING_LEN];
+ int status_mode;
+protected:
+ /**
+ * Constructor
+ */
+ OS(OSystem *syst, const GlkGameDescription &gameDesc);
+
+ /**
+ * Terminates the game
+ */
+ void os_terminate(int rc);
+
+ /**
+ * \defgroup Type Conversions
+ * @{
+ */
+
+ /**
+ * Change a TADS prompt type (OS_AFP_*) into a Glk prompt type.
+ */
+ glui32 oss_convert_prompt_type(int type);
+
+ /**
+ * Change a TADS file type (OSFT*) into a Glk file type.
+ */
+ glui32 oss_convert_file_type(int type);
+
+ /**
+ * Change a fileref ID (frefid_t) to a special string and put it in the
+ * buffer which is passed to it. The string is given by
+ * OSS_FILEREF_STRING_PREFIX + 'nnnnn' + OSS_FILEREF_STRING_SUFFIX
+ * where 'nnnnn' is the frefid_t pointer converted into a string of decimal
+ * numbers. This is only really practical for 32-bit pointers; if we use
+ * 64-bit pointers I'll have to start using a hash table or use hex
+ * numbers.
+ */
+ glui32 oss_convert_fileref_to_string(frefid_t file_to_convert, char *buffer, int buf_len);
+
+ /**
+ * Turn a filename or a special fileref string into an actual fileref.
+ * Notice that, since Glk doesn't know paths, we take this opportunity to
+ * call oss_check_path, which should do the OS-dependent path changing
+ * in the event that the filename contains path information
+ */
+ frefid_t oss_convert_string_to_fileref(char *buffer, glui32 usage);
+
+ /**
+ * Tell us if the passed string is a hashed fileref or not
+ */
+ bool oss_is_string_a_fileref(char *buffer);
+
+ /**
+ * Change a Glk key into a TADS one, using the CMD_xxx codes
+ */
+ unsigned char oss_convert_keystroke_to_tads(glui32 key);
+
+ /**@}*/
+
+ /**
+ * \defgroup Directory/File methods
+ * @{
+ */
+
+ /**
+ * If a filename contains path information, change dirs to that path.
+ * Returns true if the path was fiddled with
+ */
+ bool oss_check_path(char *filename);
+
+ /**
+ * In case we changed directories in oss_check_path, change back to the
+ * original executable directory
+ */
+ void oss_revert_path();
+
+ /**
+ * Open a stream, given a string, usage, and a filemode. tadsusage is the
+ * TADS filemode (OSFT*); tbusage is either fileusage_TextMode or
+ * fileusage_BinaryMode (from Glk).
+ */
+ osfildef *oss_open_stream(char *buffer, glui32 tadsusage, glui32 tbusage,
+ glui32 fmode, glui32 rock);
+
+ /**
+ * Get a pointer to the root name portion of a filename. This is the part
+ * of the filename after any path or directory prefix. For example, on
+ * Unix, given the string "/home/mjr/deep.gam", this function should return
+ * a pointer to the 'd' in "deep.gam". If the filename doesn't appear to
+ * have a path prefix, it should simply return the argument unchanged.
+ */
+ const char *os_get_root_name(const char *buf) const { return buf; }
+
+ /**@}*/
+
+ /**
+ * \defgroup The main text area print routines
+ * @{
+ */
+
+ /**
+ * Process hilighting codes while printing a string
+ */
+ void oss_put_string_with_hilite(winid_t win, const char *str, size_t len);
+
+ /**
+ * Status line handling
+ */
+ void oss_draw_status_line();
+
+ void oss_change_status_string(char *dest, const char *src, size_t len);
+ void oss_change_status_left(const char *str, size_t len);
+ void oss_change_status_right(const char *str);
+ int os_get_status() const { return status_mode; }
+
+ /**
+ * Flush the output
+ */
+ void os_flush();
+
+ /**
+ * Print a null terminated string
+ */
+ void os_printz(const char *str) { os_print(str, strlen(str)); }
+
+ /**
+ * Print a string
+ */
+ void os_print(const char *str, size_t len);
+
+ /**
+ * Compare two strings
+ */
+ int memicmp(char *s1, char *s2, int len);
+
+ /**@}*/
+
+ /**
+ * \defgroup Input routines
+ * @{
+ */
+
+ /**
+ * Wait for a key to be hit
+ */
+ void os_waitc(void) { os_getc(); }
+
+ /**
+ * Get a character from the keyboard. For extended characters, return 0,
+ * then return the extended key at the next call to this function
+ */
+ int os_getc() {
+ return oss_getc_from_window(story_win);
+ }
+
+ /**
+ * Accept a keystroke in the passed window
+ */
+ int oss_getc_from_window(winid_t win);
+
+
+ /**
+ * Print a message (with os_print) and wait for a key
+ */
+ void os_expause();
+
+ /**@}*/
+};
+
+} // End of namespace TADS2
+} // End of namespace TADS
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/tads/tads2/tads2.cpp b/engines/glk/tads/tads2/tads2.cpp
index 81f7272f85..9c50c20d24 100644
--- a/engines/glk/tads/tads2/tads2.cpp
+++ b/engines/glk/tads/tads2/tads2.cpp
@@ -26,11 +26,46 @@ namespace Glk {
namespace TADS {
namespace TADS2 {
-TADS2::TADS2(OSystem *syst, const GlkGameDescription &gameDesc) : TADS(syst, gameDesc) {
+TADS2::TADS2(OSystem *syst, const GlkGameDescription &gameDesc) : OS(syst, gameDesc) {
}
void TADS2::runGame(Common::SeekableReadStream *gameFile) {
- // TODO
+ errcxdef errctx;
+ errctx.errcxlgc = &errctx;
+ errctx.errcxfp = nullptr;
+ errctx.errcxofs = 0;
+ errctx.errcxappctx = this;
+
+ /* copyright-date-string */
+#ifdef T2_COPYRIGHT_NOTICE
+ trdptf("%s - A %s TADS %s Interpreter.\n",
+ G_tads_oem_app_name, G_tads_oem_display_mode,
+ TADS_RUNTIME_VERSION);
+ trdptf("%sopyright (c) 1993, 2012 by Michael J. Roberts.\n",
+ G_tads_oem_copyright_prefix ? "TADS c" : "C");
+ trdptf("%s\n", G_tads_oem_author);
+#endif
+
+ trdmain1(&errctx);
+
+ // pause before exiting if the OS desires it
+ os_expause();
+}
+
+void TADS2::trdmain1(errcxdef *errctx) {
+
+}
+
+void TADS2::trdptf(const char *fmt, ...) {
+ va_list va;
+
+ // format the string */
+ va_start(va, fmt);
+ Common::String msg = Common::String::vformat(fmt, va);
+ va_end(va);
+
+ // print the formatted buffer
+ os_printz(msg);
}
} // End of namespace TADS2
diff --git a/engines/glk/tads/tads2/tads2.h b/engines/glk/tads/tads2/tads2.h
index e07b5c8bc4..2c799a36e7 100644
--- a/engines/glk/tads/tads2/tads2.h
+++ b/engines/glk/tads/tads2/tads2.h
@@ -23,7 +23,8 @@
#ifndef GLK_TADS_TADS2
#define GLK_TADS_TADS2
-#include "glk/tads/tads.h"
+#include "glk/tads/tads2/os.h"
+#include "glk/tads/tads2/ler.h"
namespace Glk {
namespace TADS {
@@ -32,7 +33,10 @@ namespace TADS2 {
/**
* TADS 2 game interpreter
*/
-class TADS2 : public TADS {
+class TADS2 : public OS {
+private:
+ // STUBS
+ void os_printz(const Common::String &s) {}
public:
/**
* Constructor
@@ -48,8 +52,17 @@ public:
* Returns the running interpreter type
*/
virtual InterpreterType getInterpreterType() const override { return INTERPRETER_TADS2; }
+
+ void trdmain1(errcxdef *errctx);
+
+ /**
+ * printf-style formatting
+ */
+ void trdptf(const char *fmt, ...);
};
+typedef TADS2 appctxdef;
+
} // End of namespace TADS2
} // End of namespace TADS
} // End of namespace Glk