diff options
author | Paul Gilbert | 2018-11-29 21:37:31 -0800 |
---|---|---|
committer | Paul Gilbert | 2018-12-08 19:05:59 -0800 |
commit | 41b62ab00db1d1730b1d61b77fda0df2c65753c0 (patch) | |
tree | 4540fcc66b85971001943211b04bd6f6f62038a9 /engines/glk/tads | |
parent | 5ab65b0954ba69ed31edfdbd563a549f7da692af (diff) | |
download | scummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.tar.gz scummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.tar.bz2 scummvm-rg350-41b62ab00db1d1730b1d61b77fda0df2c65753c0.zip |
GLK: TADS: Add a number of GLK interface methods
Diffstat (limited to 'engines/glk/tads')
-rw-r--r-- | engines/glk/tads/tads.cpp | 21 | ||||
-rw-r--r-- | engines/glk/tads/tads.h | 2 | ||||
-rw-r--r-- | engines/glk/tads/tads2/ler.cpp | 69 | ||||
-rw-r--r-- | engines/glk/tads/tads2/ler.h | 49 | ||||
-rw-r--r-- | engines/glk/tads/tads2/os.cpp | 309 | ||||
-rw-r--r-- | engines/glk/tads/tads2/os.h | 334 | ||||
-rw-r--r-- | engines/glk/tads/tads2/tads2.cpp | 39 | ||||
-rw-r--r-- | engines/glk/tads/tads2/tads2.h | 17 |
8 files changed, 758 insertions, 82 deletions
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 |