aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/glk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/glk/glk.cpp')
-rw-r--r--engines/glk/glk.cpp1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/engines/glk/glk.cpp b/engines/glk/glk.cpp
new file mode 100644
index 0000000000..77fb242b8b
--- /dev/null
+++ b/engines/glk/glk.cpp
@@ -0,0 +1,1174 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software{} you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation{} either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY{} without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program{} if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/glk.h"
+#include "glk/conf.h"
+#include "glk/events.h"
+#include "glk/picture.h"
+#include "glk/streams.h"
+#include "glk/unicode.h"
+#include "glk/windows.h"
+#include "glk/window_graphics.h"
+#include "glk/window_text_buffer.h"
+#include "glk/window_pair.h"
+
+
+namespace Gargoyle {
+
+Glk::Glk(OSystem *syst, const GargoyleGameDescription *gameDesc) :
+ GargoyleEngine(syst, gameDesc), _gliFirstEvent(false) {
+ // Set uppercase/lowercase tables
+ int ix, res;
+ for (ix = 0; ix < 256; ix++) {
+ _charToupperTable[ix] = ix;
+ _charTolowerTable[ix] = ix;
+ }
+
+ for (ix = 0; ix < 256; ix++) {
+ if (ix >= 'A' && ix <= 'Z')
+ res = ix + ('a' - 'A');
+ else if (ix >= 0xC0 && ix <= 0xDE && ix != 0xD7)
+ res = ix + 0x20;
+ else
+ res = 0;
+
+ if (res) {
+ _charTolowerTable[ix] = res;
+ _charToupperTable[res] = ix;
+ }
+ }
+}
+
+void Glk::glk_exit(void) {
+ glk_put_string("[ press any key to exit ]");
+ _events->waitForPress();
+
+ quitGame();
+}
+
+void Glk::glk_set_interrupt_handler(void(*func)(void)) {
+ // This library doesn't handle interrupts.
+}
+
+void Glk::glk_tick(void) {
+ // Nothing needed
+}
+
+glui32 Glk::glk_gestalt(glui32 id, glui32 val) {
+ return glk_gestalt_ext(id, val, nullptr, 0);
+}
+
+glui32 Glk::glk_gestalt_ext(glui32 id, glui32 val, glui32 *arr, glui32 arrlen) {
+ switch (id) {
+ case gestalt_Version:
+ return 0x00000703;
+
+ case gestalt_LineInput:
+ if (val >= 32 && val < 0x10ffff)
+ return true;
+ else
+ return false;
+
+ case gestalt_CharInput:
+ if (val >= 32 && val < 0x10ffff)
+ return true;
+ else if (val == keycode_Return)
+ return true;
+ else
+ return false;
+
+ case gestalt_CharOutput:
+ if (val >= 32 && val < 0x10ffff) {
+ if (arr && arrlen >= 1)
+ arr[0] = 1;
+ return gestalt_CharOutput_ExactPrint;
+ } else {
+ // cheaply, we don't do any translation of printed characters,
+ // so the output is always one character even if it's wrong.
+ if (arr && arrlen >= 1)
+ arr[0] = 1;
+ return gestalt_CharOutput_CannotPrint;
+ }
+
+ case gestalt_MouseInput:
+ if (val == wintype_TextGrid)
+ return true;
+ if (val == wintype_Graphics)
+ return true;
+ return false;
+
+ case gestalt_Graphics:
+ case gestalt_GraphicsTransparency:
+ return g_conf->_graphics;
+
+ case gestalt_DrawImage:
+ if (val == wintype_TextBuffer)
+ return g_conf->_graphics;
+ if (val == wintype_Graphics)
+ return g_conf->_graphics;
+ return false;
+
+ case gestalt_Sound:
+ case gestalt_SoundVolume:
+ case gestalt_SoundMusic:
+ case gestalt_SoundNotify:
+ return g_conf->_sound;
+
+ case gestalt_LineTerminatorKey:
+ return Window::checkTerminator(val);
+
+ case gestalt_Timer:
+ case gestalt_Unicode:
+ case gestalt_UnicodeNorm:
+ case gestalt_Hyperlinks:
+ case gestalt_HyperlinkInput:
+ case gestalt_LineInputEcho:
+ case gestalt_LineTerminators:
+ case gestalt_DateTime:
+ case gestalt_GarglkText:
+ return true;
+
+ case gestalt_Sound2:
+ default:
+ return false;
+ }
+}
+
+unsigned char Glk::glk_char_to_lower(unsigned char ch) {
+ return _charTolowerTable[ch];
+}
+
+unsigned char Glk::glk_char_to_upper(unsigned char ch) {
+ return _charToupperTable[ch];
+}
+
+winid_t Glk::glk_window_get_root(void) const {
+ return _windows->getRoot();
+}
+
+winid_t Glk::glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, glui32 rock) const {
+ return _windows->windowOpen(split, method, size, wintype, rock);
+}
+
+void Glk::glk_window_close(winid_t win, stream_result_t *result) {
+ if (win) {
+ _windows->windowClose(win, result);
+ } else {
+ warning("glk_window_close: invalid ref");
+ }
+}
+
+void Glk::glk_window_get_size(winid_t win, glui32 *width, glui32 *height) {
+ if (win) {
+ win->getSize(width, height);
+ } else {
+ warning("window_get_size: invalid ref");
+ }
+}
+
+void Glk::glk_window_set_arrangement(winid_t win, glui32 method, glui32 size, winid_t keywin) {
+ if (win) {
+ win->setArrangement(method, size, keywin);
+ } else {
+ warning("window_set_arrangement: invalid ref");
+ }
+}
+
+void Glk::glk_window_get_arrangement(winid_t win, glui32 *method,
+ glui32 *size, winid_t *keyWin) {
+ if (win) {
+ win->getArrangement(method, size, keyWin);
+ } else {
+ warning("window_get_arrangement: invalid ref");
+ }
+}
+
+winid_t Glk::glk_window_iterate(winid_t win, glui32 *rock) {
+ win = win ? win->_next : _windows->getRoot();
+
+ if (win) {
+ if (rock)
+ *rock = win->_rock;
+ return win;
+ }
+
+ if (rock)
+ *rock = 0;
+
+ return nullptr;
+}
+
+glui32 Glk::glk_window_get_rock(winid_t win) {
+ if (win) {
+ return win->_rock;
+ } else {
+ warning("window_get_rock: invalid ref.");
+ return 0;
+ }
+}
+
+glui32 Glk::glk_window_get_type(winid_t win) {
+ if (win) {
+ return win->_type;
+ } else {
+ warning("window_get_parent: invalid ref");
+ return 0;
+ }
+}
+
+winid_t Glk::glk_window_get_parent(winid_t win) {
+ if (!win) {
+ warning("window_get_parent: invalid ref");
+ return 0;
+ }
+
+ return win->_parent;
+}
+
+winid_t Glk::glk_window_get_sibling(winid_t win) {
+ if (!win) {
+ warning("window_get_sibling: invalid ref");
+ return nullptr;
+ }
+
+ PairWindow *parentWin = dynamic_cast<PairWindow *>(win->_parent);
+ if (!parentWin)
+ return nullptr;
+
+ if (parentWin->_child1 == win)
+ return parentWin->_child2;
+ else if (parentWin->_child2 == win)
+ return parentWin->_child1;
+
+ return nullptr;
+}
+
+void Glk::glk_window_clear(winid_t win) {
+ if (!win) {
+ warning("window_clear: invalid ref");
+ } else {
+ if (win->_lineRequest || win->_lineRequestUni) {
+ if (g_conf->_safeClicks && _events->_forceClick) {
+ glk_cancel_line_event(win, nullptr);
+ _events->_forceClick = false;
+
+ win->clear();
+ } else {
+ warning("window_clear: window has pending line request");
+ return;
+ }
+ }
+
+ // Clear the window
+ win->clear();
+ }
+}
+
+void Glk::glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos) {
+ if (win) {
+ win->moveCursor(Point(xpos, ypos));
+ } else {
+ warning("window_move_cursor: invalid ref");
+ }
+}
+
+strid_t Glk::glk_window_get_stream(winid_t win) {
+ if (win) {
+ return win->_stream;
+ } else {
+ warning("window_get_stream: invalid ref");
+ return nullptr;
+ }
+}
+
+void Glk::glk_window_set_echo_stream(winid_t win, strid_t str) {
+ if (win) {
+ win->_echoStream = str;
+ } else {
+ warning("window_set_echo_stream: invalid window id");
+ }
+}
+
+strid_t Glk::glk_window_get_echo_stream(winid_t win) {
+ if (!win) {
+ warning("window_get_echo_stream: invalid ref");
+ return nullptr;
+ }
+
+ return win->_echoStream;
+}
+
+void Glk::glk_set_window(winid_t win) {
+ _streams->setCurrent(win ? win->_stream : nullptr);
+}
+
+strid_t Glk::glk_stream_open_file(frefid_t fileref, FileMode fmode, glui32 rock) {
+ return _streams->openFileStream(fileref, fmode, rock, false);
+}
+
+strid_t Glk::glk_stream_open_memory(char *buf, glui32 buflen, FileMode fmode, glui32 rock) {
+ return _streams->openMemoryStream(buf, buflen, fmode, rock, false);
+}
+
+void Glk::glk_stream_close(strid_t str, stream_result_t *result) {
+ str->close(result);
+}
+
+strid_t Glk::glk_stream_iterate(strid_t str, glui32 *rockptr) const {
+ return str ? str->getNext(rockptr) : _streams->getFirst(rockptr);
+}
+
+glui32 Glk::glk_stream_get_rock(strid_t str) const {
+ if (!str) {
+ warning("stream_get_rock: invalid ref");
+ return 0;
+ }
+
+ return str->getRock();
+}
+
+void Glk::glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekMode) {
+ if (str) {
+ str->setPosition(pos, seekMode);
+ } else {
+ warning("stream_set_position: invalid ref");
+ }
+}
+
+glui32 Glk::glk_stream_get_position(strid_t str) const {
+ if (str) {
+ return str->getPosition();
+ } else {
+ warning("stream_get_position: invalid ref");
+ return 0;
+ }
+}
+
+void Glk::glk_stream_set_current(strid_t str) {
+ _streams->setCurrent(str);
+}
+
+strid_t Glk::glk_stream_get_current(void) {
+ return _streams->getCurrent();
+}
+
+void Glk::glk_put_char(unsigned char ch) {
+ _streams->getCurrent()->putChar(ch);
+}
+
+void Glk::glk_put_char_stream(strid_t str, unsigned char ch) {
+ if (str) {
+ str->putChar(ch);
+ } else {
+ warning("put_char_stream: invalid ref");
+ }
+}
+
+void Glk::glk_put_string(const char *s) {
+ _streams->getCurrent()->putBuffer(s, strlen(s));
+}
+
+void Glk::glk_put_string_stream(strid_t str, const char *s) {
+ str->putBuffer(s, strlen(s));
+}
+
+void Glk::glk_put_buffer(char *buf, glui32 len) {
+ _streams->getCurrent()->putBuffer(buf, len);
+}
+
+void Glk::glk_put_buffer_stream(strid_t str, const char *buf, glui32 len) {
+ str->putBuffer(buf, len);
+}
+
+void Glk::glk_set_style(glui32 styl) {
+ _streams->getCurrent()->setStyle(styl);
+}
+
+void Glk::glk_set_style_stream(strid_t str, glui32 styl) {
+ if (str) {
+ str->setStyle(styl);
+ } else {
+ warning("set_style_stream: invalid ref");
+ }
+}
+
+glsi32 Glk::glk_get_char_stream(strid_t str) {
+ if (str) {
+ return str->getChar();
+ } else {
+ warning("get_char_stream: invalid ref");
+ return -1;
+ }
+}
+
+glui32 Glk::glk_get_line_stream(strid_t str, char *buf, glui32 len) {
+ if (str) {
+ return str->getLine(buf, len);
+ } else {
+ warning("get_line_stream: invalid ref");
+ return 0;
+ }
+}
+
+glui32 Glk::glk_get_buffer_stream(strid_t str, char *buf, glui32 len) {
+ if (str) {
+ return str->getBuffer(buf, len);
+ } else {
+ warning("get_line_stream: invalid ref");
+ return 0;
+ }
+}
+
+void Glk::glk_stylehint_set(glui32 wintype, glui32 style, glui32 hint, glsi32 val) {
+ WindowStyle *styles;
+ bool p, b, i;
+
+ if (wintype == wintype_AllTypes) {
+ glk_stylehint_set(wintype_TextGrid, style, hint, val);
+ glk_stylehint_set(wintype_TextBuffer, style, hint, val);
+ return;
+ }
+
+ if (wintype == wintype_TextGrid)
+ styles = g_conf->_gStyles;
+ else if (wintype == wintype_TextBuffer)
+ styles = g_conf->_tStyles;
+ else
+ return;
+
+ if (!g_conf->_styleHint)
+ return;
+
+ switch (hint) {
+ case stylehint_TextColor:
+ styles[style].fg[0] = (val >> 16) & 0xff;
+ styles[style].fg[1] = (val >> 8) & 0xff;
+ styles[style].fg[2] = (val) & 0xff;
+ break;
+
+ case stylehint_BackColor:
+ styles[style].bg[0] = (val >> 16) & 0xff;
+ styles[style].bg[1] = (val >> 8) & 0xff;
+ styles[style].bg[2] = (val) & 0xff;
+ break;
+
+ case stylehint_ReverseColor:
+ styles[style].reverse = (val != 0);
+ break;
+
+ case stylehint_Proportional:
+ if (wintype == wintype_TextBuffer) {
+ p = val > 0;
+ b = styles[style].isBold();
+ i = styles[style].isItalic();
+ styles[style].font = WindowStyle::makeFont(p, b, i);
+ }
+ break;
+
+ case stylehint_Weight:
+ p = styles[style].isProp();
+ b = val > 0;
+ i = styles[style].isItalic();
+ styles[style].font = WindowStyle::makeFont(p, b, i);
+ break;
+
+ case stylehint_Oblique:
+ p = styles[style].isProp();
+ b = styles[style].isBold();
+ i = val > 0;
+ styles[style].font = WindowStyle::makeFont(p, b, i);
+ break;
+ }
+
+ if (wintype == wintype_TextBuffer && style == style_Normal && hint == stylehint_BackColor) {
+ memcpy(g_conf->_windowColor, styles[style].bg, 3);
+ }
+
+ if (wintype == wintype_TextBuffer && style == style_Normal && hint == stylehint_TextColor) {
+ memcpy(g_conf->_moreColor, styles[style].fg, 3);
+ memcpy(g_conf->_caretColor, styles[style].fg, 3);
+ }
+}
+
+void Glk::glk_stylehint_clear(glui32 wintype, glui32 style, glui32 hint) {
+ WindowStyle *styles;
+ const WindowStyle *defaults;
+
+ if (wintype == wintype_AllTypes) {
+ glk_stylehint_clear(wintype_TextGrid, style, hint);
+ glk_stylehint_clear(wintype_TextBuffer, style, hint);
+ return;
+ }
+
+ if (wintype == wintype_TextGrid) {
+ styles = g_conf->_gStyles;
+ defaults = g_conf->_gStylesDefault;
+ } else if (wintype == wintype_TextBuffer) {
+ styles = g_conf->_tStyles;
+ defaults = g_conf->_tStylesDefault;
+ } else {
+ return;
+ }
+
+ if (!g_conf->_styleHint)
+ return;
+
+ switch (hint) {
+ case stylehint_TextColor:
+ styles[style].fg[0] = defaults[style].fg[0];
+ styles[style].fg[1] = defaults[style].fg[1];
+ styles[style].fg[2] = defaults[style].fg[2];
+ break;
+
+ case stylehint_BackColor:
+ styles[style].bg[0] = defaults[style].bg[0];
+ styles[style].bg[1] = defaults[style].bg[1];
+ styles[style].bg[2] = defaults[style].bg[2];
+ break;
+
+ case stylehint_ReverseColor:
+ styles[style].reverse = defaults[style].reverse;
+ break;
+
+ case stylehint_Proportional:
+ case stylehint_Weight:
+ case stylehint_Oblique:
+ styles[style].font = defaults[style].font;
+ break;
+ }
+}
+
+glui32 Glk::glk_style_distinguish(winid_t win, glui32 style1, glui32 style2) {
+ const WindowStyle *styles = win->getStyles();
+ if (!styles)
+ return false;
+
+ return styles[style1] == styles[style2] ? 0 : 1;
+}
+
+bool Glk::glk_style_measure(winid_t win, glui32 style, glui32 hint, glui32 *result) {
+ const WindowStyle *styles = win->getStyles();
+ if (!styles)
+ return false;
+
+ switch (hint) {
+ case stylehint_Indentation:
+ case stylehint_ParaIndentation:
+ *result = 0;
+ break;
+
+ case stylehint_Justification:
+ *result = stylehint_just_LeftFlush;
+ break;
+
+ case stylehint_Size:
+ *result = 1;
+ break;
+
+ case stylehint_Weight:
+ *result =
+ (styles[style].font == PROPB || styles[style].font == PROPZ ||
+ styles[style].font == MONOB || styles[style].font == MONOZ);
+ break;
+
+ case stylehint_Oblique:
+ *result =
+ (styles[style].font == PROPI || styles[style].font == PROPZ ||
+ styles[style].font == MONOI || styles[style].font == MONOZ);
+ break;
+
+ case stylehint_Proportional:
+ *result =
+ (styles[style].font == PROPR || styles[style].font == PROPI ||
+ styles[style].font == PROPB || styles[style].font == PROPZ);
+ break;
+
+ case stylehint_TextColor:
+ *result =
+ (styles[style].fg[0] << 16) | (styles[style].fg[1] << 8) | (styles[style].fg[2]);
+ break;
+
+ case stylehint_BackColor:
+ *result =
+ (styles[style].bg[0] << 16) | (styles[style].bg[1] << 8) | (styles[style].bg[2]);
+ break;
+
+ case stylehint_ReverseColor:
+ *result = styles[style].reverse;
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+frefid_t Glk::glk_fileref_create_temp(glui32 usage, glui32 rock) {
+ return _streams->createTemp(usage, rock);
+}
+
+frefid_t Glk::glk_fileref_create_by_name(glui32 usage, const char *name, glui32 rock) {
+ // Take out all dangerous characters
+ Common::String tempName(name);
+ for (uint idx = 0; idx < tempName.size(); ++idx) {
+ if (tempName[idx] == '/' || tempName[idx] == '\\' || tempName[idx] == ':')
+ tempName.setChar(idx, '-');
+ }
+
+ return _streams->createRef(tempName, usage, rock);
+}
+
+frefid_t Glk::glk_fileref_create_by_prompt(glui32 usage, FileMode fmode, glui32 rock) {
+ return _streams->createByPrompt(usage, fmode, rock);
+}
+
+frefid_t Glk::glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) {
+ if (!fref) {
+ warning("fileref_create_from_fileref: invalid ref");
+ return nullptr;
+ } else {
+ return _streams->createFromRef(fref, usage, rock);
+ }
+}
+
+void Glk::glk_fileref_destroy(frefid_t fref) {
+ _streams->deleteRef(fref);
+}
+
+frefid_t Glk::glk_fileref_iterate(frefid_t fref, glui32 *rockptr) {
+ return _streams->iterate(fref, rockptr);
+}
+
+glui32 Glk::glk_fileref_get_rock(frefid_t fref) {
+ if (!fref) {
+ warning("fileref_get_rock: invalid ref.");
+ return 0;
+ } else {
+ return fref->_rock;
+ }
+}
+
+void Glk::glk_fileref_delete_file(frefid_t fref) {
+ fref->deleteFile();
+}
+
+glui32 Glk::glk_fileref_does_file_exist(frefid_t fref) {
+ return fref->exists();
+}
+
+void Glk::glk_select(event_t *event) {
+ if (!_gliFirstEvent) {
+ _windows->inputGuessFocus();
+ _gliFirstEvent = true;
+ }
+
+ _events->getEvent(event, false);
+}
+
+void Glk::glk_select_poll(event_t *event) {
+ if (!_gliFirstEvent) {
+ _windows->inputGuessFocus();
+ _gliFirstEvent = true;
+ }
+
+ _events->getEvent(event, true);
+}
+
+void Glk::glk_request_timer_events(glui32 millisecs) {
+ _events->setTimerInterval(millisecs);
+}
+
+void Glk::glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen) {
+ if (!win) {
+ warning("request_line_event: invalid ref");
+ } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
+ || win->_lineRequestUni) {
+ warning("request_line_event: window already has keyboard request");
+ } else {
+ win->requestLineEvent(buf, maxlen, initlen);
+ }
+}
+
+void Glk::glk_request_char_event(winid_t win) {
+ if (!win) {
+ warning("request_char_event: invalid ref");
+ } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
+ || win->_lineRequestUni) {
+ warning("request_char_event: window already has keyboard request");
+ } else {
+ win->requestCharEvent();
+ }
+}
+
+void Glk::glk_request_mouse_event(winid_t win) {
+ if (!win) {
+ warning("request_mouse_event: invalid ref");
+ } else {
+ win->requestMouseEvent();
+ }
+}
+
+void Glk::glk_cancel_line_event(winid_t win, event_t *event) {
+ if (!win) {
+ warning("cancel_line_event: invalid ref");
+ } else {
+ win->cancelLineEvent(event);
+ }
+}
+
+void Glk::glk_cancel_char_event(winid_t win) {
+ if (!win) {
+ warning("glk_cancel_char_event: invalid ref");
+ } else {
+ win->cancelCharEvent();
+ }
+}
+
+void Glk::glk_cancel_mouse_event(winid_t win) {
+ if (!win) {
+ warning("cancel_mouse_event: invalid ref");
+ } else {
+ win->cancelMouseEvent();
+ }
+}
+
+void Glk::glk_set_echo_line_event(winid_t win, glui32 val) {
+ if (!win) {
+ warning("set_echo_line_event: invalid ref");
+ } else {
+ win->setEchoLineEvent(val);
+ }
+}
+
+void Glk::glk_set_terminators_line_event(winid_t win, glui32 *keycodes, glui32 count) {
+ if (!win) {
+ warning("set_terminators_line_event: invalid ref");
+ } else {
+ win->setTerminatorsLineEvent(keycodes, count);
+ }
+}
+
+glui32 Glk::glk_buffer_to_lower_case_uni(glui32 *buf, glui32 len, glui32 numchars) {
+ return bufferChangeCase(buf, len, numchars, CASE_LOWER, COND_ALL, true);
+}
+
+glui32 Glk::glk_buffer_to_upper_case_uni(glui32 *buf, glui32 len, glui32 numchars) {
+ return bufferChangeCase(buf, len, numchars, CASE_UPPER, COND_ALL, true);
+}
+
+glui32 Glk::glk_buffer_to_title_case_uni(glui32 *buf, glui32 len,
+ glui32 numchars, glui32 lowerrest) {
+ return bufferChangeCase(buf, len, numchars, CASE_TITLE, COND_LINESTART, lowerrest);
+}
+
+void Glk::glk_put_char_uni(glui32 ch) {
+ _streams->getCurrent()->putCharUni(ch);
+}
+
+void Glk::glk_put_string_uni(glui32 *s) {
+ _streams->getCurrent()->putBufferUni(s, strlen_uni(s));
+}
+
+void Glk::glk_put_buffer_uni(glui32 *buf, glui32 len) {
+ _streams->getCurrent()->putBufferUni(buf, len);
+}
+
+void Glk::glk_put_char_stream_uni(strid_t str, glui32 ch) {
+ if (str) {
+ str->putCharUni(ch);
+ } else {
+ warning("put_char_stream_uni: invalid ref");
+ }
+}
+
+void Glk::glk_put_string_stream_uni(strid_t str, const glui32 *s) {
+ if (str) {
+ str->putBufferUni(s, strlen_uni(s));
+ } else {
+ warning("put_string_stream_uni: invalid ref");
+ }
+}
+
+void Glk::glk_put_buffer_stream_uni(strid_t str, const glui32 *buf, glui32 len) {
+ if (str) {
+ str->putBufferUni(buf, len);
+ } else {
+ warning("put_buffer_stream_uni: invalid ref");
+ }
+}
+
+glsi32 Glk::glk_get_char_stream_uni(strid_t str) {
+ if (str) {
+ return str->getCharUni();
+ } else {
+ warning("get_char_stream_uni: invalid ref");
+ return -1;
+ }
+}
+
+glui32 Glk::glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len) {
+ if (str) {
+ return str->getBufferUni(buf, len);
+ } else {
+ warning("get_buffer_stream_uni: invalid ref");
+ return 0;
+ }
+}
+
+glui32 Glk::glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len) {
+ if (str) {
+ return str->getLineUni(buf, len);
+ } else {
+ warning("get_line_stream_uni: invalid ref");
+ return (glui32) - 1;
+ }
+}
+
+strid_t Glk::glk_stream_open_file_uni(frefid_t fileref, FileMode fmode, glui32 rock) {
+ return _streams->openFileStream(fileref, fmode, rock, true);
+}
+
+strid_t Glk::glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, FileMode fmode, glui32 rock) {
+ return _streams->openMemoryStream(buf, buflen, fmode, rock, true);
+}
+
+void Glk::glk_request_char_event_uni(winid_t win) {
+ if (!win) {
+ warning("request_char_event_uni: invalid ref");
+ } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
+ || win->_lineRequestUni) {
+ warning("request_char_event_uni: window already has keyboard request");
+ } else {
+ win->requestCharEvent();
+ }
+}
+
+void Glk::glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen) {
+ if (!win) {
+ warning("request_line_event_uni: invalid ref");
+ } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
+ || win->_lineRequestUni) {
+ warning("request_line_event_uni: window already has keyboard request");
+ } else {
+ win->requestLineEventUni(buf, maxlen, initlen);
+ }
+}
+
+glui32 Glk::glk_buffer_canon_decompose_uni(glui32 *buf, glui32 len,
+ glui32 numchars) {
+ // TODO
+ return 0;
+}
+
+glui32 Glk::glk_buffer_canon_normalize_uni(glui32 *buf, glui32 len, glui32 numchars) {
+ return 0;
+}
+
+glui32 Glk::glk_image_draw(winid_t win, glui32 image, glsi32 val1, glsi32 val2) {
+ if (!win) {
+ warning("image_draw: invalid ref");
+ } else if (g_conf->_graphics) {
+ TextBufferWindow *textWin = dynamic_cast<TextBufferWindow *>(win);
+ GraphicsWindow *gfxWin = dynamic_cast<GraphicsWindow *>(win);
+
+ if (textWin)
+ textWin->drawPicture(image, val1, false, 0, 0);
+ else if (gfxWin)
+ gfxWin->drawPicture(image, val1, val2, false, 0, 0);
+ }
+
+ return false;
+}
+
+glui32 Glk::glk_image_draw_scaled(winid_t win, glui32 image, glsi32 val1, glsi32 val2,
+ glui32 width, glui32 height) {
+ if (!win) {
+ warning("image_draw_scaled: invalid ref");
+ } else if (g_conf->_graphics) {
+ TextBufferWindow *textWin = dynamic_cast<TextBufferWindow *>(win);
+ GraphicsWindow *gfxWin = dynamic_cast<GraphicsWindow *>(win);
+
+ if (textWin)
+ textWin->drawPicture(image, val1, true, width, height);
+ else if (gfxWin)
+ gfxWin->drawPicture(image, val1, val2, true, width, height);
+ }
+
+ return false;
+}
+
+glui32 Glk::glk_image_get_info(glui32 image, glui32 *width, glui32 *height) {
+ if (!g_conf->_graphics)
+ return false;
+
+ Picture *pic = Picture::load(image);
+ if (!pic)
+ return false;
+
+ if (width)
+ *width = pic->w;
+ if (height)
+ *height = pic->h;
+
+ return true;
+}
+
+void Glk::glk_window_flow_break(winid_t win) {
+ if (!win) {
+ warning("window_erase_rect: invalid ref");
+ } else {
+ win->flowBreak();
+ }
+}
+
+void Glk::glk_window_erase_rect(winid_t win, glsi32 left, glsi32 top, glui32 width, glui32 height) {
+ if (!win) {
+ warning("window_erase_rect: invalid ref");
+ } else {
+ win->eraseRect(false, Rect(left, top, left + width, top + height));
+ }
+}
+
+void Glk::glk_window_fill_rect(winid_t win, glui32 color, glsi32 left, glsi32 top,
+ glui32 width, glui32 height) {
+ if (!win) {
+ warning("window_fill_rect: invalid ref");
+ } else {
+ win->eraseRect(color, Rect(left, top, left + width, top + height));
+ }
+}
+
+void Glk::glk_window_set_background_color(winid_t win, glui32 color) {
+ if (!win) {
+ warning("window_set_background_color: invalid ref");
+ } else {
+ win->setBackgroundColor(color);
+ }
+}
+
+schanid_t Glk::glk_schannel_create(glui32 rock) {
+ // TODO
+ return nullptr;
+}
+
+void Glk::glk_schannel_destroy(schanid_t chan) {
+ // TODO
+}
+
+schanid_t Glk::glk_schannel_iterate(schanid_t chan, glui32 *rockptr) {
+ // TODO
+ return nullptr;
+}
+
+glui32 Glk::glk_schannel_get_rock(schanid_t chan) {
+ // TODO
+ return 0;
+}
+
+glui32 Glk::glk_schannel_play(schanid_t chan, glui32 snd) {
+ // TODO
+ return 0;
+}
+
+glui32 Glk::glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify) {
+ // TODO
+ return 0;
+}
+
+void Glk::glk_schannel_stop(schanid_t chan) {
+ // TODO
+}
+
+void Glk::glk_schannel_set_volume(schanid_t chan, glui32 vol) {
+ // TODO
+}
+
+void Glk::glk_sound_load_hint(glui32 snd, glui32 flag) {
+ // TODO
+}
+
+schanid_t Glk::glk_schannel_create_ext(glui32 rock, glui32 volume) {
+ // TODO
+ return nullptr;
+}
+
+glui32 Glk::glk_schannel_play_multi(schanid_t *chanarray, glui32 chancount,
+ glui32 *sndarray, glui32 soundcount, glui32 notify) {
+ // TODO
+ return 0;
+}
+
+void Glk::glk_schannel_pause(schanid_t chan) {
+ // TODO
+}
+
+void Glk::glk_schannel_unpause(schanid_t chan) {
+ // TODO
+}
+
+void Glk::glk_schannel_set_volume_ext(schanid_t chan, glui32 vol,
+ glui32 duration, glui32 notify) {
+ // TODO
+}
+
+void Glk::glk_set_hyperlink(glui32 linkval) {
+ _streams->getCurrent()->setHyperlink(linkval);
+}
+
+void Glk::glk_set_hyperlink_stream(strid_t str, glui32 linkval) {
+ if (str)
+ str->setHyperlink(linkval);
+}
+
+void Glk::glk_request_hyperlink_event(winid_t win) {
+ if (!win) {
+ warning("request_hyperlink_event: invalid ref");
+ } else {
+ win->requestHyperlinkEvent();
+ }
+}
+
+void Glk::glk_cancel_hyperlink_event(winid_t win) {
+ if (win) {
+ win->cancelHyperlinkEvent();
+ } else {
+ warning("cancel_hyperlink_event: invalid ref");
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Glk::glk_current_time(glktimeval_t *time) {
+ TimeAndDate td;
+ *time = td;
+}
+
+glsi32 Glk::glk_current_simple_time(glui32 factor) {
+ assert(factor);
+ TimeAndDate td;
+
+ return td / factor;
+}
+
+void Glk::glk_time_to_date_utc(const glktimeval_t *time, glkdate_t *date) {
+ // TODO: timezones aren't currently supported
+ *date = TimeAndDate(*time);
+}
+
+void Glk::glk_time_to_date_local(const glktimeval_t *time, glkdate_t *date) {
+ *date = TimeAndDate(*time);
+}
+
+void Glk::glk_simple_time_to_date_utc(glsi32 time, glui32 factor, glkdate_t *date) {
+ TimeSeconds secs = (int64)time * factor;
+ *date = TimeAndDate(secs);
+}
+
+void Glk::glk_simple_time_to_date_local(glsi32 time, glui32 factor, glkdate_t *date) {
+ TimeSeconds secs = (int64)time * factor;
+ *date = TimeAndDate(secs);
+}
+
+void Glk::glk_date_to_time_utc(const glkdate_t *date, glktimeval_t *time) {
+ // WORKAROUND: timezones aren't currently supported
+ *time = TimeAndDate(*date);
+}
+
+void Glk::glk_date_to_time_local(const glkdate_t *date, glktimeval_t *time) {
+ *time = TimeAndDate(*date);
+}
+
+glsi32 Glk::glk_date_to_simple_time_utc(const glkdate_t *date, glui32 factor) {
+ // WORKAROUND: timezones aren't currently supported
+ assert(factor);
+ TimeSeconds ts = TimeAndDate(*date);
+ return ts / factor;
+}
+
+glsi32 Glk::glk_date_to_simple_time_local(const glkdate_t *date, glui32 factor) {
+ assert(factor);
+ TimeSeconds ts = TimeAndDate(*date);
+ return ts / factor;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* XXX non-official Glk functions */
+
+const char *Glk::garglk_fileref_get_name(frefid_t fref) const {
+ return fref->_filename.c_str();
+}
+
+void Glk::garglk_set_program_name(const char *name) {
+ // Program name isn't displayed
+}
+
+void Glk::garglk_set_program_info(const char *info) {
+ // Program info isn't displayed
+}
+
+void Glk::garglk_set_story_name(const char *name) {
+ // Story name isn't displayed
+}
+
+void Glk::garglk_set_story_title(const char *title) {
+ // Story title isn't displayed
+}
+
+void Glk::garglk_set_config(const char *name) {
+ // No implementation
+}
+
+void Glk::garglk_unput_string(const char *str) {
+ _streams->getCurrent()->unputBuffer(str, strlen(str));
+}
+
+void Glk::garglk_unput_string_uni(const glui32 *str) {
+ _streams->getCurrent()->unputBufferUni(str, strlen_uni(str));
+}
+
+void Glk::garglk_set_zcolors(glui32 fg, glui32 bg) {
+ _streams->getCurrent()->setZColors(fg, bg);
+}
+
+void Glk::garglk_set_zcolors_stream(strid_t str, glui32 fg, glui32 bg) {
+ if (str) {
+ str->setZColors(fg, bg);
+ } else {
+ warning("set_style_stream: Invalid ref");
+ }
+}
+
+void Glk::garglk_set_reversevideo(glui32 reverse) {
+ _streams->getCurrent()->setReverseVideo(reverse != 0);
+}
+
+void Glk::garglk_set_reversevideo_stream(strid_t str, glui32 reverse) {
+ if (str) {
+ str->setReverseVideo(reverse != 0);
+ } else {
+ warning("set_reversevideo: Invalid ref");
+ }
+}
+
+} // End of namespace Gargoyle