GLK: TADS: Add a number of GLK interface methods

This commit is contained in:
Paul Gilbert 2018-11-29 21:37:31 -08:00 committed by Paul Gilbert
parent 5ab65b0954
commit 41b62ab00d
11 changed files with 761 additions and 84 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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:

View File

@ -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,54 +127,25 @@ 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);
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
}
#endif /* DEBUG */
#ifdef ERR_NO_MACRO
void errsign(errcxdef *ctx, int e, char *facility) {
strncpy(ctx->errcxptr->errfac, facility, ERRFACMAX);
ctx->errcxptr->errfac[ERRFACMAX] = '\0';
ctx->errcxofs = 0;
longjmp(ctx->errcxptr->errbuf, e);
}
void errsigf(errcxdef *ctx, char *facility, int e) {
errargc(ctx, 0);
errsign(ctx, e, facility);
}
char *errstr(errcxdef *ctx, const char *str, int len) {
char *ret = &ctx->errcxbuf[ctx->errcxofs];
memcpy(ret, str, (size_t)len);
ret[len] = '\0';
ctx->errcxofs += len + 1;
return(ret);
}
void errrse1(errcxdef *ctx, errdef *fr) {
errargc(ctx, fr->erraac);
memcpy(ctx->errcxptr->erraav, fr->erraav,
(size_t)(fr->erraac * sizeof(erradef)));
errsign(ctx, fr->errcode, fr->errfac);
}
void errlogn(errcxdef *ctx, int err, char *facility) {
ctx->errcxofs = 0;
(*ctx->errcxlog)(ctx->errcxlgc, facility, err, ctx->errcxptr->erraac,
ctx->errcxptr->erraav);
}
void errlogf(errcxdef *ctx, char *facility, int err) {
errargc(ctx, 0);
errlogn(ctx, err, facility);
}
#endif /* ERR_NO_MACRO */
} // End of namespace TADS2
} // End of namespace TADS

View File

@ -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);

View File

@ -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

334
engines/glk/tads/tads2/os.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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