diff options
author | Paul Gilbert | 2019-05-18 15:54:26 -1000 |
---|---|---|
committer | Paul Gilbert | 2019-05-24 18:21:06 -0700 |
commit | bc87d740f55cfd0d283c6342abf641dfd0ff2e42 (patch) | |
tree | cd3734c76a03c841a4534cc0dc3d50507201f56c | |
parent | 3d9e03af554814bee10f112c2efa0b7f0b722489 (diff) | |
download | scummvm-rg350-bc87d740f55cfd0d283c6342abf641dfd0ff2e42.tar.gz scummvm-rg350-bc87d740f55cfd0d283c6342abf641dfd0ff2e42.tar.bz2 scummvm-rg350-bc87d740f55cfd0d283c6342abf641dfd0ff2e42.zip |
GLK: TADS2: Yet more volumous code additions
-rw-r--r-- | engines/glk/module.mk | 3 | ||||
-rw-r--r-- | engines/glk/tads/os_banners.cpp | 812 | ||||
-rw-r--r-- | engines/glk/tads/os_banners.h | 631 | ||||
-rw-r--r-- | engines/glk/tads/os_buffer.cpp | 11 | ||||
-rw-r--r-- | engines/glk/tads/os_glk.cpp | 101 | ||||
-rw-r--r-- | engines/glk/tads/os_glk.h | 597 | ||||
-rw-r--r-- | engines/glk/tads/os_parse.cpp | 989 | ||||
-rw-r--r-- | engines/glk/tads/os_parse.h | 43 | ||||
-rw-r--r-- | engines/glk/tads/tads2/debug.h | 27 | ||||
-rw-r--r-- | engines/glk/tads/tads2/error_message.cpp | 66 | ||||
-rw-r--r-- | engines/glk/tads/tads2/file_io.cpp | 6 | ||||
-rw-r--r-- | engines/glk/tads/tads2/get_string.cpp | 173 | ||||
-rw-r--r-- | engines/glk/tads/tads2/ltk.cpp | 6 | ||||
-rw-r--r-- | engines/glk/tads/tads2/output.cpp | 27 | ||||
-rw-r--r-- | engines/glk/tads/tads2/post_compilation.cpp | 32 | ||||
-rw-r--r-- | engines/glk/tads/tads2/post_compilation.h | 16 | ||||
-rw-r--r-- | engines/glk/tads/tads2/runtime_driver.cpp | 78 | ||||
-rw-r--r-- | engines/glk/tads/tads2/text_io.h | 3 |
18 files changed, 2952 insertions, 669 deletions
diff --git a/engines/glk/module.mk b/engines/glk/module.mk index 1ce24586c9..db930f2e2f 100644 --- a/engines/glk/module.mk +++ b/engines/glk/module.mk @@ -92,9 +92,11 @@ MODULE_OBJS := \ scott/detection.o \ scott/scott.o \ tads/detection.o \ + tads/os_banners.o \ tads/os_buffer.o \ tads/os_glk.o \ tads/os_frob_tads.o \ + tads/os_parse.o \ tads/tads.o \ tads/tads2/built_in.o \ tads/tads2/character_map.o \ @@ -106,6 +108,7 @@ MODULE_OBJS := \ tads/tads2/error_message.o \ tads/tads2/execute_command.o \ tads/tads2/file_io.o \ + tads/tads2/get_string.o \ tads/tads2/line_source_file.o \ tads/tads2/list.o \ tads/tads2/ltk.o \ diff --git a/engines/glk/tads/os_banners.cpp b/engines/glk/tads/os_banners.cpp new file mode 100644 index 0000000000..577e9f3dd3 --- /dev/null +++ b/engines/glk/tads/os_banners.cpp @@ -0,0 +1,812 @@ +/* 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/os_banners.h" +#include "glk/tads/os_buffer.h" +#include "glk/tads/tads.h" +#include "glk/glk_api.h" +#include "glk/window_text_buffer.h" + +namespace Glk { +namespace TADS { + +struct os_banner_t; +struct banner_contents_t; +typedef os_banner_t *osbanid_t; +typedef banner_contents_t *contentid_t; + +/* for tracking banner windows */ +struct os_banner_t { + uint id; /* unique identifier */ + uint valid; /* banner status */ + + osbanid_t prev; /* previous sibling */ + osbanid_t next; /* next sibling */ + osbanid_t children; /* child's descendents */ + osbanid_t parent; /* child's parent */ + + uint method; /* glk window method */ + uint size; /* glk window size */ + uint type; /* glk window type */ + uint status; /* glk status style */ + + uint cheight; /* glk char height */ + uint cwidth; /* glk char width */ + + uint fgcolor; /* foreground color */ + uint bgcolor; /* background color */ + uint fgcustom; /* custom colors */ + uint bgcustom; + uint bgtrans; + + contentid_t contents; /* window contents */ + uint style; /* active Glk style value */ + uint newline; /* active newline */ + uint move, x, y; /* active cursor position */ + + winid_t win; /* glk window object */ +}; + +/* for reprinting banner contents */ +struct banner_contents_t { + osbanid_t banner; /* content owner */ + contentid_t next; /* next set of contents */ + + uint style; /* stored contents style */ + uint newline; /* stored newline */ + uint move, x, y; /* stored cursor position */ + + char *chars; + uint len; +}; + +static osbanid_t os_banners = NULL; +static uint os_banner_count = 999; + +extern winid_t mainwin; +extern winid_t statuswin; + +extern uint mainfg; +extern uint mainbg; + +extern uint statusfg; +extern uint statusbg; + +void banner_contents_display(contentid_t contents); + +/* Implementation-specific functions for managing banner windows */ +/* + os_banner_init(); + os_banner_insert(); + os_banner_styles_apply(); + os_banner_styles_reset(); + os_banners_close(); + os_banners_open(); + os_banners_redraw(); +*/ + +osbanid_t os_banner_init() { + osbanid_t instance; + instance = (osbanid_t)malloc(sizeof(os_banner_t)); + if (!instance) + return 0; + + instance->id = ++ os_banner_count; + instance->valid = 1; + + instance->prev = 0; + instance->next = 0; + instance->children = 0; + instance->parent = 0; + + instance->method = 0; + instance->size = 0; + instance->type = 0; + instance->status = 0; + + instance->cheight = 0; + instance->cwidth = 0; + + instance->contents = 0; + instance->style = style_Normal; + instance->newline = 0; + instance->move = 0; + instance->x = 0; + instance->y = 0; + + instance->win = 0; + + return instance; +} + +osbanid_t os_banner_insert(osbanid_t parent, uint operation, osbanid_t other, + uint method, uint size, uint type, uint status) +{ + if (!parent || !(parent->valid)) + return 0; + + if (operation == OS_BANNER_BEFORE || operation == OS_BANNER_AFTER) + if (!other || !(other->valid) || !(other->parent == parent)) + operation = OS_BANNER_LAST; + + osbanid_t baby = os_banner_init(); + if (!baby) + return 0; + baby->parent = parent; + + if (!(parent->children)) + { + parent->children = baby; + } + else + { + osbanid_t child = parent->children; + + switch (operation) + { + case OS_BANNER_FIRST: + parent->children = baby; + baby->next = child; + child->prev = baby; + break; + + case OS_BANNER_BEFORE: + while (child != other && child->next) + child = child->next; + + if (child->prev) + { + child->prev->next = baby; + baby->prev = child->prev; + } + else + { + parent->children = baby; + } + + baby->next = child; + child->prev = baby; + break; + + case OS_BANNER_LAST: + while(child->next) + child = child->next; + + baby->prev = child; + child->next = baby; + break; + + case OS_BANNER_AFTER: + while (child != other && child->next) + child = child->next; + + if (child->next) + { + child->next->prev = baby; + baby->next = child->next; + } + + baby->prev = child; + child->next = baby; + break; + + default: break; + } + } + + baby->method = method; + baby->size = size; + baby->type = type; + baby->status = status; + + return baby; +} + +void os_banner_styles_apply (osbanid_t banner) +{ + if (!banner || !(banner->valid)) + return; + + uint propval = banner->status ? 0 : (banner->type == wintype_TextGrid ? 0 : 1); + uint bgcustom = banner->bgtrans ? banner->bgcolor : banner->bgcustom; + + /* font style: monospace for text grid and tab aligned buffers, else proportional */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_Proportional, propval); + + /* foreground color: user1 reverse, user2 custom */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_TextColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_TextColor, banner->fgcustom); + + /* background color: user1 reverse, user2 custom */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_BackColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_BackColor, bgcustom); + +} + +void os_banner_styles_reset (void) +{ + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_Proportional); + + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_TextColor); + + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_BackColor); + +#ifdef GARGLK + /* reset our default colors with a superfluous hint */ + g_vm->glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_TextColor, mainfg); + g_vm->glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_BackColor, mainbg); +#endif /* GARGLK */ +} + +void os_banners_close(osbanid_t banner) +{ + if (!banner) + return; + + os_banners_close(banner->children); + os_banners_close(banner->next); + + if (banner->win && (banner->win != mainwin)) + { + g_vm->glk_window_close(banner->win, 0); + banner->win = 0; + } +} + +void os_banners_open(osbanid_t banner) +{ + if (!banner) + return; + + if (banner->valid) + { + if (banner->size && banner->parent && banner->parent->win) + { + os_banner_styles_apply(banner); + banner->win = g_vm->glk_window_open(banner->parent->win, banner->method, + banner->size, banner->type, banner->id); + banner_contents_display(banner->contents); + } + os_banners_open(banner->children); + } + + os_banners_open(banner->next); +} + +void os_banners_redraw() +{ + if (!os_banners) + return; + + os_banners_close(os_banners); + os_banners_open(os_banners); + os_banner_styles_reset(); +} + +/* Implementation-specific functions for managing banner contents */ +/* + banner_contents_init(); + banner_contents_insert(); + banner_contents_display(); + banner_contents_clear(); +*/ + +contentid_t banner_contents_init(void) +{ + contentid_t instance; + instance = (contentid_t)malloc(sizeof(banner_contents_t)); + if (!instance) + return 0; + + instance->banner = 0; + instance->next = 0; + + instance->style = style_Normal; + instance->newline = 0; + instance->move = 0; + instance->x = 0; + instance->y = 0; + + instance->chars = 0; + instance->len = 0; + + return instance; +} + +void banner_contents_insert(contentid_t contents, const char *txt, size_t len) +{ + if (!contents) + return; + + contents->chars = (char *)malloc(sizeof(char) * (len + 1)); + if (!(contents->chars)) + return; + + memcpy(contents->chars, txt, len); + + contents->chars[len] = '\0'; + contents->len = len; +} + +void banner_contents_display(contentid_t contents) +{ + if (!contents || !(contents->banner)) + return; + + winid_t win = contents->banner->win; + uint len = contents->len; + + g_vm->glk_set_window(win); + + if (contents->newline) + { + char ch = '\n'; + os_put_buffer(&ch, 1); + } + + if (len && (contents->chars[len-1] == '\n')) + { + len --; + contents->banner->newline = 1; + } + else + { + contents->banner->newline = 0; + } + + if (contents->move) + { + g_vm->glk_window_move_cursor(win, contents->x, contents->y); + contents->banner->move = 0; + contents->banner->x = 0; + contents->banner->y = 0; + } + + g_vm->glk_set_style(contents->style); + os_put_buffer(contents->chars, len); + g_vm->glk_set_window(mainwin); + banner_contents_display(contents->next); +} + +void banner_contents_clear(contentid_t contents) +{ + if (!contents) + return; + + banner_contents_clear(contents->next); + + if (contents->chars) + free(contents->chars); + + free(contents); +} + +/* Banner API functions */ + +void *os_banner_create(void *parent, int where, void *other, int wintype, + int align, int siz, int siz_units, + unsigned long style) +{ + osbanid_t gparent = (osbanid_t)parent; + osbanid_t gbanner; + uint gwinmeth = 0; + uint gwinsize = siz; + uint gwintype = 0; + uint gstatus = (style & OS_BANNER_STYLE_TAB_ALIGN); + + if (gparent && !(gparent->valid)) + return 0; + + if (!os_banners) + { + os_banners = os_banner_init(); + if (!os_banners) + return 0; + os_banners->win = mainwin; + } + + if (!gparent) + gparent = os_banners; + + switch (wintype) + { + case OS_BANNER_TYPE_TEXT: gwintype = wintype_TextBuffer; break; + case OS_BANNER_TYPE_TEXTGRID: gwintype = wintype_TextGrid; break; + default: gwintype = wintype_TextGrid; break; + } + + switch (align) + { + case OS_BANNER_ALIGN_TOP: gwinmeth = winmethod_Above; break; + case OS_BANNER_ALIGN_BOTTOM: gwinmeth = winmethod_Below; break; + case OS_BANNER_ALIGN_LEFT: gwinmeth = winmethod_Left; break; + case OS_BANNER_ALIGN_RIGHT: gwinmeth = winmethod_Right; break; + default: gwinmeth = winmethod_Above; break; + } + + switch (siz_units) + { + case OS_BANNER_SIZE_PCT: gwinmeth |= winmethod_Proportional; break; + case OS_BANNER_SIZE_ABS: gwinmeth |= winmethod_Fixed; break; + default: gwinmeth |= winmethod_Fixed; break; + } + + gbanner = os_banner_insert(gparent, where, (osbanid_t)other, gwinmeth, gwinsize, gwintype, gstatus); + + if (gbanner) + { + gbanner->fgcolor = gstatus ? statusbg : mainfg; + gbanner->bgcolor = gstatus ? statusfg : mainbg; + gbanner->fgcustom = gbanner->fgcolor; + gbanner->bgcustom = gbanner->bgcolor; + gbanner->bgtrans = 1; + } + + os_banners_redraw(); + + return gbanner; +} + +void os_banner_set_size(void *banner_handle, int siz, int siz_units, int is_advisory) +{ + osbanid_t banner = (osbanid_t)banner_handle; + + if (!banner || !banner->valid) + return; + + uint gwinsize = siz; + uint gwinmeth = 0; + + gwinmeth = banner->method & + (winmethod_Above | winmethod_Below | + winmethod_Left | winmethod_Right); + + switch (siz_units) + { + case OS_BANNER_SIZE_PCT: gwinmeth |= winmethod_Proportional; break; + case OS_BANNER_SIZE_ABS: gwinmeth |= winmethod_Fixed; break; + default: gwinmeth |= winmethod_Fixed; break; + } + + banner->method = gwinmeth; + banner->size = gwinsize; + + os_banners_redraw(); +} + +void os_banner_size_to_contents(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + + if (!banner || !banner->valid || !banner->win) + return; + +#ifdef GARGLK + if (banner->type == wintype_TextBuffer) + { + TextBufferWindow *win = dynamic_cast<TextBufferWindow *>(banner->win); + assert(win); + int size = win->_scrollMax; + if (win->_numChars) + size++; + os_banner_set_size(banner, size, OS_BANNER_SIZE_ABS, 0); + } +#endif /* GARGLK */ +} + +void os_banner_delete(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !(banner->valid)) + return; + + banner->valid = 0; + os_banners_redraw(); + + if (banner->parent && banner->parent->children == banner) + banner->parent->children = banner->next; + + if (banner->next) + banner->next->prev = banner->prev; + + if (banner->prev) + banner->prev->next = banner->next; + + banner_contents_clear(banner->contents); + + free(banner); +} + +void os_banner_orphan(void *banner_handle) +{ + os_banner_delete(banner_handle); +} + +int os_banner_getinfo(void *banner_handle, os_banner_info_t *info) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 1; + + //winid_t win = banner->win; + uint gwintype = banner->type; + uint gwinmeth = banner->method; + uint gstyletab = banner->status; + + if (gwinmeth & winmethod_Above) + info->align = OS_BANNER_ALIGN_TOP; + if (gwinmeth & winmethod_Below) + info->align = OS_BANNER_ALIGN_BOTTOM; + if (gwinmeth & winmethod_Left) + info->align = OS_BANNER_ALIGN_LEFT; + if (gwinmeth & winmethod_Right) + info->align = OS_BANNER_ALIGN_RIGHT; + + info->style = gstyletab ? OS_BANNER_STYLE_TAB_ALIGN : 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + info->rows = banner->cheight; + info->columns = banner->cwidth; + + info->pix_width = 0; + info->pix_height = 0; + + info->os_line_wrap = gstyletab ? 0 : (gwintype == wintype_TextBuffer); + + return 1; +} + +int os_banner_get_charwidth(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + return banner->cwidth; +} + +int os_banner_get_charheight(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + return banner->cheight; +} + +void os_banner_clear(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (banner->win) + { + winid_t win = banner->win; + g_vm->glk_window_clear(win); + } + + banner_contents_clear(banner->contents); + banner->contents = 0; + banner->newline = 0; + banner->move = 0; + banner->x = 0; + banner->y = 0; +} + +void os_banner_disp(void *banner_handle, const char *txt, size_t len) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return; + + contentid_t update = banner_contents_init(); + if (!update) + return; + update->banner = banner; + + if (!(banner->contents)) + { + banner->contents = update; + } + else + { + contentid_t contents = banner->contents; + while (contents->next) + contents = contents->next; + contents->next = update; + } + + update->style = banner->style; + update->newline = banner->newline; + update->move = banner->move; + update->x = banner->x; + update->y = banner->y; + + banner_contents_insert(update, txt, len); + banner_contents_display(update); +} + +void os_banner_goto(void *banner_handle, int row, int col) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return; + + if (banner->type == wintype_TextGrid) + { + banner->move = 1; + banner->x = col; + banner->y = row; + } +} + +void os_banner_set_attr(void *banner_handle, int attr) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (attr & OS_ATTR_BOLD && attr & OS_ATTR_ITALIC) + banner->style = style_Alert; + else if (attr & OS_ATTR_BOLD) + banner->style = style_Subheader; + else if (attr & OS_ATTR_ITALIC) + banner->style = style_Emphasized; + else + banner->style = style_Normal; +} + +void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + uint reversed = 0; + uint normal = 0; + uint transparent = 0; + + /* evaluate parameters */ + + if (os_color_is_param(fg)) + { + switch(fg) + { + case OS_COLOR_P_TEXTBG: + case OS_COLOR_P_STATUSBG: + reversed = 1; + break; + + case OS_COLOR_P_TEXT: + case OS_COLOR_P_STATUSLINE: + case OS_COLOR_P_INPUT: + normal = 1; + break; + + default: + break; + } + } + + if (os_color_is_param(bg)) + { + switch (bg) + { + case OS_COLOR_P_TRANSPARENT: + transparent = 1; + break; + + default: + break; + } + } + + /* choose a style */ + + if (normal && transparent) + banner->style = style_Normal; + else if (reversed) + banner->style = style_User1; + else + banner->style = style_User2; + + /* process our custom color */ + + if (banner->style == style_User2) + { + /* store current settings */ + uint oldfg = banner->fgcustom; + uint oldbg = banner->bgcustom; + uint oldtr = banner->bgtrans; + + /* reset custom color parameters */ + banner->fgcustom = banner->fgcolor; + banner->bgcustom = banner->bgcolor; + banner->bgtrans = 1; + + if (!normal) + banner->fgcustom = fg; + + if (!transparent) + { + banner->bgcustom = bg; + banner->bgtrans = 0; + } + + if (!(banner->fgcustom == oldfg + && banner->bgcustom == oldbg + && banner->bgtrans == oldtr)) + os_banners_redraw(); + } +} + +void os_banner_set_screen_color(void *banner_handle, os_color_t color) { + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (!(os_color_is_param(color))) + banner->bgcolor = color; + + os_banners_redraw(); +} + +void os_banner_flush(void *banner_handle) {} +void os_banner_start_html(void *banner_handle) {} +void os_banner_end_html(void *banner_handle) {} + +} // End of namespace TADS +} // End of namespace Glk diff --git a/engines/glk/tads/os_banners.h b/engines/glk/tads/os_banners.h new file mode 100644 index 0000000000..f518d8e84f --- /dev/null +++ b/engines/glk/tads/os_banners.h @@ -0,0 +1,631 @@ +/* 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. + * + */ + +/* TADS OS interface file type definitions + * + * Defines certain datatypes used in the TADS operating system interface + */ + +#ifndef GLK_TADS_OS_BANNERS +#define GLK_TADS_OS_BANNERS + +#include "common/scummsys.h" +#include "glk/tads/os_glk.h" + +namespace Glk { +namespace TADS { + +/* ------------------------------------------------------------------------ */ +/* + * External Banner Interface. This interface provides the ability to + * divide the display window into multiple sub-windows, each with its own + * independent contents. + * + * To determine where a new banner is displayed, we look at the banners as + * a tree, rooted at the "main window," the special banner that the system + * automatically creates initially for the main game text. We start by + * allocating the entire display (or the entire application window, if + * we're running on a GUI system) to the main window. We then traverse + * the tree, starting with the root window's children. For each child + * window, we allocate space for the child out of the parent window's + * area, according to the child's alignment and size settings, and deduct + * this space from the parent window's size. We then lay out the children + * of the child. + * + * For each banner window, we take its requested space out of the parent + * window's area by starting at the edge of the parent window rectangle as + * indicated by the banner's alignment, and taking the requested `width + * (for a left/right banner) or height (for a top/bottom banner), limiting + * to the available width/height in the parent window's space. Give the + * banner the full extent of the parent's space in its other dimension (so + * a left/right banner gets the full height of the parent space, and a + * top/bottom banner gets the full width). + * + * Note that the layout proceeds exclusively down the tree (i.e., from the + * root to children to grandchildren, and so on). It *appears* that a + * child affects its parent, because of the deduction step: a child + * acquires screen space by carving out a chunk of its parent. The right + * way to think about this, though, is that the parent's full area is the + * union of the parent window and all of its children; when viewed this + * way, the parent's full area is fully determined the instant the parent + * is laid out, and never changes as its children are laid out. Note in + * particular that a child can never make a parent larger; the only thing + * a child can do to a parent is carve out a chunk of the parent for + * itself, which doesn't affect the boundaries of the union of the parent + * plus its children. + * + * Note also that if the banner has a border, and the implementation + * actually draws borders, the border must be drawn for the *full* area of + * the banner, as defined above. For example, suppose we have two + * borders: banner A is a child of the main window, is top-aligned, and + * has a border. Banner B is a child of banner A, right-aligned, with no + * border. Obviously, without considering banner B, banner A's space runs + * across the entire width of the main window, so its border (at the + * bottom of its area) runs across the entire width of the main window. + * Banner B carves out some space from A's right side for itself, so + * banner A's actual on-screen area runs from the left edge of the main + * window to banner B's left edge. However, even though banner A itself + * no longer runs the full width of the main window, banner A's *full* + * area - that is, the union of banner A's on-screen area and all of its + * children's full areas - does still run the entire width of the main + * window, hence banner A's border must still run the full width of the + * main window. The simple way of looking at this is that a banner's + * border is always to be drawn exactly the same way, regardless of + * whether or not the banner has children - simply draw the banner as it + * would be drawn if the banner had no children. + * + * Each time a banner is added or removed, we must recalculate the layout + * of the remaining banners and main text area. The os_banner_xxx() + * implementation is responsible for this layout refiguring. + * + * The entire external banner window interface is optional, although the + * functions must at least be defined as dummies to avoid linker errors + * when building. If a platform doesn't implement this feature, + * os_banner_create() should simply return null, and the other routines + * can do nothing. + */ + +/* + * Create a banner window. 'info' gives the desired parameters for the new + * banner. + * + * Note that certain requested parameter settings might or might not be + * respected, depending on the capabilities of the platform and user + * preferences. os_banner_getinfo() can be used after creation to + * determine which parameter settings are actually used in the new banner. + * + * 'parent' gives the parent of this banner; this is the banner handle of + * another banner window, or null. If 'parent' is null, then the new + * banner is a child of the main window, which the system creates + * automatically at startup and which contains the main input/output + * transcript. The new banner's on-screen area is carved out of the + * parent's space, according to the alignment and size settings of the new + * window, so this determines how the window is laid out on the screen. + * + * 'where' is OS_BANNER_FIRST to make the new window the first child of its + * parent; OS_BANNER_LAST to make it the last child of its parent; + * OS_BANNER_BEFORE to insert it immediately before the existing banner + * identified by handle in 'other'; or OS_BANNER_AFTER to insert + * immediately after 'other'. When BEFORE or AFTER is used, 'other' must + * be another child of the same parent; if it is not, the routine should + * act as though 'where' were given as OS_BANNER_LAST. + * + * 'other' is a banner handle for an existing banner window. This is used + * to specify the relative position among children of the new banner's + * parent, if 'where' is either OS_BANNER_BEFORE or OS_BANNER_AFTER. If + * 'where' is OS_BANNER_FIRST or OS_BANNER_LAST, 'other' is ignored. + * + * 'wintype' is the type of the window. This is one of the + * OS_BANNER_TYPE_xxx codes indicating what kind of window is desired. + * + * 'align' is the banner's alignment, given as an OS_BANNER_ALIGN_xxx + * value. Top/bottom banners are horizontal: they run across the full + * width of the existing main text area. Left/right banners are vertical: + * they run down the full height of the existing main text area. + * + * 'siz' is the requested size of the new banner. The meaning of 'siz' + * depends on the value of 'siz_units', which can be OS_BANNER_SIZE_PCT to + * set the size as a percentage of the REMAINING space, or + * OS_BANNER_SIZE_ABS to set an absolute size in the "natural" units of the + * window. The natural units vary by window type: for text and text grid + * windows, this is in rows/columns of '0' characters in the default font + * for the window. Note that when OS_BANNER_SIZE_ABS is used in a text or + * text grid window, the OS implementation MUST add the space needed for + * margins and borders when determining the actual pixel size of the + * window; in other words, the window should be large enough that it can + * actually display the given number or rows or columns. + * + * The size is interpreted as a width or height according to the window's + * orientation. For a TOP or BOTTOM banner, the size is the height; for a + * LEFT or RIGHT banner, the size is the width. A banner has only one + * dimension's size given, since the other dimension's size is determined + * automatically by the layout rules. + * + * Note that the window's size can be changed later using + * banner_size_to_contents() or banner_set_size(). + * + * 'style' is a combination of OS_BANNER_STYLE_xxx flags - see below. The + * style flags give the REQUESTED style for the banner, which might or + * might not be respected, depending on the platform's capabilities, user + * preferences, and other factors. os_banner_getinfo() can be used to + * determine which style flags are actually used. + * + * Returns the "handle" to the new banner window, which is an opaque value + * that is used in subsequent os_banner_xxx calls to operate on the window. + * Returns null if the window cannot be created. An implementation is not + * required to support this functionality at all, and can subset it if it + * does support it (for example, an implementation could support only + * top/bottom-aligned banners, but not left/right-aligned), so callers must + * be prepared for this routine to return null. + */ +void *os_banner_create(void *parent, int where, void *other, int wintype, + int align, int siz, int siz_units, + unsigned long style); + + +/* + * insertion positions + */ +#define OS_BANNER_FIRST 1 +#define OS_BANNER_LAST 2 +#define OS_BANNER_BEFORE 3 +#define OS_BANNER_AFTER 4 + +/* + * banner types + */ + +/* + * Normal text stream window. This is a text stream that behaves + * essentially like the main text window: text is displayed to this + * through os_banner_disp(), always in a stream-like fashion by adding new + * text to the end of any exiting text. + * + * Systems that use proportional fonts should usually simply use the same + * font they use by default in the main text window. However, note that + * the OS_BANNER_STYLE_TAB_ALIGN style flag might imply that a fixed-pitch + * font should be used even when proportional fonts are available, because + * a fixed-pitch font will allow the calling code to rely on using spaces + * to align text within the window. + */ +#define OS_BANNER_TYPE_TEXT 1 + +/* + * "Text grid" window. This type of window is similar to an normal text + * window (OS_BANNER_TYPE_TEXT), but is guaranteed to arrange its text in + * a regular grid of character cells, all of the same size. This means + * that the output position can be moved to an arbitrary point within the + * window at any time, so the calling program can precisely control the + * layout of the text in the window. + * + * Because the output position can be moved to arbitrary positions in the + * window, it is possible to overwrite text previously displayed. When + * this happens, the old text is completely obliterated by the new text, + * leaving no trace of the overwritten text. + * + * In order to guarantee that character cells are all the same size, this + * type of window does not allow any text attributes. The implementation + * should simply ignore any attempts to change text attributes in this + * type of window. However, colors can be used to the same degree they + * can be used in an ordinary text window. + * + * To guarantee the regular spacing of character cells, all + * implementations must use fixed-pitch fonts for these windows. This + * applies even to platforms where proportional fonts are available. + */ +#define OS_BANNER_TYPE_TEXTGRID 2 + + +/* + * banner alignment types + */ +#define OS_BANNER_ALIGN_TOP 0 +#define OS_BANNER_ALIGN_BOTTOM 1 +#define OS_BANNER_ALIGN_LEFT 2 +#define OS_BANNER_ALIGN_RIGHT 3 + +/* + * size units + */ +#define OS_BANNER_SIZE_PCT 1 +#define OS_BANNER_SIZE_ABS 2 + + +/* + * banner style flags + */ + +/* + * The banner has a visible border; this indicates that a line is to be + * drawn to separate the banner from the adjacent window or windows + * "inside" the banner. So, a top-aligned banner will have its border + * drawn along its bottom edge; a left-aligned banner will show a border + * along its right edge; and so forth. + * + * Note that character-mode platforms generally do NOT respect the border + * style, since doing so takes up too much screen space. + */ +#define OS_BANNER_STYLE_BORDER 0x00000001 + +/* + * The banner has a vertical/horizontal scrollbar. Character-mode + * platforms generally do not support scrollbars. + */ +#define OS_BANNER_STYLE_VSCROLL 0x00000002 +#define OS_BANNER_STYLE_HSCROLL 0x00000004 + +/* + * Automatically scroll the banner vertically/horizontally whenever new + * text is displayed in the window. In other words, whenever + * os_banner_disp() is called, scroll the window so that the text that the + * new cursor position after the new text is displayed is visible in the + * window. + * + * Note that this style is independent of the presence of scrollbars. + * Even if there are no scrollbars, we can still scroll the window's + * contents programmatically. + * + * Implementations can, if desired, keep an internal buffer of the + * window's contents, so that the contents can be recalled via the + * scrollbars if the text displayed in the banner exceeds the space + * available in the banner's window on the screen. If the implementation + * does keep such a buffer, we recommend the following method for managing + * this buffer. If the AUTO_VSCROLL flag is not set, then the banner's + * contents should be truncated at the bottom when the contents overflow + * the buffer; that is, once the banner's internal buffer is full, any new + * text that the calling program attempts to add to the banner should + * simply be discarded. If the AUTO_VSCROLL flag is set, then the OLDEST + * text should be discarded instead, so that the most recent text is + * always retained. + */ +#define OS_BANNER_STYLE_AUTO_VSCROLL 0x00000008 +#define OS_BANNER_STYLE_AUTO_HSCROLL 0x00000010 + +/* + * Tab-based alignment is required/supported. On creation, this is a hint + * to the implementation that is sometimes necessary to determine what + * kind of font to use in the new window, for non-HTML platforms. If this + * flag is set on creation, the caller is indicating that it wants to use + * <TAB> tags to align text in the window. + * + * Character-mode implementations that use a single font with fixed pitch + * can simply ignore this. These implementations ALWAYS have a working + * <TAB> capability, because the portable output formatter provides <TAB> + * interpretation for a fixed-pitch window. + * + * Full HTML TADS implementations can also ignore this. HTML TADS + * implementations always have full <TAB> support via the HTML + * parser/renderer. + * + * Text-only implementations on GUI platforms (i.e., implementations that + * are not based on the HTML parser/renderer engine in HTML TADS, but + * which run on GUI platforms with proportionally-spaced text) should use + * this flag to determine the font to display. If this flag is NOT set, + * then the caller doesn't care about <TAB>, and the implementation is + * free to use a proportionally-spaced font in the window if desired. + * + * When retrieving information on an existing banner, this flag indicates + * that <TAB> alignment is actually supported on the window. + */ +#define OS_BANNER_STYLE_TAB_ALIGN 0x00000020 + +/* + * Use "MORE" mode in this window. By default, a banner window should + * happily allow text to overflow the vertical limits of the window; the + * only special thing that should happen on overflow is that the window + * should be srolled down to show the latest text, if the auto-vscroll + * style is set. With this flag, though, a banner window acts just like + * the main text window: when the window fills up vertically, we show a + * MORE prompt (using appropriate system conventions), and wait for the + * user to indicate that they're ready to see more text. On most systems, + * the user acknowledges a MORE prompt by pressing a key or scrolling with + * the mouse, but it's up to the system implementor to decide what's + * appropriate for the system. + * + * Note that MORE mode in ANY banner window should generally override all + * other user input focus. In other words, if the game in the main window + * would like to read a keystroke from the user, but one of the banner + * windows is pausing with a MORE prompt, any keyboard input should be + * directed to the banner paused at the MORE prompt, not to the main + * window; the main window should not receive any key events until the MORE + * prompt has been removed. + * + * This style requires the auto-vscroll style. Implementations should + * assume auto-vscroll when this style is set. This style can be ignored + * with text grid windows. + */ +#define OS_BANNER_STYLE_MOREMODE 0x00000040 + +/* + * This banner is a horizontal/vertical "strut" for sizing purposes. This + * means that the banner's content size is taken into account when figuring + * the content size of its *parent* banner. If the banner has the same + * orientation as the parent, its content size is added to its parent's + * internal content size to determine the parent's overall content size. + * If the banner's orientation is orthogonal to the parent's, then the + * parent's overall content size is the larger of the parent's internal + * content size and this banner's content size. + */ +#define OS_BANNER_STYLE_HSTRUT 0x00000080 +#define OS_BANNER_STYLE_VSTRUT 0x00000100 + + +/* + * Delete a banner. This removes the banner from the display, which + * requires recalculating the entire screen's layout to reallocate this + * banner's space to other windows. When this routine returns, the banner + * handle is invalid and can no longer be used in any os_banner_xxx + * function calls. + * + * If the banner has children, the children will no longer be displayed, + * but will remain valid in memory until deleted. A child window's + * display area always comes out of its parent's space, so once the parent + * is gone, a child has no way to acquire any display space; resizing the + * child won't help, since it simply has no way to obtain any screen space + * once its parent has been deleted. Even though the window's children + * will become invisible, their banner handles will remain valid; the + * caller is responsible for explicitly deleting the children even after + * deleting their parent. + */ +void os_banner_delete(void *banner_handle); + +/* + * "Orphan" a banner. This tells the osifc implementation that the caller + * wishes to sever all of its ties with the banner (as part of program + * termination, for example), but that the calling program does not + * actually require that the banner's on-screen display be immediately + * removed. + * + * The osifc implementation can do one of two things: + * + * 1. Simply call os_banner_delete(). If the osifc implementation + * doesn't want to do anything extra with the banner, it can simply delete + * the banner, since the caller has no more use for it. + * + * 2. Take ownership of the banner. If the osifc implementation wishes + * to continue displaying the final screen configuration after a program + * has terminated, it can simply take over the banner and leave it on the + * screen. The osifc subsystem must eventually delete the banner itself + * if it takes this routine; for example, if the osifc subsystem allows + * another client program to be loaded into the same window after a + * previous program has terminated, it would want to delete any orphaned + * banners from the previous program when loading a new program. + */ +void os_banner_orphan(void *banner_handle); + +/* + * Banner information structure. This is filled in by the system-specific + * implementation in os_banner_getinfo(). + */ +struct os_banner_info_t +{ + /* alignment */ + int align; + + /* style flags - these indicate the style flags actually in use */ + unsigned long style; + + /* + * Actual on-screen size of the banner, in rows and columns. If the + * banner is displayed in a proportional font or can display multiple + * fonts of different sizes, this is approximated by the number of "0" + * characters in the window's default font that will fit in the + * window's display area. + */ + int rows; + int columns; + + /* + * Actual on-screen size of the banner in pixels. This is meaningful + * only for full HTML interpreter; for text-only interpreters, these + * are always set to zero. + * + * Note that even if we're running on a GUI operating system, these + * aren't meaningful unless this is a full HTML interpreter. Text-only + * interpreters should always set these to zero, even on GUI OS's. + */ + int pix_width; + int pix_height; + + /* + * OS line wrapping flag. If this is set, the window uses OS-level + * line wrapping because the window uses a proportional font, so the + * caller does not need to (and should not) perform line breaking in + * text displayed in the window. + * + * Note that OS line wrapping is a PERMANENT feature of the window. + * Callers can note this information once and expect it to remain + * fixed through the window's lifetime. + */ + int os_line_wrap; +}; +typedef struct os_banner_info_t os_banner_info_t; + +/* + * Get information on the banner - fills in the information structure with + * the banner's current settings. Note that this should indicate the + * ACTUAL properties of the banner, not the requested properties; this + * allows callers to determine how the banner is actually displayed, which + * depends upon the platform's capabilities and user preferences. + * + * Returns true if the information was successfully obtained, false if + * not. This can return false if the underlying OS window has already + * been closed by a user action, for example. + */ +int os_banner_getinfo(void *banner_handle, os_banner_info_t *info); + +/* + * Get the character width/height of the banner, for layout purposes. This + * gives the size of the banner in character cells. + * + * These are not meaningful when the underlying window uses a proportional + * font or varying fonts of different sizes. When the size of text varies + * in the window, the OS layer is responsible for word-wrapping and other + * layout, in which case these simply return zero. + * + * Note that these routines might appear to be redundant with the 'rows' + * and 'columns' information returned from os_banner_getinfo(), but these + * have two important distinctions. First, these routines return only the + * width and height information, so they can be implemented with less + * overhead than os_banner_getinfo(); this is important because formatters + * might need to call these routines frequently while formatting text. + * Second, these routines are not required to return an approximation for + * windows using proportional fonts, as os_banner_getinfo() does; these can + * simply return zero when a proportional font is in use. + */ +int os_banner_get_charwidth(void *banner_handle); +int os_banner_get_charheight(void *banner_handle); + +/* clear the contents of a banner */ +void os_banner_clear(void *banner_handle); + +/* + * Display output on a banner. Writes the output to the window on the + * display at the current output position. + * + * The following special characters should be recognized and handled: + * + * '\n' - newline; move output position to the start of the next line. + * + * '\r' - move output position to start of current line; subsequent text + * overwrites any text previously displayed on the current line. It is + * permissible to delete the old text immediately on seeing the '\r', + * rather than waiting for additional text to actually overwrite it. + * + * All other characters should simply be displayed as ordinary printing + * text characters. Note that tab characters should not be passed to this + * routine, but if they are, they can simply be treated as ordinary spaces + * if desired. Other control characters (backspace, escape, etc) should + * never be passed to this routine; the implementation is free to ignore + * any control characters not listed above. + * + * If any text displayed here overflows the current boundaries of the + * window on the screen, the text MUST be "clipped" to the current window + * boundaries; in other words, anything this routine tries to display + * outside of the window's on-screen rectangle must not actually be shown + * on the screen. + * + * Text overflowing the display boundaries MUST also be retained in an + * internal buffer. This internal buffer can be limited to the actual + * maximum display size of the terminal screen or application window, if + * desired. It is necessary to retain clipped text, because this allows a + * window to be expanded to the size of its contents AFTER the contents + * have already been displayed. + * + * If the banner does its own line wrapping, it must indicate this via the + * os_line_wrap flag in the os_banner_getinfo() return data. If the + * banner doesn't indicate this flag, then it must not do any line + * wrapping at all, even if the caller attempts to write text beyond the + * right edge of the window - any text overflowing the width of the window + * must simply be clipped. + * + * Text grid banners must ALWAYS clip - these banners should never perform + * any line wrapping. + */ +void os_banner_disp(void *banner_handle, const char *txt, size_t len); + +/* + * Set the text attributes in a banner, for subsequent text displays. + * 'attr' is a (bitwise-OR'd) combination of OS_ATTR_xxx values. + */ +void os_banner_set_attr(void *banner_handle, int attr); + +/* + * Set the text color in a banner, for subsequent text displays. The 'fg' + * and 'bg' colors are given as RGB or parameterized colors; see the + * definition of os_color_t for details. + * + * If the underlying renderer is HTML-enabled, then this should not be + * used; the appropriate HTML code should simply be displayed to the + * banner instead. + */ +void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg); + +/* + * Set the screen color in the banner - this is analogous to the screen + * color in the main text area. + * + * If the underlying renderer is HTML-enabled, then this should not be + * used; the HTML <BODY> tag should be used instead. + */ +void os_banner_set_screen_color(void *banner_handle, os_color_t color); + +/* flush output on a banner */ +void os_banner_flush(void *banner_handle); + +/* + * Set the banner's size. The size has the same meaning as in + * os_banner_create(). + * + * 'is_advisory' indicates whether the sizing is required or advisory only. + * If this flag is false, then the size should be set as requested. If + * this flag is true, it means that the caller intends to call + * os_banner_size_to_contents() at some point, and that the size being set + * now is for advisory purposes only. Platforms that support + * size-to-contents may simply ignore advisory sizing requests, although + * they might want to ensure that they have sufficient off-screen buffer + * space to keep track of the requested size of display, so that the + * information the caller displays in preparation for calling + * size-to-contents will be retained. Platforms that do not support + * size-to-contents should set the requested size even when 'is_advisory' + * is true. + */ +void os_banner_set_size(void *banner_handle, int siz, int siz_units, + int is_advisory); + +/* + * Set the banner to the size of its current contents. This can be used + * to set the banner's size after some text (or other material) has been + * displayed to the banner, so that the size can be set according to the + * banner's actual space requirements. + * + * This changes the banner's "requested size" to match the current size. + * Subsequent calls to os_banner_getinfo() will thus indicate a requested + * size according to the size set here. + */ +void os_banner_size_to_contents(void *banner_handle); + +/* + * Turn HTML mode on/off in the banner window. If the underlying renderer + * doesn't support HTML, these have no effect. + */ +void os_banner_start_html(void *banner_handle); +void os_banner_end_html(void *banner_handle); + +/* + * Set the output coordinates in a text grid window. The grid window is + * arranged into character cells numbered from row zero, column zero for + * the upper left cell. This function can only be used if the window was + * created with type OS_BANNER_TYPE_TEXTGRID; the request should simply be + * ignored by other window types. + * + * Moving the output position has no immediate effect on the display, and + * does not itself affect the "content size" for the purposes of + * os_banner_size_to_contents(). This simply sets the coordinates where + * any subsequent text is displayed. + */ +void os_banner_goto(void *banner_handle, int row, int col); + +} // End of namespace TADS +} // End of namespace Glk + +#endif diff --git a/engines/glk/tads/os_buffer.cpp b/engines/glk/tads/os_buffer.cpp index 0f00e9dd9b..539a379bcd 100644 --- a/engines/glk/tads/os_buffer.cpp +++ b/engines/glk/tads/os_buffer.cpp @@ -21,6 +21,7 @@ */ #include "glk/tads/os_buffer.h" +#include "glk/tads/os_parse.h" #include "glk/tads/tads.h" namespace Glk { @@ -50,10 +51,6 @@ char *os_fill_buffer(char *buf, size_t len) static uint32 *input = 0; static uint max = 0; -extern uint os_parse_chars(const char *buf, uint buflen, uint32 *out, uint outlen); - -extern uint os_prepare_chars(uint32 *buf, uint buflen, char *out, uint outlen); - void os_put_buffer(const char *buf, size_t len) { uint *out; uint outlen; @@ -66,7 +63,7 @@ void os_put_buffer(const char *buf, size_t len) { return; outlen = len; - outlen = os_parse_chars(buf, len, out, outlen); + outlen = os_parse_chars((const unsigned char *)buf, len, out, outlen); if (outlen) g_vm->glk_put_buffer_uni(out, outlen); @@ -81,13 +78,13 @@ void os_get_buffer(char *buf, size_t len, size_t init) { max = len; if (init) - os_parse_chars(buf, init + 1, input, len); + os_parse_chars((const unsigned char *)buf, init + 1, input, len); g_vm->glk_request_line_event_uni(mainwin, input, len - 1, init); } char *os_fill_buffer(char *buf, size_t len) { - uint res = os_prepare_chars(input, len, buf, max); + uint res = os_prepare_chars(input, len, (unsigned char *)buf, max); buf[res] = '\0'; free(input); diff --git a/engines/glk/tads/os_glk.cpp b/engines/glk/tads/os_glk.cpp index 5565086626..884703c54e 100644 --- a/engines/glk/tads/os_glk.cpp +++ b/engines/glk/tads/os_glk.cpp @@ -44,6 +44,11 @@ uint mainbg; uint statusfg; uint statusbg; +int G_os_pagelength; +int G_os_linewidth; +int G_os_moremode; +char G_os_gamename[OSFNMAX]; + /* ------------------------------------------------------------------------ */ /* @@ -993,10 +998,106 @@ long os_get_sys_clock_ms() { return g_system->getMillis(); } +void os_xlat_html4(unsigned int html4_char, char *result, size_t result_len) { + /* Return all standard Latin-1 characters as-is */ + if (html4_char <= 128 || (html4_char >= 160 && html4_char <= 255)) + result[0] = (unsigned char)html4_char; + else { + switch (html4_char) { + case 130: /* single back quote */ + result[0] = '`'; break; + case 132: /* double back quote */ + result[0] = '\"'; break; + case 153: /* trade mark */ + strcpy(result, "(tm)"); return; + case 140: /* OE ligature */ + case 338: /* OE ligature */ + strcpy(result, "OE"); return; + case 339: /* oe ligature */ + strcpy(result, "oe"); return; + case 159: /* Yuml */ + result[0] = (char)255; + case 376: /* Y with diaresis */ + result[0] = 'Y'; break; + case 352: /* S with caron */ + result[0] = 'S'; break; + case 353: /* s with caron */ + result[0] = 's'; break; + case 150: /* en dash */ + case 8211: /* en dash */ + result[0] = '-'; break; + case 151: /* em dash */ + case 8212: /* em dash */ + strcpy(result, "--"); return; + case 145: /* left single quote */ + case 8216: /* left single quote */ + result[0] = '`'; break; + case 146: /* right single quote */ + case 8217: /* right single quote */ + case 8218: /* single low-9 quote */ + result[0] = '\''; break; + case 147: /* left double quote */ + case 148: /* right double quote */ + case 8220: /* left double quote */ + case 8221: /* right double quote */ + case 8222: /* double low-9 quote */ + result[0] = '\"'; break; + case 8224: /* dagger */ + case 8225: /* double dagger */ + case 8240: /* per mille sign */ + result[0] = ' '; break; + case 139: /* single left-pointing angle quote */ + case 8249: /* single left-pointing angle quote */ + result[0] = '<'; break; + case 155: /* single right-pointing angle quote */ + case 8250: /* single right-pointing angle quote */ + result[0] = '>'; break; + case 8482: /* small tilde */ + result[0] = '~'; break; + + default: + /* unmappable character - return space */ + result[0] = (unsigned char)' '; + } + } + result[1] = 0; +} + #ifndef os_tzset void os_tzset() {} #endif +void os_nonstop_mode(int flag) {} + +void os_advise_load_charmap(const char *id, const char *ldesc, const char *sysinfo) {} + +void os_gen_charmap_filename(char *filename, char *internal_id, char *argv0) {} + +int os_input_dialog(int icon_id, const char *prompt, int standard_button_set, + const char **buttons, int button_count, int default_index, int cancel_index) { + // CUrrently unsupported + return 0; +} + +void os_flush() { + g_vm->glk_tick(); +} + +char *os_strlwr(char *s) { + for (char *p = s; *p; ++p) + *p = tolower(*p); + return s; +} + +void os_expause() { +#ifdef USE_EXPAUSE + os_printz("(Strike any key to exit...)"); + os_flush(); + os_waitc(); +#endif /* USE_EXPAUSE */ +} + +void os_plain(void) {} } // End of namespace TADS } // End of namespace Glk diff --git a/engines/glk/tads/os_glk.h b/engines/glk/tads/os_glk.h index 237502a456..7b76876001 100644 --- a/engines/glk/tads/os_glk.h +++ b/engines/glk/tads/os_glk.h @@ -42,6 +42,7 @@ namespace TADS { #define OSPATHURL "/" #define OSPATHSEP ':' #define OS_NEWLINE_SEQ "\n" +#define DBG_OFF /* maximum width (in characters) of a line of text */ #define OS_MAXWIDTH 255 @@ -2802,8 +2803,7 @@ void os_xlat_html4(unsigned int html4_char, * This parameter is provided so that the system code can look for * mapping files in the original TADS executables directory, if desired. */ -void os_gen_charmap_filename(char *filename, char *internal_id, - char *argv0); +void os_gen_charmap_filename(char *filename, char *internal_id, char *argv0); /* * Receive notification that a character mapping file has been loaded. @@ -2912,599 +2912,6 @@ void os_get_charmap(char *mapname, int charmap_id); */ #define OS_CHARMAP_CMDLINE 4 - -/* ------------------------------------------------------------------------ */ -/* - * External Banner Interface. This interface provides the ability to - * divide the display window into multiple sub-windows, each with its own - * independent contents. - * - * To determine where a new banner is displayed, we look at the banners as - * a tree, rooted at the "main window," the special banner that the system - * automatically creates initially for the main game text. We start by - * allocating the entire display (or the entire application window, if - * we're running on a GUI system) to the main window. We then traverse - * the tree, starting with the root window's children. For each child - * window, we allocate space for the child out of the parent window's - * area, according to the child's alignment and size settings, and deduct - * this space from the parent window's size. We then lay out the children - * of the child. - * - * For each banner window, we take its requested space out of the parent - * window's area by starting at the edge of the parent window rectangle as - * indicated by the banner's alignment, and taking the requested `width - * (for a left/right banner) or height (for a top/bottom banner), limiting - * to the available width/height in the parent window's space. Give the - * banner the full extent of the parent's space in its other dimension (so - * a left/right banner gets the full height of the parent space, and a - * top/bottom banner gets the full width). - * - * Note that the layout proceeds exclusively down the tree (i.e., from the - * root to children to grandchildren, and so on). It *appears* that a - * child affects its parent, because of the deduction step: a child - * acquires screen space by carving out a chunk of its parent. The right - * way to think about this, though, is that the parent's full area is the - * union of the parent window and all of its children; when viewed this - * way, the parent's full area is fully determined the instant the parent - * is laid out, and never changes as its children are laid out. Note in - * particular that a child can never make a parent larger; the only thing - * a child can do to a parent is carve out a chunk of the parent for - * itself, which doesn't affect the boundaries of the union of the parent - * plus its children. - * - * Note also that if the banner has a border, and the implementation - * actually draws borders, the border must be drawn for the *full* area of - * the banner, as defined above. For example, suppose we have two - * borders: banner A is a child of the main window, is top-aligned, and - * has a border. Banner B is a child of banner A, right-aligned, with no - * border. Obviously, without considering banner B, banner A's space runs - * across the entire width of the main window, so its border (at the - * bottom of its area) runs across the entire width of the main window. - * Banner B carves out some space from A's right side for itself, so - * banner A's actual on-screen area runs from the left edge of the main - * window to banner B's left edge. However, even though banner A itself - * no longer runs the full width of the main window, banner A's *full* - * area - that is, the union of banner A's on-screen area and all of its - * children's full areas - does still run the entire width of the main - * window, hence banner A's border must still run the full width of the - * main window. The simple way of looking at this is that a banner's - * border is always to be drawn exactly the same way, regardless of - * whether or not the banner has children - simply draw the banner as it - * would be drawn if the banner had no children. - * - * Each time a banner is added or removed, we must recalculate the layout - * of the remaining banners and main text area. The os_banner_xxx() - * implementation is responsible for this layout refiguring. - * - * The entire external banner window interface is optional, although the - * functions must at least be defined as dummies to avoid linker errors - * when building. If a platform doesn't implement this feature, - * os_banner_create() should simply return null, and the other routines - * can do nothing. - */ - -/* - * Create a banner window. 'info' gives the desired parameters for the new - * banner. - * - * Note that certain requested parameter settings might or might not be - * respected, depending on the capabilities of the platform and user - * preferences. os_banner_getinfo() can be used after creation to - * determine which parameter settings are actually used in the new banner. - * - * 'parent' gives the parent of this banner; this is the banner handle of - * another banner window, or null. If 'parent' is null, then the new - * banner is a child of the main window, which the system creates - * automatically at startup and which contains the main input/output - * transcript. The new banner's on-screen area is carved out of the - * parent's space, according to the alignment and size settings of the new - * window, so this determines how the window is laid out on the screen. - * - * 'where' is OS_BANNER_FIRST to make the new window the first child of its - * parent; OS_BANNER_LAST to make it the last child of its parent; - * OS_BANNER_BEFORE to insert it immediately before the existing banner - * identified by handle in 'other'; or OS_BANNER_AFTER to insert - * immediately after 'other'. When BEFORE or AFTER is used, 'other' must - * be another child of the same parent; if it is not, the routine should - * act as though 'where' were given as OS_BANNER_LAST. - * - * 'other' is a banner handle for an existing banner window. This is used - * to specify the relative position among children of the new banner's - * parent, if 'where' is either OS_BANNER_BEFORE or OS_BANNER_AFTER. If - * 'where' is OS_BANNER_FIRST or OS_BANNER_LAST, 'other' is ignored. - * - * 'wintype' is the type of the window. This is one of the - * OS_BANNER_TYPE_xxx codes indicating what kind of window is desired. - * - * 'align' is the banner's alignment, given as an OS_BANNER_ALIGN_xxx - * value. Top/bottom banners are horizontal: they run across the full - * width of the existing main text area. Left/right banners are vertical: - * they run down the full height of the existing main text area. - * - * 'siz' is the requested size of the new banner. The meaning of 'siz' - * depends on the value of 'siz_units', which can be OS_BANNER_SIZE_PCT to - * set the size as a percentage of the REMAINING space, or - * OS_BANNER_SIZE_ABS to set an absolute size in the "natural" units of the - * window. The natural units vary by window type: for text and text grid - * windows, this is in rows/columns of '0' characters in the default font - * for the window. Note that when OS_BANNER_SIZE_ABS is used in a text or - * text grid window, the OS implementation MUST add the space needed for - * margins and borders when determining the actual pixel size of the - * window; in other words, the window should be large enough that it can - * actually display the given number or rows or columns. - * - * The size is interpreted as a width or height according to the window's - * orientation. For a TOP or BOTTOM banner, the size is the height; for a - * LEFT or RIGHT banner, the size is the width. A banner has only one - * dimension's size given, since the other dimension's size is determined - * automatically by the layout rules. - * - * Note that the window's size can be changed later using - * banner_size_to_contents() or banner_set_size(). - * - * 'style' is a combination of OS_BANNER_STYLE_xxx flags - see below. The - * style flags give the REQUESTED style for the banner, which might or - * might not be respected, depending on the platform's capabilities, user - * preferences, and other factors. os_banner_getinfo() can be used to - * determine which style flags are actually used. - * - * Returns the "handle" to the new banner window, which is an opaque value - * that is used in subsequent os_banner_xxx calls to operate on the window. - * Returns null if the window cannot be created. An implementation is not - * required to support this functionality at all, and can subset it if it - * does support it (for example, an implementation could support only - * top/bottom-aligned banners, but not left/right-aligned), so callers must - * be prepared for this routine to return null. - */ -void *os_banner_create(void *parent, int where, void *other, int wintype, - int align, int siz, int siz_units, - unsigned long style); - - -/* - * insertion positions - */ -#define OS_BANNER_FIRST 1 -#define OS_BANNER_LAST 2 -#define OS_BANNER_BEFORE 3 -#define OS_BANNER_AFTER 4 - -/* - * banner types - */ - -/* - * Normal text stream window. This is a text stream that behaves - * essentially like the main text window: text is displayed to this - * through os_banner_disp(), always in a stream-like fashion by adding new - * text to the end of any exiting text. - * - * Systems that use proportional fonts should usually simply use the same - * font they use by default in the main text window. However, note that - * the OS_BANNER_STYLE_TAB_ALIGN style flag might imply that a fixed-pitch - * font should be used even when proportional fonts are available, because - * a fixed-pitch font will allow the calling code to rely on using spaces - * to align text within the window. - */ -#define OS_BANNER_TYPE_TEXT 1 - -/* - * "Text grid" window. This type of window is similar to an normal text - * window (OS_BANNER_TYPE_TEXT), but is guaranteed to arrange its text in - * a regular grid of character cells, all of the same size. This means - * that the output position can be moved to an arbitrary point within the - * window at any time, so the calling program can precisely control the - * layout of the text in the window. - * - * Because the output position can be moved to arbitrary positions in the - * window, it is possible to overwrite text previously displayed. When - * this happens, the old text is completely obliterated by the new text, - * leaving no trace of the overwritten text. - * - * In order to guarantee that character cells are all the same size, this - * type of window does not allow any text attributes. The implementation - * should simply ignore any attempts to change text attributes in this - * type of window. However, colors can be used to the same degree they - * can be used in an ordinary text window. - * - * To guarantee the regular spacing of character cells, all - * implementations must use fixed-pitch fonts for these windows. This - * applies even to platforms where proportional fonts are available. - */ -#define OS_BANNER_TYPE_TEXTGRID 2 - - -/* - * banner alignment types - */ -#define OS_BANNER_ALIGN_TOP 0 -#define OS_BANNER_ALIGN_BOTTOM 1 -#define OS_BANNER_ALIGN_LEFT 2 -#define OS_BANNER_ALIGN_RIGHT 3 - -/* - * size units - */ -#define OS_BANNER_SIZE_PCT 1 -#define OS_BANNER_SIZE_ABS 2 - - -/* - * banner style flags - */ - -/* - * The banner has a visible border; this indicates that a line is to be - * drawn to separate the banner from the adjacent window or windows - * "inside" the banner. So, a top-aligned banner will have its border - * drawn along its bottom edge; a left-aligned banner will show a border - * along its right edge; and so forth. - * - * Note that character-mode platforms generally do NOT respect the border - * style, since doing so takes up too much screen space. - */ -#define OS_BANNER_STYLE_BORDER 0x00000001 - -/* - * The banner has a vertical/horizontal scrollbar. Character-mode - * platforms generally do not support scrollbars. - */ -#define OS_BANNER_STYLE_VSCROLL 0x00000002 -#define OS_BANNER_STYLE_HSCROLL 0x00000004 - -/* - * Automatically scroll the banner vertically/horizontally whenever new - * text is displayed in the window. In other words, whenever - * os_banner_disp() is called, scroll the window so that the text that the - * new cursor position after the new text is displayed is visible in the - * window. - * - * Note that this style is independent of the presence of scrollbars. - * Even if there are no scrollbars, we can still scroll the window's - * contents programmatically. - * - * Implementations can, if desired, keep an internal buffer of the - * window's contents, so that the contents can be recalled via the - * scrollbars if the text displayed in the banner exceeds the space - * available in the banner's window on the screen. If the implementation - * does keep such a buffer, we recommend the following method for managing - * this buffer. If the AUTO_VSCROLL flag is not set, then the banner's - * contents should be truncated at the bottom when the contents overflow - * the buffer; that is, once the banner's internal buffer is full, any new - * text that the calling program attempts to add to the banner should - * simply be discarded. If the AUTO_VSCROLL flag is set, then the OLDEST - * text should be discarded instead, so that the most recent text is - * always retained. - */ -#define OS_BANNER_STYLE_AUTO_VSCROLL 0x00000008 -#define OS_BANNER_STYLE_AUTO_HSCROLL 0x00000010 - -/* - * Tab-based alignment is required/supported. On creation, this is a hint - * to the implementation that is sometimes necessary to determine what - * kind of font to use in the new window, for non-HTML platforms. If this - * flag is set on creation, the caller is indicating that it wants to use - * <TAB> tags to align text in the window. - * - * Character-mode implementations that use a single font with fixed pitch - * can simply ignore this. These implementations ALWAYS have a working - * <TAB> capability, because the portable output formatter provides <TAB> - * interpretation for a fixed-pitch window. - * - * Full HTML TADS implementations can also ignore this. HTML TADS - * implementations always have full <TAB> support via the HTML - * parser/renderer. - * - * Text-only implementations on GUI platforms (i.e., implementations that - * are not based on the HTML parser/renderer engine in HTML TADS, but - * which run on GUI platforms with proportionally-spaced text) should use - * this flag to determine the font to display. If this flag is NOT set, - * then the caller doesn't care about <TAB>, and the implementation is - * free to use a proportionally-spaced font in the window if desired. - * - * When retrieving information on an existing banner, this flag indicates - * that <TAB> alignment is actually supported on the window. - */ -#define OS_BANNER_STYLE_TAB_ALIGN 0x00000020 - -/* - * Use "MORE" mode in this window. By default, a banner window should - * happily allow text to overflow the vertical limits of the window; the - * only special thing that should happen on overflow is that the window - * should be srolled down to show the latest text, if the auto-vscroll - * style is set. With this flag, though, a banner window acts just like - * the main text window: when the window fills up vertically, we show a - * MORE prompt (using appropriate system conventions), and wait for the - * user to indicate that they're ready to see more text. On most systems, - * the user acknowledges a MORE prompt by pressing a key or scrolling with - * the mouse, but it's up to the system implementor to decide what's - * appropriate for the system. - * - * Note that MORE mode in ANY banner window should generally override all - * other user input focus. In other words, if the game in the main window - * would like to read a keystroke from the user, but one of the banner - * windows is pausing with a MORE prompt, any keyboard input should be - * directed to the banner paused at the MORE prompt, not to the main - * window; the main window should not receive any key events until the MORE - * prompt has been removed. - * - * This style requires the auto-vscroll style. Implementations should - * assume auto-vscroll when this style is set. This style can be ignored - * with text grid windows. - */ -#define OS_BANNER_STYLE_MOREMODE 0x00000040 - -/* - * This banner is a horizontal/vertical "strut" for sizing purposes. This - * means that the banner's content size is taken into account when figuring - * the content size of its *parent* banner. If the banner has the same - * orientation as the parent, its content size is added to its parent's - * internal content size to determine the parent's overall content size. - * If the banner's orientation is orthogonal to the parent's, then the - * parent's overall content size is the larger of the parent's internal - * content size and this banner's content size. - */ -#define OS_BANNER_STYLE_HSTRUT 0x00000080 -#define OS_BANNER_STYLE_VSTRUT 0x00000100 - - -/* - * Delete a banner. This removes the banner from the display, which - * requires recalculating the entire screen's layout to reallocate this - * banner's space to other windows. When this routine returns, the banner - * handle is invalid and can no longer be used in any os_banner_xxx - * function calls. - * - * If the banner has children, the children will no longer be displayed, - * but will remain valid in memory until deleted. A child window's - * display area always comes out of its parent's space, so once the parent - * is gone, a child has no way to acquire any display space; resizing the - * child won't help, since it simply has no way to obtain any screen space - * once its parent has been deleted. Even though the window's children - * will become invisible, their banner handles will remain valid; the - * caller is responsible for explicitly deleting the children even after - * deleting their parent. - */ -void os_banner_delete(void *banner_handle); - -/* - * "Orphan" a banner. This tells the osifc implementation that the caller - * wishes to sever all of its ties with the banner (as part of program - * termination, for example), but that the calling program does not - * actually require that the banner's on-screen display be immediately - * removed. - * - * The osifc implementation can do one of two things: - * - * 1. Simply call os_banner_delete(). If the osifc implementation - * doesn't want to do anything extra with the banner, it can simply delete - * the banner, since the caller has no more use for it. - * - * 2. Take ownership of the banner. If the osifc implementation wishes - * to continue displaying the final screen configuration after a program - * has terminated, it can simply take over the banner and leave it on the - * screen. The osifc subsystem must eventually delete the banner itself - * if it takes this routine; for example, if the osifc subsystem allows - * another client program to be loaded into the same window after a - * previous program has terminated, it would want to delete any orphaned - * banners from the previous program when loading a new program. - */ -void os_banner_orphan(void *banner_handle); - -/* - * Banner information structure. This is filled in by the system-specific - * implementation in os_banner_getinfo(). - */ -struct os_banner_info_t -{ - /* alignment */ - int align; - - /* style flags - these indicate the style flags actually in use */ - unsigned long style; - - /* - * Actual on-screen size of the banner, in rows and columns. If the - * banner is displayed in a proportional font or can display multiple - * fonts of different sizes, this is approximated by the number of "0" - * characters in the window's default font that will fit in the - * window's display area. - */ - int rows; - int columns; - - /* - * Actual on-screen size of the banner in pixels. This is meaningful - * only for full HTML interpreter; for text-only interpreters, these - * are always set to zero. - * - * Note that even if we're running on a GUI operating system, these - * aren't meaningful unless this is a full HTML interpreter. Text-only - * interpreters should always set these to zero, even on GUI OS's. - */ - int pix_width; - int pix_height; - - /* - * OS line wrapping flag. If this is set, the window uses OS-level - * line wrapping because the window uses a proportional font, so the - * caller does not need to (and should not) perform line breaking in - * text displayed in the window. - * - * Note that OS line wrapping is a PERMANENT feature of the window. - * Callers can note this information once and expect it to remain - * fixed through the window's lifetime. - */ - int os_line_wrap; -}; -typedef struct os_banner_info_t os_banner_info_t; - -/* - * Get information on the banner - fills in the information structure with - * the banner's current settings. Note that this should indicate the - * ACTUAL properties of the banner, not the requested properties; this - * allows callers to determine how the banner is actually displayed, which - * depends upon the platform's capabilities and user preferences. - * - * Returns true if the information was successfully obtained, false if - * not. This can return false if the underlying OS window has already - * been closed by a user action, for example. - */ -int os_banner_getinfo(void *banner_handle, os_banner_info_t *info); - -/* - * Get the character width/height of the banner, for layout purposes. This - * gives the size of the banner in character cells. - * - * These are not meaningful when the underlying window uses a proportional - * font or varying fonts of different sizes. When the size of text varies - * in the window, the OS layer is responsible for word-wrapping and other - * layout, in which case these simply return zero. - * - * Note that these routines might appear to be redundant with the 'rows' - * and 'columns' information returned from os_banner_getinfo(), but these - * have two important distinctions. First, these routines return only the - * width and height information, so they can be implemented with less - * overhead than os_banner_getinfo(); this is important because formatters - * might need to call these routines frequently while formatting text. - * Second, these routines are not required to return an approximation for - * windows using proportional fonts, as os_banner_getinfo() does; these can - * simply return zero when a proportional font is in use. - */ -int os_banner_get_charwidth(void *banner_handle); -int os_banner_get_charheight(void *banner_handle); - -/* clear the contents of a banner */ -void os_banner_clear(void *banner_handle); - -/* - * Display output on a banner. Writes the output to the window on the - * display at the current output position. - * - * The following special characters should be recognized and handled: - * - * '\n' - newline; move output position to the start of the next line. - * - * '\r' - move output position to start of current line; subsequent text - * overwrites any text previously displayed on the current line. It is - * permissible to delete the old text immediately on seeing the '\r', - * rather than waiting for additional text to actually overwrite it. - * - * All other characters should simply be displayed as ordinary printing - * text characters. Note that tab characters should not be passed to this - * routine, but if they are, they can simply be treated as ordinary spaces - * if desired. Other control characters (backspace, escape, etc) should - * never be passed to this routine; the implementation is free to ignore - * any control characters not listed above. - * - * If any text displayed here overflows the current boundaries of the - * window on the screen, the text MUST be "clipped" to the current window - * boundaries; in other words, anything this routine tries to display - * outside of the window's on-screen rectangle must not actually be shown - * on the screen. - * - * Text overflowing the display boundaries MUST also be retained in an - * internal buffer. This internal buffer can be limited to the actual - * maximum display size of the terminal screen or application window, if - * desired. It is necessary to retain clipped text, because this allows a - * window to be expanded to the size of its contents AFTER the contents - * have already been displayed. - * - * If the banner does its own line wrapping, it must indicate this via the - * os_line_wrap flag in the os_banner_getinfo() return data. If the - * banner doesn't indicate this flag, then it must not do any line - * wrapping at all, even if the caller attempts to write text beyond the - * right edge of the window - any text overflowing the width of the window - * must simply be clipped. - * - * Text grid banners must ALWAYS clip - these banners should never perform - * any line wrapping. - */ -void os_banner_disp(void *banner_handle, const char *txt, size_t len); - -/* - * Set the text attributes in a banner, for subsequent text displays. - * 'attr' is a (bitwise-OR'd) combination of OS_ATTR_xxx values. - */ -void os_banner_set_attr(void *banner_handle, int attr); - -/* - * Set the text color in a banner, for subsequent text displays. The 'fg' - * and 'bg' colors are given as RGB or parameterized colors; see the - * definition of os_color_t for details. - * - * If the underlying renderer is HTML-enabled, then this should not be - * used; the appropriate HTML code should simply be displayed to the - * banner instead. - */ -void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg); - -/* - * Set the screen color in the banner - this is analogous to the screen - * color in the main text area. - * - * If the underlying renderer is HTML-enabled, then this should not be - * used; the HTML <BODY> tag should be used instead. - */ -void os_banner_set_screen_color(void *banner_handle, os_color_t color); - -/* flush output on a banner */ -void os_banner_flush(void *banner_handle); - -/* - * Set the banner's size. The size has the same meaning as in - * os_banner_create(). - * - * 'is_advisory' indicates whether the sizing is required or advisory only. - * If this flag is false, then the size should be set as requested. If - * this flag is true, it means that the caller intends to call - * os_banner_size_to_contents() at some point, and that the size being set - * now is for advisory purposes only. Platforms that support - * size-to-contents may simply ignore advisory sizing requests, although - * they might want to ensure that they have sufficient off-screen buffer - * space to keep track of the requested size of display, so that the - * information the caller displays in preparation for calling - * size-to-contents will be retained. Platforms that do not support - * size-to-contents should set the requested size even when 'is_advisory' - * is true. - */ -void os_banner_set_size(void *banner_handle, int siz, int siz_units, - int is_advisory); - -/* - * Set the banner to the size of its current contents. This can be used - * to set the banner's size after some text (or other material) has been - * displayed to the banner, so that the size can be set according to the - * banner's actual space requirements. - * - * This changes the banner's "requested size" to match the current size. - * Subsequent calls to os_banner_getinfo() will thus indicate a requested - * size according to the size set here. - */ -void os_banner_size_to_contents(void *banner_handle); - -/* - * Turn HTML mode on/off in the banner window. If the underlying renderer - * doesn't support HTML, these have no effect. - */ -void os_banner_start_html(void *banner_handle); -void os_banner_end_html(void *banner_handle); - -/* - * Set the output coordinates in a text grid window. The grid window is - * arranged into character cells numbered from row zero, column zero for - * the upper left cell. This function can only be used if the window was - * created with type OS_BANNER_TYPE_TEXTGRID; the request should simply be - * ignored by other window types. - * - * Moving the output position has no immediate effect on the display, and - * does not itself affect the "content size" for the purposes of - * os_banner_size_to_contents(). This simply sets the coordinates where - * any subsequent text is displayed. - */ -void os_banner_goto(void *banner_handle, int row, int col); - - /* ------------------------------------------------------------------------ */ /* * Get system information. 'code' is a SYSINFO_xxx code, which diff --git a/engines/glk/tads/os_parse.cpp b/engines/glk/tads/os_parse.cpp new file mode 100644 index 0000000000..d722d14e05 --- /dev/null +++ b/engines/glk/tads/os_parse.cpp @@ -0,0 +1,989 @@ +/* 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/os_parse.h" +#include "glk/glk_types.h" + +namespace Glk { +namespace TADS { + +#ifdef GLK_MODULE_UNICODE + +enum CHARMAPS { OS_UTF8, OS_CP1251, OS_CP1252, OS_MACROMAN, OS_UNKNOWN }; + +static uint os_charmap = OS_UTF8; + +uint is_cyrillic(unsigned char ch) +{ + if (ch >= 0xBC) + return 1; + + switch (ch) + { + case 0x80: + case 0x81: + case 0x83: + case 0x8A: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x9A: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA5: + case 0xA8: + case 0xAA: + case 0xAF: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB8: + case 0xBA: + return 1; + + default: + return 0; + } +} + +uint is_macroman (unsigned char ch) +{ + switch (ch) + { + /* trademarks */ + case 0xA8: + case 0xAA: + return 1; + + /* dashes and right quotes */ + case 0xD0: + case 0xD1: + case 0xD3: + case 0xD5: + return 1; + + /* accents */ + case 0x8E: + case 0x8F: + case 0x9A: + return 1; + + default: + return 0; + } +} + +uint is_cp1252 (unsigned char ch) +{ + switch (ch) + { + /* trademarks */ + case 0x99: + case 0xAE: + return 1; + + /* dashes and right quotes */ + case 0x92: + case 0x94: + case 0x96: + case 0x97: + return 1; + + /* accents */ + case 0xE8: + case 0xE9: + case 0xF6: + return 1; + + default: + return 0; + } +} + +uint identify_chars(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) { + uint pos = 0; + uint val = 0; + uint count_macroman = 0; + uint count_cp1252 = 0; + uint wordlen = 0; + uint cyrilen = 0; + uint charmap = OS_UNKNOWN; + + while (pos < buflen) + { + val = buf[pos++]; + + count_macroman += is_macroman(val); + count_cp1252 += is_cp1252(val); + + if (val != 0x20) + { + wordlen++; + cyrilen += is_cyrillic(val); + } + else + { + if (wordlen == cyrilen) + { + charmap = OS_CP1251; + break; + } + wordlen = 0; + cyrilen = 0; + } + } + + if (charmap == OS_CP1251) + os_charmap = OS_CP1251; + else if (count_cp1252 >= count_macroman) + os_charmap = OS_CP1252; + else + os_charmap = OS_MACROMAN; + + return os_parse_chars(buf, buflen, out, outlen); +} + +uint parse_utf8(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) +{ + uint pos = 0; + uint outpos = 0; + uint res; + uint val0, val1, val2, val3; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + val0 = buf[pos++]; + + if (val0 < 0x80) + { + res = val0; + out[outpos++] = res; + continue; + } + + if ((val0 & 0xe0) == 0xc0) + { + if (pos+1 > buflen) + { + //printf("incomplete two-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + val1 = buf[pos++]; + if ((val1 & 0xc0) != 0x80) + { + //printf("malformed two-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + res = (val0 & 0x1f) << 6; + res |= (val1 & 0x3f); + out[outpos++] = res; + continue; + } + + if ((val0 & 0xf0) == 0xe0) + { + if (pos+2 > buflen) + { + //printf("incomplete three-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + val1 = buf[pos++]; + val2 = buf[pos++]; + if ((val1 & 0xc0) != 0x80) + { + //printf("malformed three-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + if ((val2 & 0xc0) != 0x80) + { + //printf("malformed three-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + res = (((val0 & 0xf)<<12) & 0x0000f000); + res |= (((val1 & 0x3f)<<6) & 0x00000fc0); + res |= (((val2 & 0x3f)) & 0x0000003f); + out[outpos++] = res; + continue; + } + + if ((val0 & 0xf0) == 0xf0) + { + if ((val0 & 0xf8) != 0xf0) + { + //printf("malformed four-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + if (pos+3 > buflen) + { + //printf("incomplete four-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + val1 = buf[pos++]; + val2 = buf[pos++]; + val3 = buf[pos++]; + if ((val1 & 0xc0) != 0x80) + { + //printf("malformed four-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + if ((val2 & 0xc0) != 0x80) + { + //printf("malformed four-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + if ((val3 & 0xc0) != 0x80) + { + //printf("malformed four-byte character\n"); + return identify_chars(buf, buflen, out, outlen); + } + res = (((val0 & 0x7)<<18) & 0x1c0000); + res |= (((val1 & 0x3f)<<12) & 0x03f000); + res |= (((val2 & 0x3f)<<6) & 0x000fc0); + res |= (((val3 & 0x3f)) & 0x00003f); + out[outpos++] = res; + continue; + } + + //printf("malformed character\n"); + return identify_chars(buf, buflen, out, outlen); + } + + return outpos; +} + +uint prepare_utf8(const uint32 *buf, uint buflen, unsigned char *out, uint outlen) +{ + uint i=0, k=0; + + /*convert UTF-32 to UTF-8 */ + while (i < buflen && k < outlen) + { + if ((buf[i] < 0x80)) + { + out[k] = buf[i]; + k++; + } + else if ((buf[i] < 0x800) && (k < outlen - 1)) + { + out[k ] = (0xC0 | ((buf[i] & 0x7C0) >> 6)); + out[k+1] = (0x80 | (buf[i] & 0x03F) ); + k = k + 2; + } + else if ((buf[i] < 0x10000) && (k < outlen - 2)) + { + out[k ] = (0xE0 | ((buf[i] & 0xF000) >> 12)); + out[k+1] = (0x80 | ((buf[i] & 0x0FC0) >> 6)); + out[k+2] = (0x80 | (buf[i] & 0x003F) ); + k = k + 3; + } + else if ((buf[i] < 0x200000) && (k < outlen - 3)) + { + out[k ] = (0xF0 | ((buf[i] & 0x1C0000) >> 18)); + out[k+1] = (0x80 | ((buf[i] & 0x03F000) >> 12)); + out[k+2] = (0x80 | ((buf[i] & 0x000FC0) >> 6)); + out[k+3] = (0x80 | (buf[i] & 0x00003F) ); + k = k + 4; + } + else + { + out[k] = '?'; + k++; + } + i++; + } + + return k; +} + +/* http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT */ + +static const uint CP1251ToUnicode[128] = { + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, 0x2030, + 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, 0x0452, 0x2018, 0x2019, 0x201C, + 0x201D, 0x2022, 0x2013, 0x2014, 0x003F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, + 0x045B, 0x045F, 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, 0x00B0, 0x00B1, + 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, 0x0451, 0x2116, 0x0454, 0x00BB, + 0x0458, 0x0405, 0x0455, 0x0457, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, + 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, + 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, + 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, + 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F + +}; + +uint parse_cp1251(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) { + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + out[outpos++] = res; + else + out[outpos++] = CP1251ToUnicode[res - 0x80]; + } + + return outpos; +} + +uint prepare_cp1251(const uint *buf, uint buflen, + unsigned char *out, uint outlen) +{ + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + { + out[outpos++] = res; + continue; + } + + switch (res) + { + case 0x0402: out[outpos++] = 0x80; break; + case 0x0403: out[outpos++] = 0x81; break; + case 0x201A: out[outpos++] = 0x82; break; + case 0x0453: out[outpos++] = 0x83; break; + case 0x201E: out[outpos++] = 0x84; break; + case 0x2026: out[outpos++] = 0x85; break; + case 0x2020: out[outpos++] = 0x86; break; + case 0x2021: out[outpos++] = 0x87; break; + case 0x20AC: out[outpos++] = 0x88; break; + case 0x2030: out[outpos++] = 0x89; break; + case 0x0409: out[outpos++] = 0x8A; break; + case 0x2039: out[outpos++] = 0x8B; break; + case 0x040A: out[outpos++] = 0x8C; break; + case 0x040C: out[outpos++] = 0x8D; break; + case 0x040B: out[outpos++] = 0x8E; break; + case 0x040F: out[outpos++] = 0x8F; break; + + case 0x0452: out[outpos++] = 0x90; break; + case 0x2018: out[outpos++] = 0x91; break; + case 0x2019: out[outpos++] = 0x92; break; + case 0x201C: out[outpos++] = 0x93; break; + case 0x201D: out[outpos++] = 0x94; break; + case 0x2022: out[outpos++] = 0x95; break; + case 0x2013: out[outpos++] = 0x96; break; + case 0x2014: out[outpos++] = 0x97; break; + case 0x2122: out[outpos++] = 0x99; break; + case 0x0459: out[outpos++] = 0x9A; break; + case 0x203A: out[outpos++] = 0x9B; break; + case 0x045A: out[outpos++] = 0x9C; break; + case 0x045C: out[outpos++] = 0x9D; break; + case 0x045B: out[outpos++] = 0x9E; break; + case 0x045F: out[outpos++] = 0x9F; break; + + case 0x00A0: out[outpos++] = 0xA0; break; + case 0x040E: out[outpos++] = 0xA1; break; + case 0x045E: out[outpos++] = 0xA2; break; + case 0x0408: out[outpos++] = 0xA3; break; + case 0x00A4: out[outpos++] = 0xA4; break; + case 0x0490: out[outpos++] = 0xA5; break; + case 0x00A6: out[outpos++] = 0xA6; break; + case 0x00A7: out[outpos++] = 0xA7; break; + case 0x0401: out[outpos++] = 0xA8; break; + case 0x00A9: out[outpos++] = 0xA9; break; + case 0x0404: out[outpos++] = 0xAA; break; + case 0x00AB: out[outpos++] = 0xAB; break; + case 0x00AC: out[outpos++] = 0xAC; break; + case 0x00AD: out[outpos++] = 0xAD; break; + case 0x00AE: out[outpos++] = 0xAE; break; + case 0x0407: out[outpos++] = 0xAF; break; + + case 0x00B0: out[outpos++] = 0xB0; break; + case 0x00B1: out[outpos++] = 0xB1; break; + case 0x0406: out[outpos++] = 0xB2; break; + case 0x0456: out[outpos++] = 0xB3; break; + case 0x0491: out[outpos++] = 0xB4; break; + case 0x00B5: out[outpos++] = 0xB5; break; + case 0x00B6: out[outpos++] = 0xB6; break; + case 0x00B7: out[outpos++] = 0xB7; break; + case 0x0451: out[outpos++] = 0xB8; break; + case 0x2116: out[outpos++] = 0xB9; break; + case 0x0454: out[outpos++] = 0xBA; break; + case 0x00BB: out[outpos++] = 0xBB; break; + case 0x0458: out[outpos++] = 0xBC; break; + case 0x0405: out[outpos++] = 0xBD; break; + case 0x0455: out[outpos++] = 0xBE; break; + case 0x0457: out[outpos++] = 0xBF; break; + + case 0x0410: out[outpos++] = 0xC0; break; + case 0x0411: out[outpos++] = 0xC1; break; + case 0x0412: out[outpos++] = 0xC2; break; + case 0x0413: out[outpos++] = 0xC3; break; + case 0x0414: out[outpos++] = 0xC4; break; + case 0x0415: out[outpos++] = 0xC5; break; + case 0x0416: out[outpos++] = 0xC6; break; + case 0x0417: out[outpos++] = 0xC7; break; + case 0x0418: out[outpos++] = 0xC8; break; + case 0x0419: out[outpos++] = 0xC9; break; + case 0x041A: out[outpos++] = 0xCA; break; + case 0x041B: out[outpos++] = 0xCB; break; + case 0x041C: out[outpos++] = 0xCC; break; + case 0x041D: out[outpos++] = 0xCD; break; + case 0x041E: out[outpos++] = 0xCE; break; + case 0x041F: out[outpos++] = 0xCF; break; + + case 0x0420: out[outpos++] = 0xD0; break; + case 0x0421: out[outpos++] = 0xD1; break; + case 0x0422: out[outpos++] = 0xD2; break; + case 0x0423: out[outpos++] = 0xD3; break; + case 0x0424: out[outpos++] = 0xD4; break; + case 0x0425: out[outpos++] = 0xD5; break; + case 0x0426: out[outpos++] = 0xD6; break; + case 0x0427: out[outpos++] = 0xD7; break; + case 0x0428: out[outpos++] = 0xD8; break; + case 0x0429: out[outpos++] = 0xD9; break; + case 0x042A: out[outpos++] = 0xDA; break; + case 0x042B: out[outpos++] = 0xDB; break; + case 0x042C: out[outpos++] = 0xDC; break; + case 0x042D: out[outpos++] = 0xDD; break; + case 0x042E: out[outpos++] = 0xDE; break; + case 0x042F: out[outpos++] = 0xDF; break; + + case 0x0430: out[outpos++] = 0xE0; break; + case 0x0431: out[outpos++] = 0xE1; break; + case 0x0432: out[outpos++] = 0xE2; break; + case 0x0433: out[outpos++] = 0xE3; break; + case 0x0434: out[outpos++] = 0xE4; break; + case 0x0435: out[outpos++] = 0xE5; break; + case 0x0436: out[outpos++] = 0xE6; break; + case 0x0437: out[outpos++] = 0xE7; break; + case 0x0438: out[outpos++] = 0xE8; break; + case 0x0439: out[outpos++] = 0xE9; break; + case 0x043A: out[outpos++] = 0xEA; break; + case 0x043B: out[outpos++] = 0xEB; break; + case 0x043C: out[outpos++] = 0xEC; break; + case 0x043D: out[outpos++] = 0xED; break; + case 0x043E: out[outpos++] = 0xEE; break; + case 0x043F: out[outpos++] = 0xEF; break; + + case 0x0440: out[outpos++] = 0xF0; break; + case 0x0441: out[outpos++] = 0xF1; break; + case 0x0442: out[outpos++] = 0xF2; break; + case 0x0443: out[outpos++] = 0xF3; break; + case 0x0444: out[outpos++] = 0xF4; break; + case 0x0445: out[outpos++] = 0xF5; break; + case 0x0446: out[outpos++] = 0xF6; break; + case 0x0447: out[outpos++] = 0xF7; break; + case 0x0448: out[outpos++] = 0xF8; break; + case 0x0449: out[outpos++] = 0xF9; break; + case 0x044A: out[outpos++] = 0xFA; break; + case 0x044B: out[outpos++] = 0xFB; break; + case 0x044C: out[outpos++] = 0xFC; break; + case 0x044D: out[outpos++] = 0xFD; break; + case 0x044E: out[outpos++] = 0xFE; break; + case 0x044F: out[outpos++] = 0xFF; break; + + default: + /* undefined */ + out[outpos++] = '?'; + break; + } + + continue; + } + + return outpos; +} + +/* http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT */ + +static const uint CP1252ToUnicode[128] = { + 0x20AC, 0x003F, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, + 0x0160, 0x2039, 0x0152, 0x003F, 0x017D, 0x003F, 0x003F, 0x2018, 0x2019, 0x201C, + 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x003F, + 0x017E, 0x0178, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, + 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, + 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, + 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, + 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, + 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, + 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF +}; + +uint parse_cp1252(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) { + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + out[outpos++] = res; + else + out[outpos++] = CP1252ToUnicode[res - 0x80]; + } + + return outpos; +} + +uint prepare_cp1252(const uint *buf, uint buflen, + unsigned char *out, uint outlen) +{ + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + { + out[outpos++] = res; + continue; + } + + switch (res) + { + case 0x20AC: out[outpos++] = 0x80; break; + case 0x201A: out[outpos++] = 0x82; break; + case 0x0192: out[outpos++] = 0x83; break; + case 0x201E: out[outpos++] = 0x84; break; + case 0x2026: out[outpos++] = 0x85; break; + case 0x2020: out[outpos++] = 0x86; break; + case 0x2021: out[outpos++] = 0x87; break; + case 0x02C6: out[outpos++] = 0x88; break; + case 0x2030: out[outpos++] = 0x89; break; + case 0x0160: out[outpos++] = 0x8A; break; + case 0x2039: out[outpos++] = 0x8B; break; + case 0x0152: out[outpos++] = 0x8C; break; + case 0x017D: out[outpos++] = 0x8E; break; + + case 0x2018: out[outpos++] = 0x91; break; + case 0x2019: out[outpos++] = 0x92; break; + case 0x201C: out[outpos++] = 0x93; break; + case 0x201D: out[outpos++] = 0x94; break; + case 0x2022: out[outpos++] = 0x95; break; + case 0x2013: out[outpos++] = 0x96; break; + case 0x2014: out[outpos++] = 0x97; break; + case 0x02DC: out[outpos++] = 0x98; break; + case 0x2122: out[outpos++] = 0x99; break; + case 0x0161: out[outpos++] = 0x9A; break; + case 0x203A: out[outpos++] = 0x9B; break; + case 0x0153: out[outpos++] = 0x9C; break; + case 0x017E: out[outpos++] = 0x9E; break; + case 0x0178: out[outpos++] = 0x9F; break; + + case 0x00A0: out[outpos++] = 0xA0; break; + case 0x00A1: out[outpos++] = 0xA1; break; + case 0x00A2: out[outpos++] = 0xA2; break; + case 0x00A3: out[outpos++] = 0xA3; break; + case 0x00A4: out[outpos++] = 0xA4; break; + case 0x00A5: out[outpos++] = 0xA5; break; + case 0x00A6: out[outpos++] = 0xA6; break; + case 0x00A7: out[outpos++] = 0xA7; break; + case 0x00A8: out[outpos++] = 0xA8; break; + case 0x00A9: out[outpos++] = 0xA9; break; + case 0x00AA: out[outpos++] = 0xAA; break; + case 0x00AB: out[outpos++] = 0xAB; break; + case 0x00AC: out[outpos++] = 0xAC; break; + case 0x00AD: out[outpos++] = 0xAD; break; + case 0x00AE: out[outpos++] = 0xAE; break; + case 0x00AF: out[outpos++] = 0xAF; break; + + case 0x00B0: out[outpos++] = 0xB0; break; + case 0x00B1: out[outpos++] = 0xB1; break; + case 0x00B2: out[outpos++] = 0xB2; break; + case 0x00B3: out[outpos++] = 0xB3; break; + case 0x00B4: out[outpos++] = 0xB4; break; + case 0x00B5: out[outpos++] = 0xB5; break; + case 0x00B6: out[outpos++] = 0xB6; break; + case 0x00B7: out[outpos++] = 0xB7; break; + case 0x00B8: out[outpos++] = 0xB8; break; + case 0x00B9: out[outpos++] = 0xB9; break; + case 0x00BA: out[outpos++] = 0xBA; break; + case 0x00BB: out[outpos++] = 0xBB; break; + case 0x00BC: out[outpos++] = 0xBC; break; + case 0x00BD: out[outpos++] = 0xBD; break; + case 0x00BE: out[outpos++] = 0xBE; break; + case 0x00BF: out[outpos++] = 0xBF; break; + + case 0x00C0: out[outpos++] = 0xC0; break; + case 0x00C1: out[outpos++] = 0xC1; break; + case 0x00C2: out[outpos++] = 0xC2; break; + case 0x00C3: out[outpos++] = 0xC3; break; + case 0x00C4: out[outpos++] = 0xC4; break; + case 0x00C5: out[outpos++] = 0xC5; break; + case 0x00C6: out[outpos++] = 0xC6; break; + case 0x00C7: out[outpos++] = 0xC7; break; + case 0x00C8: out[outpos++] = 0xC8; break; + case 0x00C9: out[outpos++] = 0xC9; break; + case 0x00CA: out[outpos++] = 0xCA; break; + case 0x00CB: out[outpos++] = 0xCB; break; + case 0x00CC: out[outpos++] = 0xCC; break; + case 0x00CD: out[outpos++] = 0xCD; break; + case 0x00CE: out[outpos++] = 0xCE; break; + case 0x00CF: out[outpos++] = 0xCF; break; + + case 0x00D0: out[outpos++] = 0xD0; break; + case 0x00D1: out[outpos++] = 0xD1; break; + case 0x00D2: out[outpos++] = 0xD2; break; + case 0x00D3: out[outpos++] = 0xD3; break; + case 0x00D4: out[outpos++] = 0xD4; break; + case 0x00D5: out[outpos++] = 0xD5; break; + case 0x00D6: out[outpos++] = 0xD6; break; + case 0x00D7: out[outpos++] = 0xD7; break; + case 0x00D8: out[outpos++] = 0xD8; break; + case 0x00D9: out[outpos++] = 0xD9; break; + case 0x00DA: out[outpos++] = 0xDA; break; + case 0x00DB: out[outpos++] = 0xDB; break; + case 0x00DC: out[outpos++] = 0xDC; break; + case 0x00DD: out[outpos++] = 0xDD; break; + case 0x00DE: out[outpos++] = 0xDE; break; + case 0x00DF: out[outpos++] = 0xDF; break; + + case 0x00E0: out[outpos++] = 0xE0; break; + case 0x00E1: out[outpos++] = 0xE1; break; + case 0x00E2: out[outpos++] = 0xE2; break; + case 0x00E3: out[outpos++] = 0xE3; break; + case 0x00E4: out[outpos++] = 0xE4; break; + case 0x00E5: out[outpos++] = 0xE5; break; + case 0x00E6: out[outpos++] = 0xE6; break; + case 0x00E7: out[outpos++] = 0xE7; break; + case 0x00E8: out[outpos++] = 0xE8; break; + case 0x00E9: out[outpos++] = 0xE9; break; + case 0x00EA: out[outpos++] = 0xEA; break; + case 0x00EB: out[outpos++] = 0xEB; break; + case 0x00EC: out[outpos++] = 0xEC; break; + case 0x00ED: out[outpos++] = 0xED; break; + case 0x00EE: out[outpos++] = 0xEE; break; + case 0x00EF: out[outpos++] = 0xEF; break; + + case 0x00F0: out[outpos++] = 0xF0; break; + case 0x00F1: out[outpos++] = 0xF1; break; + case 0x00F2: out[outpos++] = 0xF2; break; + case 0x00F3: out[outpos++] = 0xF3; break; + case 0x00F4: out[outpos++] = 0xF4; break; + case 0x00F5: out[outpos++] = 0xF5; break; + case 0x00F6: out[outpos++] = 0xF6; break; + case 0x00F7: out[outpos++] = 0xF7; break; + case 0x00F8: out[outpos++] = 0xF8; break; + case 0x00F9: out[outpos++] = 0xF9; break; + case 0x00FA: out[outpos++] = 0xFA; break; + case 0x00FB: out[outpos++] = 0xFB; break; + case 0x00FC: out[outpos++] = 0xFC; break; + case 0x00FD: out[outpos++] = 0xFD; break; + case 0x00FE: out[outpos++] = 0xFE; break; + case 0x00FF: out[outpos++] = 0xFF; break; + + default: + /* undefined */ + out[outpos++] = '?'; + break; + } + + continue; + } + + return outpos; +} + +/* http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT */ + +static const uint MacRomanToUnicode[128] = { + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, + 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, 0x00EA, 0x00EB, 0x00ED, 0x00EC, + 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, + 0x00FB, 0x00FC, 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, 0x221E, 0x00B1, + 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, + 0x00BA, 0x03A9, 0x00E6, 0x00F8, 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, + 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, + 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, 0x2021, 0x00B7, 0x201A, 0x201E, + 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, + 0x00D3, 0x00D4, 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 +}; + +uint parse_mac(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) { + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + out[outpos++] = res; + else + out[outpos++] = MacRomanToUnicode[res - 0x80]; + } + + return outpos; +} + +uint prepare_mac(const uint *buf, uint buflen, unsigned char *out, uint outlen) { + uint pos = 0; + uint outpos = 0; + uint res; + + while (outpos < outlen) + { + if (pos >= buflen) + break; + + res = buf[pos++]; + + if (res < 0x80) + { + out[outpos++] = res; + continue; + } + + switch (res) + { + case 0x00C4: out[outpos++] = 0x80; break; + case 0x00C5: out[outpos++] = 0x81; break; + case 0x00C7: out[outpos++] = 0x82; break; + case 0x00C9: out[outpos++] = 0x83; break; + case 0x00D1: out[outpos++] = 0x84; break; + case 0x00D6: out[outpos++] = 0x85; break; + case 0x00DC: out[outpos++] = 0x86; break; + case 0x00E1: out[outpos++] = 0x87; break; + case 0x00E0: out[outpos++] = 0x88; break; + case 0x00E2: out[outpos++] = 0x89; break; + case 0x00E4: out[outpos++] = 0x8A; break; + case 0x00E3: out[outpos++] = 0x8B; break; + case 0x00E5: out[outpos++] = 0x8C; break; + case 0x00E7: out[outpos++] = 0x8D; break; + case 0x00E9: out[outpos++] = 0x8E; break; + case 0x00E8: out[outpos++] = 0x8F; break; + + case 0x00EA: out[outpos++] = 0x90; break; + case 0x00EB: out[outpos++] = 0x91; break; + case 0x00ED: out[outpos++] = 0x92; break; + case 0x00EC: out[outpos++] = 0x93; break; + case 0x00EE: out[outpos++] = 0x94; break; + case 0x00EF: out[outpos++] = 0x95; break; + case 0x00F1: out[outpos++] = 0x96; break; + case 0x00F3: out[outpos++] = 0x97; break; + case 0x00F2: out[outpos++] = 0x98; break; + case 0x00F4: out[outpos++] = 0x99; break; + case 0x00F6: out[outpos++] = 0x9A; break; + case 0x00F5: out[outpos++] = 0x9B; break; + case 0x00FA: out[outpos++] = 0x9C; break; + case 0x00F9: out[outpos++] = 0x9D; break; + case 0x00FB: out[outpos++] = 0x9E; break; + case 0x00FC: out[outpos++] = 0x9F; break; + + case 0x2020: out[outpos++] = 0xA0; break; + case 0x00B0: out[outpos++] = 0xA1; break; + case 0x00A2: out[outpos++] = 0xA2; break; + case 0x00A3: out[outpos++] = 0xA3; break; + case 0x00A7: out[outpos++] = 0xA4; break; + case 0x2022: out[outpos++] = 0xA5; break; + case 0x00B6: out[outpos++] = 0xA6; break; + case 0x00DF: out[outpos++] = 0xA7; break; + case 0x00AE: out[outpos++] = 0xA8; break; + case 0x00A9: out[outpos++] = 0xA9; break; + case 0x2122: out[outpos++] = 0xAA; break; + case 0x00B4: out[outpos++] = 0xAB; break; + case 0x00A8: out[outpos++] = 0xAC; break; + case 0x2260: out[outpos++] = 0xAD; break; + case 0x00C6: out[outpos++] = 0xAE; break; + case 0x00D8: out[outpos++] = 0xAF; break; + + case 0x221E: out[outpos++] = 0xB0; break; + case 0x00B1: out[outpos++] = 0xB1; break; + case 0x2264: out[outpos++] = 0xB2; break; + case 0x2265: out[outpos++] = 0xB3; break; + case 0x00A5: out[outpos++] = 0xB4; break; + case 0x00B5: out[outpos++] = 0xB5; break; + case 0x2202: out[outpos++] = 0xB6; break; + case 0x2211: out[outpos++] = 0xB7; break; + case 0x220F: out[outpos++] = 0xB8; break; + case 0x03C0: out[outpos++] = 0xB9; break; + case 0x222B: out[outpos++] = 0xBA; break; + case 0x00AA: out[outpos++] = 0xBB; break; + case 0x00BA: out[outpos++] = 0xBC; break; + case 0x03A9: out[outpos++] = 0xBD; break; + case 0x00E6: out[outpos++] = 0xBE; break; + case 0x00F8: out[outpos++] = 0xBF; break; + + case 0x00BF: out[outpos++] = 0xC0; break; + case 0x00A1: out[outpos++] = 0xC1; break; + case 0x00AC: out[outpos++] = 0xC2; break; + case 0x221A: out[outpos++] = 0xC3; break; + case 0x0192: out[outpos++] = 0xC4; break; + case 0x2248: out[outpos++] = 0xC5; break; + case 0x2206: out[outpos++] = 0xC6; break; + case 0x00AB: out[outpos++] = 0xC7; break; + case 0x00BB: out[outpos++] = 0xC8; break; + case 0x2026: out[outpos++] = 0xC9; break; + case 0x00A0: out[outpos++] = 0xCA; break; + case 0x00C0: out[outpos++] = 0xCB; break; + case 0x00C3: out[outpos++] = 0xCC; break; + case 0x00D5: out[outpos++] = 0xCD; break; + case 0x0152: out[outpos++] = 0xCE; break; + case 0x0153: out[outpos++] = 0xCF; break; + + case 0x2013: out[outpos++] = 0xD0; break; + case 0x2014: out[outpos++] = 0xD1; break; + case 0x201C: out[outpos++] = 0xD2; break; + case 0x201D: out[outpos++] = 0xD3; break; + case 0x2018: out[outpos++] = 0xD4; break; + case 0x2019: out[outpos++] = 0xD5; break; + case 0x00F7: out[outpos++] = 0xD6; break; + case 0x25CA: out[outpos++] = 0xD7; break; + case 0x00FF: out[outpos++] = 0xD8; break; + case 0x0178: out[outpos++] = 0xD9; break; + case 0x2044: out[outpos++] = 0xDA; break; + case 0x20AC: out[outpos++] = 0xDB; break; + case 0x2039: out[outpos++] = 0xDC; break; + case 0x203A: out[outpos++] = 0xDD; break; + case 0xFB01: out[outpos++] = 0xDE; break; + case 0xFB02: out[outpos++] = 0xDF; break; + + case 0x2021: out[outpos++] = 0xE0; break; + case 0x00B7: out[outpos++] = 0xE1; break; + case 0x201A: out[outpos++] = 0xE2; break; + case 0x201E: out[outpos++] = 0xE3; break; + case 0x2030: out[outpos++] = 0xE4; break; + case 0x00C2: out[outpos++] = 0xE5; break; + case 0x00CA: out[outpos++] = 0xE6; break; + case 0x00C1: out[outpos++] = 0xE7; break; + case 0x00CB: out[outpos++] = 0xE8; break; + case 0x00C8: out[outpos++] = 0xE9; break; + case 0x00CD: out[outpos++] = 0xEA; break; + case 0x00CE: out[outpos++] = 0xEB; break; + case 0x00CF: out[outpos++] = 0xEC; break; + case 0x00CC: out[outpos++] = 0xED; break; + case 0x00D3: out[outpos++] = 0xEE; break; + case 0x00D4: out[outpos++] = 0xEF; break; + + case 0xF8FF: out[outpos++] = 0xF0; break; + case 0x00D2: out[outpos++] = 0xF1; break; + case 0x00DA: out[outpos++] = 0xF2; break; + case 0x00DB: out[outpos++] = 0xF3; break; + case 0x00D9: out[outpos++] = 0xF4; break; + case 0x0131: out[outpos++] = 0xF5; break; + case 0x02C6: out[outpos++] = 0xF6; break; + case 0x02DC: out[outpos++] = 0xF7; break; + case 0x00AF: out[outpos++] = 0xF8; break; + case 0x02D8: out[outpos++] = 0xF9; break; + case 0x02D9: out[outpos++] = 0xFA; break; + case 0x02DA: out[outpos++] = 0xFB; break; + case 0x00B8: out[outpos++] = 0xFC; break; + case 0x02DD: out[outpos++] = 0xFD; break; + case 0x02DB: out[outpos++] = 0xFE; break; + case 0x02C7: out[outpos++] = 0xFF; break; + + default: + /* undefined */ + out[outpos++] = '?'; + break; + } + + continue; + } + + return outpos; +} + +uint os_parse_chars(const unsigned char *buf, uint buflen, uint32 *out, uint outlen) { + switch (os_charmap) + { + case OS_UTF8: + return parse_utf8(buf, buflen, out, outlen); + + case OS_CP1251: + return parse_cp1251(buf, buflen, out, outlen); + + case OS_CP1252: + return parse_cp1252(buf, buflen, out, outlen); + + case OS_MACROMAN: + return parse_mac(buf, buflen, out, outlen); + + default: + return 0; + } +} + +uint os_prepare_chars(const uint32 *buf, uint buflen, unsigned char *out, uint outlen) { + switch (os_charmap) { + case OS_UTF8: + return prepare_utf8(buf, buflen, out, outlen); + + case OS_CP1251: + return prepare_cp1251(buf, buflen, out, outlen); + + case OS_CP1252: + return prepare_cp1252(buf, buflen, out, outlen); + + case OS_MACROMAN: + return prepare_mac(buf, buflen, out, outlen); + + default: + return 0; + } +} + +#endif /* GLK_MODULE_UNICODE */ + +} // End of namespace TADS +} // End of namespace Glk diff --git a/engines/glk/tads/os_parse.h b/engines/glk/tads/os_parse.h new file mode 100644 index 0000000000..05f88c2889 --- /dev/null +++ b/engines/glk/tads/os_parse.h @@ -0,0 +1,43 @@ +/* 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. + * + */ + +/* TADS OS interface file type definitions + * + * Defines certain datatypes used in the TADS operating system interface + */ + +#ifndef GLK_TADS_OS_PARSE +#define GLK_TADS_OS_PARSE + +#include "common/scummsys.h" + +namespace Glk { +namespace TADS { + +extern uint os_parse_chars(const unsigned char *buf, uint buflen, uint32 *out, uint outlen); + +extern uint os_prepare_chars(const uint32 *buf, uint buflen, unsigned char *out, uint outlen); + +} // End of namespace TADS +} // End of namespace Glk + +#endif diff --git a/engines/glk/tads/tads2/debug.h b/engines/glk/tads/tads2/debug.h index 52695cfb86..0e7369e232 100644 --- a/engines/glk/tads/tads2/debug.h +++ b/engines/glk/tads/tads2/debug.h @@ -25,6 +25,7 @@ #include "glk/tads/tads2/lib.h" #include "glk/tads/tads2/object.h" +#include "glk/tads/os_glk.h" namespace Glk { namespace TADS { @@ -181,7 +182,7 @@ void dbgclin(struct tokcxdef *tokctx, objnum objn, uint ofs); * the program define the appropriate implementation through the linker. */ #ifdef DBG_OFF -#define dbgpresent() (FALSE) +#define dbgpresent() (false) #else int dbgpresent(); #endif @@ -545,22 +546,22 @@ void trcsho(void); */ #ifdef DBG_OFF -# define dbgenter(ctx, bp, self, target, prop, binum, argc) -# define dbgleave(ctx, exittype) -# define dbgdump(ctx) -# define dbgrst(ctx) ((void)0) -# define dbgframe(ctx, frofs, linofs) -# define dbgssi(ctx, ofs, instr, err, p) +#define dbgenter(ctx, bp, self, target, prop, binum, argc) +#define dbgleave(ctx, exittype) +#define dbgdump(ctx) ((void)0) +#define dbgrst(ctx) ((void)0) +#define dbgframe(ctx, frofs, linofs) +#define dbgssi(ctx, ofs, instr, err, p) ((void)0) #else /* DBG_OFF */ -# define dbgenter(ctx, bp, self, target, prop, binum, argc) \ +#define dbgenter(ctx, bp, self, target, prop, binum, argc) \ dbgent(ctx, bp, self, target, prop, binum, argc) -# define dbgleave(ctx, exittype) dbglv(ctx, exittype) -# define dbgdump(ctx) dbgds(ctx) -# define dbgrst(ctx) ((ctx)->dbgcxfcn = (ctx)->dbgcxdep = 0) -# define dbgframe(ctx, frofs, linofs) \ +#define dbgleave(ctx, exittype) dbglv(ctx, exittype) +#define dbgdump(ctx) dbgds(ctx) +#define dbgrst(ctx) ((ctx)->dbgcxfcn = (ctx)->dbgcxdep = 0) +#define dbgframe(ctx, frofs, linofs) \ (((ctx)->dbgcxfrm[(ctx)->dbgcxfcn - 1].dbgffr = (frofs)), \ ((ctx)->dbgcxfrm[(ctx)->dbgcxfcn - 1].dbgflin = (linofs))) -# define dbgssi(ctx, ofs, instr, err, p) dbgss(ctx, ofs, instr, err, p) +#define dbgssi(ctx, ofs, instr, err, p) dbgss(ctx, ofs, instr, err, p) #endif /* DBG_OFF */ /* ======================================================================== */ diff --git a/engines/glk/tads/tads2/error_message.cpp b/engines/glk/tads/tads2/error_message.cpp index 3cfe8deea7..ace3613625 100644 --- a/engines/glk/tads/tads2/error_message.cpp +++ b/engines/glk/tads/tads2/error_message.cpp @@ -27,58 +27,42 @@ namespace Glk { namespace TADS { namespace TADS2 { - -/*--------------------------------- lerini ---------------------------------*/ -/* - * lerini - allocate and initialize an error context. Returns a - * pointer to an initialized error context if successful, 0 otherwise. - */ errcxdef *lerini() { - errcxdef *errcx; /* error context */ + errcxdef *errcx; /* error context */ - /* allocate an error context */ - if (!(errcx = (errcxdef *)ltk_suballoc(sizeof(errcxdef)))) - { - /* failure */ - return((errcxdef *)0); - } + // allocate an error context + if (!(errcx = (errcxdef *)ltk_suballoc(sizeof(errcxdef)))) { + // failure + return((errcxdef *)0); + } - /* initialize the error context */ - errcx->errcxfp = (osfildef *)0; /* no error file handle */ - errcx->errcxofs = 0; /* no offset in argument buffer */ - errcx->errcxlog = ltk_errlog; /* error logging routine */ - errcx->errcxlgc = errcx; /* error logging context */ + // initialize the error context + errcx->errcxfp = (osfildef *)0; /* no error file handle */ + errcx->errcxofs = 0; /* no offset in argument buffer */ + errcx->errcxlog = ltk_errlog; /* error logging routine */ + errcx->errcxlgc = errcx; /* error logging context */ - /* return the new context */ - return(errcx); + // return the new context + return errcx; } - -/*--------------------------------- lerfre ---------------------------------*/ -/* - * lerfre - FREe error context allocated by errini. - */ -void lerfre(errcxdef *errcx) { - /* free the context */ - ltk_subfree(errcx); +void errini(errcxdef *ctx, char *arg0) { + VARUSED(ctx); + VARUSED(arg0); } +void errini(errcxdef *ctx, osfildef *fp) { + VARUSED(ctx); + VARUSED(fp); +} -/*--------------------------------- errmsg ---------------------------------*/ -/* - * errmsg - format error message number 'err' into the given buffer. - */ -void errmsg(errcxdef *ctx, char *outbuf, int outbufl, uint err) { - sprintf(outbuf, "Error #%d occured.", err); +void lerfre(errcxdef *errcx) { + // free the context + ltk_subfree(errcx); } -/*--------------------------------- errini ---------------------------------*/ -/* - * errini - initialize error system. - */ -void errini(errcxdef *ctx, char *arg0) { - VARUSED(ctx); - VARUSED(arg0); +void errmsg(errcxdef *ctx, char *outbuf, uint outbufl, uint err) { + sprintf(outbuf, "Error #%d occured.", err); } } // End of namespace TADS2 diff --git a/engines/glk/tads/tads2/file_io.cpp b/engines/glk/tads/tads2/file_io.cpp index bef91f10d2..10b8bca180 100644 --- a/engines/glk/tads/tads2/file_io.cpp +++ b/engines/glk/tads/tads2/file_io.cpp @@ -1769,6 +1769,12 @@ ret_error: return TRUE; } +void fioxor(uchar *p, uint siz, uint seed, uint inc) +{ + for (; siz; seed += inc, --siz) + *p++ ^= (uchar)seed; +} + } // End of namespace TADS2 } // End of namespace TADS } // End of namespace Glk diff --git a/engines/glk/tads/tads2/get_string.cpp b/engines/glk/tads/tads2/get_string.cpp new file mode 100644 index 0000000000..69982fcde1 --- /dev/null +++ b/engines/glk/tads/tads2/get_string.cpp @@ -0,0 +1,173 @@ +/* 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/character_map.h" +#include "glk/tads/tads2/text_io.h" +#include "glk/tads/tads2/os.h" + +namespace Glk { +namespace TADS { +namespace TADS2 { + + +/* + * Global variable with the current command logging file. If this is + * not null, we'll log each command that we read to this file. + */ +osfildef *cmdfile; + +/* + * External global with the current script input file. If this is + * non-null, we'll read commands from this file rather than from the + * keyboard. + */ +extern osfildef *scrfp; + +/* + * External global indicating script echo status. If we're reading from + * a script input file (i.e., scrfp is non-null), and this variable is + * true, it indicates that we're in "quiet" mode reading the script, so + * we will not echo commands that we read from the script file to the + * display. + */ +extern int scrquiet; + +/* + * getstring reads a string from the keyboard, doing all necessary + * output flushing. Prompting is to be done by the caller. This + * routine should be called instead of os_gets. + */ +int getstring(char *prompt, char *buf, int bufl) +{ + char *result; + int savemoremode; + int retval = 0; + + /* show prompt if one was given and flush output */ + savemoremode = setmore(0); + if (prompt != 0) + { + /* display the prompt text */ + outformat(prompt); + + /* make sure it shows up in the log file as well */ + out_logfile_print(prompt, FALSE); + } + outflushn(0); + outreset(); + + /* read from the command input file if we have one */ + if (scrfp != 0) + { + int quiet = scrquiet; + + /* try reading from command input file */ + if ((result = qasgets(buf, bufl)) == 0) + { + /* + * End of command input file; return to reading the + * keyboard. If we didn't already show the prompt, show it + * now. + * + * Note that qasgets() will have closed the script file + * before returning eof, so we won't directly read the + * command here but instead handle it later when we check to + * see if we need to read from the keyboard. + */ + if (quiet && prompt != 0) + outformat(prompt); + outflushn(0); + outreset(); + + /* + * Guarantee that moremode is turned back on. (moremode can + * be turned off for one of two reasons: we're printing the + * prompt, or we're reading from a script with no pauses. + * In either case, moremode should be turned back on at this + * point. -CDN) + */ + savemoremode = 1; + + /* turn off NONSTOP mode now that we're done with the script */ + os_nonstop_mode(FALSE); + } + + /* success */ + retval = 0; + } + + /* if we don't have a script file, read from the keyboard */ + if (scrfp == 0) + { + /* update the status line */ + runstat(); + + /* read a line from the keyboard */ + result = (char *)os_gets((uchar *)buf, bufl); + + /* + * if the result is null, we're at eof, so return a non-zero + * value; otherwise, we successfully read a command, so return + * zero + */ + retval = (result == 0); + } + + /* restore the original "more" mode */ + setmore(savemoremode); + + /* check the result */ + if (retval != 0) + { + /* we got an error reading the command - return the error */ + return retval; + } + else + { + char *p; + + /* + * we got a command, or at least a partial command (if we timed + * out, we may still have a partial line in the buffer) - write + * the input line to the log and/or command files, as + * appropriate + */ + out_logfile_print(buf, TRUE); + if (cmdfile != 0) + { + os_fprintz(cmdfile, ">"); + os_fprintz(cmdfile, buf); + os_fprintz(cmdfile, "\n"); + } + + /* translate the input to the internal character set */ + for (p = buf ; *p != '\0' ; ++p) + *p = cmap_n2i(*p); + + /* success */ + return retval; + } +} + +} // End of namespace TADS2 +} // End of namespace TADS +} // End of namespace Glk diff --git a/engines/glk/tads/tads2/ltk.cpp b/engines/glk/tads/tads2/ltk.cpp index b1128394b2..c385ee7999 100644 --- a/engines/glk/tads/tads2/ltk.cpp +++ b/engines/glk/tads/tads2/ltk.cpp @@ -130,15 +130,15 @@ void ltk_free(void *mem) { * ltk_errlog - ERRor LOGging function. Logs an error from the LER * system. */ -void ltk_errlog(void *ctx, char *fac, int errno, int argc, erradef *argv) { +void ltk_errlog(void *ctx, char *fac, int errCode, int argc, erradef *argv) { char buf[128]; /* formatted error buffer */ char msg[128]; /* message buffer */ /* $$$ filter out error #504 $$$ */ - if (errno == 504) return; + if (errCode == 504) return; /* get the error message into msg */ - errmsg((errcxdef *)ctx, msg, sizeof(msg), errno); + errmsg((errcxdef *)ctx, msg, sizeof(msg), errCode); /* format the error message */ errfmt(buf, (int)sizeof(buf), msg, argc, argv); diff --git a/engines/glk/tads/tads2/output.cpp b/engines/glk/tads/tads2/output.cpp index 6aa39b5683..8b9fd74925 100644 --- a/engines/glk/tads/tads2/output.cpp +++ b/engines/glk/tads/tads2/output.cpp @@ -3554,6 +3554,33 @@ void out_set_doublespace(int dbl) doublespace = dbl; } +int tio_askfile(const char *prompt, char *reply, int replen, int prompt_type, os_filetype_t file_type) { + // let the OS layer handle it + return os_askfile(prompt, reply, replen, prompt_type, file_type); +} + +int tio_input_dialog(int icon_id, const char *prompt, int standard_button_set, + const char **buttons, int button_count, + int default_index, int cancel_index) { + // call the OS implementation + return os_input_dialog(icon_id, prompt, standard_button_set, + buttons, button_count, + default_index, cancel_index); +} + +void outfmt(tiocxdef *ctx, uchar *txt) { + uint len; + + VARUSED(ctx); + + /* read the length prefix */ + len = osrp2(txt) - 2; + txt += 2; + + /* write out the string */ + tioputslen(ctx, (char *)txt, len); +} + } // End of namespace TADS2 } // End of namespace TADS } // End of namespace Glk diff --git a/engines/glk/tads/tads2/post_compilation.cpp b/engines/glk/tads/tads2/post_compilation.cpp index cd501db1e2..c1755cadc5 100644 --- a/engines/glk/tads/tads2/post_compilation.cpp +++ b/engines/glk/tads/tads2/post_compilation.cpp @@ -28,6 +28,38 @@ namespace Glk { namespace TADS { namespace TADS2 { +void supcont(void *ctx, objnum obj, prpnum prp) { + // No implementation +} + +void supivoc(supcxdef *ctx) { + // No implementation +} + +void supfind(errcxdef *ctx, tokthdef *tab, voccxdef *voc, + objnum *preinit, int warnlevel, int casefold) { + // No implementation +} + +void suprsrv(supcxdef *sup, void(*bif[])(struct bifcxdef *, int), + toktdef *tab, int fncntmax, int v1compat, char *new_do, int casefold) { + // No implementation +} + +void supbif(supcxdef *sup, void(*bif[])(struct bifcxdef *, int), int bifsiz) { + // No implementation +} + +void sup_log_undefobj(mcmcxdef *mctx, errcxdef *ec, int err, + char *sym_name, int sym_name_len, objnum objn) { + // No implementation +} + +void supivoc1(supcxdef *sup, voccxdef *ctx, vocidef *v, objnum target, + int inh_from_obj, int flags) { + // No implementation +} + } // End of namespace TADS2 } // End of namespace TADS } // End of namespace Glk diff --git a/engines/glk/tads/tads2/post_compilation.h b/engines/glk/tads/tads2/post_compilation.h index fdd12619fb..1d7ac7ac6d 100644 --- a/engines/glk/tads/tads2/post_compilation.h +++ b/engines/glk/tads/tads2/post_compilation.h @@ -46,34 +46,34 @@ struct supcxdef { }; /* set up contents list for one object for demand-on-load */ -inline void supcont(void *ctx, objnum obj, prpnum prp); +extern void supcont(void *ctx, objnum obj, prpnum prp); /* set up inherited vocabulary (called before executing game) */ -inline void supivoc(supcxdef *ctx); +extern void supivoc(supcxdef *ctx); /* find required objects/functions */ -inline void supfind(errcxdef *ctx, tokthdef *tab, voccxdef *voc, +extern void supfind(errcxdef *ctx, tokthdef *tab, voccxdef *voc, objnum *preinit, int warnlevel, int casefold); /* set up reserved words */ -inline void suprsrv(supcxdef *sup, void (*bif[])(struct bifcxdef *, int), +extern void suprsrv(supcxdef *sup, void (*bif[])(struct bifcxdef *, int), toktdef *tab, int fncntmax, int v1compat, char *new_do, int casefold); /* set up built-in functions without symbol table (for run-time) */ -inline void supbif(supcxdef *sup, void (*bif[])(struct bifcxdef *, int), +extern void supbif(supcxdef *sup, void (*bif[])(struct bifcxdef *, int), int bifsiz); /* log an undefined-object error */ -inline void sup_log_undefobj(mcmcxdef *mctx, errcxdef *ec, int err, +extern void sup_log_undefobj(mcmcxdef *mctx, errcxdef *ec, int err, char *sym_name, int sym_name_len, objnum objn); /* set up inherited vocabulary for a particular object */ -inline void supivoc1(supcxdef *sup, voccxdef *ctx, vocidef *v, objnum target, +extern void supivoc1(supcxdef *sup, voccxdef *ctx, vocidef *v, objnum target, int inh_from_obj, int flags); /* get name of an object out of symbol table */ -inline void supgnam(char *buf, tokthdef *tab, objnum objn); +extern void supgnam(char *buf, tokthdef *tab, objnum objn); /* table of built-in functions */ struct supbidef { diff --git a/engines/glk/tads/tads2/runtime_driver.cpp b/engines/glk/tads/tads2/runtime_driver.cpp index b2169ddf55..20ba6c1e99 100644 --- a/engines/glk/tads/tads2/runtime_driver.cpp +++ b/engines/glk/tads/tads2/runtime_driver.cpp @@ -53,6 +53,84 @@ void tok_read_defines(tokcxdef *tctx, osfildef *fp, errcxdef *ec) } /* dummy debugger functions */ + +int dbgbpset(dbgcxdef *ctx, char *addr, int *bpnum) { return 0; } + +int dbgbpat(dbgcxdef *ctx, objnum objn, objnum self, + uint ofs, int *bpnum, char *bpname, int toggle, + char *condition, int *did_set) { return 0; } + +int dbgbpatid(dbgcxdef *ctx, int bpnum, objnum target, objnum self, + uint ofs, char *bpname, int toggle, char *cond, + int *did_set) { return 0; } + +int dbgisbp(dbgcxdef *ctx, objnum target, objnum self, uint ofs, int *bpnum) { return 0; } + +int dbgisbpena(dbgcxdef *ctx, int bpnum) { return 0; } + +int dbgbpdel(dbgcxdef *ctx, int bpnum) { return 0; } + +int dbgbpdis(dbgcxdef *ctx, int bpnum, int disable) { return 0; } + +int dbgbpsetcond(dbgcxdef *ctx, int bpnum, char *cond) { return 0; } + +void dbgbplist(dbgcxdef *ctx, void(*dispfn)(void *ctx, const char *str, int len), void *dispctx) {} + +void dbgbpenum(dbgcxdef *ctx, void(*cbfunc)(void *cbctx, int bpnum, const char *desc, + const char *cond, int disabled), void *cbctx) {} + +void dbgbpeach(dbgcxdef *ctx, void(*fn)(void *, int, uchar *, uint), void *fnctx) {} + +int dbgbpgetinfo(dbgcxdef *ctx, int bpnum, char *descbuf, size_t descbuflen, + char *condbuf, size_t condbuflen) { return 0; } + +int dbgeval(dbgcxdef *ctx, char *expr, + void(*dispfn)(void *dispctx, const char *str, int strl), + void *dispctx, int level, int showtype) { return 0; } + +int dbgevalext(dbgcxdef *ctx, char *expr, + void(*dispfn)(void *dispctx, const char *str, int strl), + void *dispctx, int level, int showtype, dattyp *dat, + void(*aggcb)(void *aggctx, const char *subname, + int subnamelen, const char *relationship), + void *aggctx, int speculative) { return 0 ;} + +void dbgenumlcl(dbgcxdef *ctx, int level, + void(*func)(void *ctx, const char *lclnam, size_t lclnamlen), + void *cbctx) {} + +int dbgcompile(dbgcxdef *ctx, char *expr, dbgfdef *fr, objnum *objn, + int speculative) { return 0; } + +void dbgwhere(dbgcxdef *ctx, char *buf) {} + +int dbgwxset(dbgcxdef *ctx, char *expr, int *wxnum, int level) { return 0; } + +int dbgwxdel(dbgcxdef *ctx, int wxnum) { return 0; } + +void dbgwxupd(dbgcxdef *ctx, + void(*dispfn)(void *dispctx, const char *txt, int len), + void *dispctx) {} + +void dbgswitch(struct lindef **linp, struct lindef *newlin) {} + +void dbguini(dbgcxdef *ctx, const char *game_filename) {} + +void dbguini2(dbgcxdef *ctx) {} + +int dbgu_err_resume(dbgcxdef *ctx) { return 0; } + +int dbgu_find_src(const char *origname, int origlen, + char *fullname, size_t full_len, int must_find_file) { return 0; } + +void dbgucmd(dbgcxdef *ctx, int bphit, int err, unsigned int *exec_ofs) {} + +void dbguquitting(dbgcxdef *ctx) {} + +void dbguterm(dbgcxdef *ctx) {} + +void dbguerr(dbgcxdef *ctx, int errnum, char *msg) {} + void trchid(void) {} void trcsho(void) {} diff --git a/engines/glk/tads/tads2/text_io.h b/engines/glk/tads/tads2/text_io.h index 33a914e0ba..65194654f1 100644 --- a/engines/glk/tads/tads2/text_io.h +++ b/engines/glk/tads/tads2/text_io.h @@ -212,8 +212,7 @@ void out_set_doublespace(int dbl); * call directly for graphical implementations. We'll use formatted * text for text-only implementations. */ -int tio_askfile(const char *prompt, char *fname_buf, int fname_buf_len, - int prompt_type, os_filetype_t file_type); +int tio_askfile(const char *prompt, char *reply, int replen, int prompt_type, os_filetype_t file_type); /* * Display a dialog, using a system-defined dialog (via os_input_dialog) |