mirror of
https://github.com/He4eT/cheap-glkote.git
synced 2026-05-05 08:57:25 +00:00
6396 lines
No EOL
206 KiB
JavaScript
6396 lines
No EOL
206 KiB
JavaScript
/* GlkAPI -- a Javascript Glk API for IF interfaces
|
|
* GlkOte Library: version 2.2.3.
|
|
* Glk API which this implements: version 0.7.4.
|
|
* Designed by Andrew Plotkin <erkyrath@eblong.com>
|
|
* <http://eblong.com/zarf/glk/glkote.html>
|
|
*
|
|
* This Javascript library is copyright 2010-16 by Andrew Plotkin.
|
|
* It is distributed under the MIT license; see the "LICENSE" file.
|
|
*
|
|
* This file is a Glk API compatibility layer for glkote.js. It offers a
|
|
* set of Javascript calls which closely match the original C Glk API;
|
|
* these work by means of glkote.js operations.
|
|
*
|
|
* This API was built for Quixe, which is a pure-Javascript Glulx
|
|
* interpreter. Therefore, the API is a little strange. Notably, it
|
|
* accepts text buffers in the form of arrays of integers, not
|
|
* Javascript strings. Only the Glk calls that explicitly use strings
|
|
* (glk_put_string, etc) accept Javascript native strings.
|
|
*
|
|
* If you are writing an application in pure Javascript, you can use
|
|
* this layer (along with glkote.js). If you are writing a web app which
|
|
* is the front face of a server-side Glk app, ignore this file -- use
|
|
* glkote.js directly.
|
|
*/
|
|
|
|
/* Known problems:
|
|
|
|
Some places in the library get confused about Unicode characters
|
|
beyond 0xFFFF. They are handled correctly by streams, but grid windows
|
|
will think they occupy two characters rather than one, which will
|
|
throw off the grid spacing.
|
|
|
|
Also, the glk_put_jstring() function can't handle them at all. Quixe
|
|
printing operations that funnel through glk_put_jstring() -- meaning,
|
|
most native string printing -- will break up three-byte characters
|
|
into a UTF-16-encoded pair of two-byte characters. This will come
|
|
out okay in a buffer window, but it will again mess up grid windows,
|
|
and will also double the write-count in a stream.
|
|
*/
|
|
|
|
/* Put everything inside the Glk namespace. */
|
|
|
|
Glk = function() {
|
|
|
|
/* The VM interface object. */
|
|
var VM = null;
|
|
|
|
/* References to external libraries */
|
|
var Dialog;
|
|
var GiDispa;
|
|
var GiLoad;
|
|
var GlkOte;
|
|
|
|
/* Environment capabilities */
|
|
var support = {};
|
|
|
|
/* Options from the vm_options object. */
|
|
var option_exit_warning;
|
|
var option_do_vm_autosave;
|
|
var option_before_select_hook;
|
|
var option_extevent_hook;
|
|
var option_glk_gestalt_hook;
|
|
|
|
/* Library display state. */
|
|
var has_exited = false;
|
|
var ui_disabled = false;
|
|
var ui_specialinput = null;
|
|
var ui_specialcallback = null;
|
|
var event_generation = 0;
|
|
var current_partial_inputs = null;
|
|
var current_partial_outputs = null;
|
|
|
|
// Set external variable references
|
|
function set_references( vm_options )
|
|
{
|
|
if ( vm_options.Dialog )
|
|
{
|
|
Dialog = vm_options.Dialog;
|
|
}
|
|
if ( !Dialog )
|
|
{
|
|
if ( typeof window !== 'undefined' && window.Dialog )
|
|
{
|
|
Dialog = window.Dialog;
|
|
}
|
|
else
|
|
{
|
|
throw new Error( 'No reference to Dialog' );
|
|
}
|
|
}
|
|
|
|
if ( vm_options.GiDispa )
|
|
{
|
|
GiDispa = vm_options.GiDispa;
|
|
}
|
|
else if ( !GiDispa && typeof window !== 'undefined' && window.GiDispa )
|
|
{
|
|
GiDispa = window.GiDispa;
|
|
}
|
|
|
|
if ( vm_options.GiLoad )
|
|
{
|
|
GiLoad = vm_options.GiLoad;
|
|
}
|
|
else if ( !GiLoad && typeof window !== 'undefined' && window.GiLoad )
|
|
{
|
|
GiLoad = window.GiLoad;
|
|
}
|
|
|
|
if ( vm_options.GlkOte )
|
|
{
|
|
GlkOte = vm_options.GlkOte;
|
|
}
|
|
if ( !GlkOte )
|
|
{
|
|
if ( typeof window !== 'undefined' && window.GlkOte )
|
|
{
|
|
GlkOte = window.GlkOte;
|
|
}
|
|
else
|
|
{
|
|
throw new Error('No reference to GlkOte');
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialize the library, initialize the VM, and set it running. (It will
|
|
run until the first glk_select() or glk_exit() call.)
|
|
|
|
The vm_options argument must have a vm_options.vm field, which must be an
|
|
appropriate VM interface object. (For example, Quixe.) This must have
|
|
init() and resume() methods.
|
|
|
|
The vm_options argument is also passed through to GlkOte as the game
|
|
interface object. It can be used to affect some GlkOte display options,
|
|
such as window spacing.
|
|
|
|
(You do not need to provide a vm_options.accept() function. The Glk
|
|
library sets that up for you.)
|
|
*/
|
|
function init(vm_options) {
|
|
/* Set references to external libraries */
|
|
set_references( vm_options );
|
|
|
|
VM = vm_options.vm;
|
|
if (GiDispa)
|
|
GiDispa.set_vm(VM);
|
|
|
|
vm_options.accept = accept_ui_event;
|
|
|
|
GlkOte.init(vm_options);
|
|
|
|
option_exit_warning = vm_options.exit_warning;
|
|
option_do_vm_autosave = vm_options.do_vm_autosave;
|
|
option_before_select_hook = vm_options.before_select_hook;
|
|
option_extevent_hook = vm_options.extevent_hook;
|
|
option_glk_gestalt_hook = vm_options.glk_gestalt_hook;
|
|
|
|
if (option_before_select_hook) {
|
|
option_before_select_hook();
|
|
}
|
|
}
|
|
|
|
function accept_ui_event(obj) {
|
|
var box;
|
|
|
|
//qlog("### accept_ui_event: " + obj.type + ", gen " + obj.gen);
|
|
if (ui_disabled) {
|
|
/* We've hit glk_exit() or a VM fatal error, or just blocked the UI for
|
|
some modal dialog. */
|
|
qlog("### ui is disabled, ignoring event");
|
|
return;
|
|
}
|
|
|
|
if (obj.gen != event_generation) {
|
|
GlkOte.log('Input event had wrong generation number: got ' + obj.gen + ', currently at ' + event_generation);
|
|
return;
|
|
}
|
|
event_generation += 1;
|
|
|
|
/* Note any partial inputs; we'll need them if the game cancels a line
|
|
input. This may be undef. */
|
|
current_partial_inputs = obj.partial;
|
|
|
|
switch (obj.type) {
|
|
case 'init':
|
|
content_metrics = obj.metrics;
|
|
/* Process the support array */
|
|
if (obj.support) {
|
|
obj.support.forEach(function(item) {support[item] = 1;});
|
|
}
|
|
VM.init();
|
|
break;
|
|
|
|
case 'external':
|
|
var res = null;
|
|
if (option_extevent_hook) {
|
|
res = option_extevent_hook(obj.value);
|
|
}
|
|
if (!res && obj.value == 'timer') {
|
|
/* Timer events no longer come in this way, but we'll still
|
|
accept them. */
|
|
gli_timer_started = Date.now();
|
|
res = { type: Const.evtype_Timer };
|
|
}
|
|
if (res && res.type) {
|
|
handle_external_input(res);
|
|
}
|
|
break;
|
|
|
|
case 'timer':
|
|
gli_timer_started = Date.now();
|
|
var res = { type: Const.evtype_Timer };
|
|
handle_external_input(res);
|
|
break;
|
|
|
|
case 'hyperlink':
|
|
handle_hyperlink_input(obj.window, obj.value);
|
|
break;
|
|
|
|
case 'mouse':
|
|
handle_mouse_input(obj.window, obj.x, obj.y);
|
|
break;
|
|
|
|
case 'char':
|
|
handle_char_input(obj.window, obj.value);
|
|
break;
|
|
|
|
case 'line':
|
|
handle_line_input(obj.window, obj.value, obj.terminator);
|
|
break;
|
|
|
|
case 'arrange':
|
|
content_metrics = obj.metrics;
|
|
box = {
|
|
left: content_metrics.outspacingx,
|
|
top: content_metrics.outspacingy,
|
|
right: content_metrics.width-content_metrics.outspacingx,
|
|
bottom: content_metrics.height-content_metrics.outspacingy
|
|
};
|
|
if (gli_rootwin)
|
|
gli_window_rearrange(gli_rootwin, box);
|
|
handle_arrange_input();
|
|
break;
|
|
|
|
case 'redraw':
|
|
handle_redraw_input();
|
|
break;
|
|
|
|
case 'specialresponse':
|
|
if (obj.response == 'fileref_prompt') {
|
|
gli_fileref_create_by_prompt_callback(obj);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
function handle_arrange_input() {
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
gli_selectref.set_field(0, Const.evtype_Arrange);
|
|
gli_selectref.set_field(1, null);
|
|
gli_selectref.set_field(2, 0);
|
|
gli_selectref.set_field(3, 0);
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_redraw_input() {
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
gli_selectref.set_field(0, Const.evtype_Redraw);
|
|
gli_selectref.set_field(1, null);
|
|
gli_selectref.set_field(2, 0);
|
|
gli_selectref.set_field(3, 0);
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_external_input(res) {
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
/* This also handles timer input. */
|
|
var val1 = 0;
|
|
var val2 = 0;
|
|
if (res.val1)
|
|
val1 = res.val1;
|
|
if (res.val2)
|
|
val2 = res.val2;
|
|
|
|
gli_selectref.set_field(0, res.type);
|
|
gli_selectref.set_field(1, null);
|
|
gli_selectref.set_field(2, val1);
|
|
gli_selectref.set_field(3, val2);
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_hyperlink_input(disprock, val) {
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
var win = null;
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.disprock == disprock)
|
|
break;
|
|
}
|
|
if (!win || !win.hyperlink_request)
|
|
return;
|
|
|
|
gli_selectref.set_field(0, Const.evtype_Hyperlink);
|
|
gli_selectref.set_field(1, win);
|
|
gli_selectref.set_field(2, val);
|
|
gli_selectref.set_field(3, 0);
|
|
|
|
win.hyperlink_request = false;
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_mouse_input(disprock, xpos, ypos) {
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
var win = null;
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.disprock == disprock)
|
|
break;
|
|
}
|
|
if (!win || !win.mouse_request)
|
|
return;
|
|
|
|
gli_selectref.set_field(0, Const.evtype_MouseInput);
|
|
gli_selectref.set_field(1, win);
|
|
gli_selectref.set_field(2, xpos);
|
|
gli_selectref.set_field(3, ypos);
|
|
|
|
win.mouse_request = false;
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_char_input(disprock, input) {
|
|
var charval;
|
|
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
var win = null;
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.disprock == disprock)
|
|
break;
|
|
}
|
|
if (!win || !win.char_request)
|
|
return;
|
|
|
|
if (input.length == 1) {
|
|
charval = input.charCodeAt(0);
|
|
if (!win.char_request_uni)
|
|
charval = charval & 0xFF;
|
|
}
|
|
else {
|
|
charval = KeystrokeNameMap[input];
|
|
if (!charval)
|
|
charval = Const.keycode_Unknown;
|
|
}
|
|
|
|
gli_selectref.set_field(0, Const.evtype_CharInput);
|
|
gli_selectref.set_field(1, win);
|
|
gli_selectref.set_field(2, charval);
|
|
gli_selectref.set_field(3, 0);
|
|
|
|
win.char_request = false;
|
|
win.char_request_uni = false;
|
|
win.input_generation = null;
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function handle_line_input(disprock, input, termkey) {
|
|
var ix;
|
|
|
|
if (!gli_selectref)
|
|
return;
|
|
|
|
var win = null;
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.disprock == disprock)
|
|
break;
|
|
}
|
|
if (!win || !win.line_request)
|
|
return;
|
|
|
|
if (input.length > win.linebuf.length)
|
|
input = input.slice(0, win.linebuf.length);
|
|
|
|
if (win.request_echo_line_input) {
|
|
ix = win.style;
|
|
gli_set_style(win.str, Const.style_Input);
|
|
gli_window_put_string(win, input);
|
|
if (win.echostr)
|
|
glk_put_jstring_stream(win.echostr, input);
|
|
gli_set_style(win.str, ix);
|
|
gli_window_put_string(win, "\n");
|
|
if (win.echostr)
|
|
glk_put_jstring_stream(win.echostr, "\n");
|
|
}
|
|
|
|
for (ix=0; ix<input.length; ix++)
|
|
win.linebuf[ix] = input.charCodeAt(ix);
|
|
|
|
var termcode = 0;
|
|
if (termkey && KeystrokeNameMap[termkey])
|
|
termcode = KeystrokeNameMap[termkey];
|
|
|
|
gli_selectref.set_field(0, Const.evtype_LineInput);
|
|
gli_selectref.set_field(1, win);
|
|
gli_selectref.set_field(2, input.length);
|
|
gli_selectref.set_field(3, termcode);
|
|
|
|
if (GiDispa)
|
|
GiDispa.unretain_array(win.linebuf);
|
|
win.line_request = false;
|
|
win.line_request_uni = false;
|
|
win.request_echo_line_input = null;
|
|
win.input_generation = null;
|
|
win.linebuf = null;
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(gli_selectref);
|
|
gli_selectref = null;
|
|
VM.resume();
|
|
}
|
|
|
|
function update(type) {
|
|
var dataobj = { type: type || 'update', gen: event_generation };
|
|
var winarray = null;
|
|
var contentarray = null;
|
|
var inputarray = null;
|
|
var win, obj, robj, useobj, lineobj, ls, val, ix, cx;
|
|
var initial, lastpos, laststyle, lasthyperlink;
|
|
|
|
if (geometry_changed) {
|
|
geometry_changed = false;
|
|
winarray = [];
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.type == Const.wintype_Pair)
|
|
continue;
|
|
|
|
obj = { id: win.disprock, rock: win.rock };
|
|
winarray.push(obj);
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
obj.type = 'buffer';
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
obj.type = 'grid';
|
|
obj.gridwidth = win.gridwidth;
|
|
obj.gridheight = win.gridheight;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
obj.type = 'graphics';
|
|
obj.graphwidth = win.graphwidth;
|
|
obj.graphheight = win.graphheight;
|
|
break;
|
|
}
|
|
|
|
obj.left = win.bbox.left;
|
|
obj.top = win.bbox.top;
|
|
obj.width = win.bbox.right - win.bbox.left;
|
|
obj.height = win.bbox.bottom - win.bbox.top;
|
|
}
|
|
}
|
|
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
useobj = false;
|
|
obj = { id: win.disprock };
|
|
if (contentarray == null)
|
|
contentarray = [];
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
gli_window_buffer_deaccumulate(win);
|
|
if (win.content.length) {
|
|
obj.text = win.content.slice(0);
|
|
win.content.length = 0;
|
|
useobj = true;
|
|
}
|
|
if (win.clearcontent) {
|
|
obj.clear = true;
|
|
win.clearcontent = false;
|
|
useobj = true;
|
|
if (!obj.text) {
|
|
obj.text = [];
|
|
}
|
|
win.reserve.length = 0;
|
|
}
|
|
if (obj.text && obj.text.length) {
|
|
for (ix=0; ix<obj.text.length; ix++) {
|
|
win.reserve.push(obj.text[ix]);
|
|
}
|
|
}
|
|
if (win.reserve.length > 100) {
|
|
win.reserve.splice(0, win.reserve.length-100);
|
|
}
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
if (win.gridwidth == 0 || win.gridheight == 0)
|
|
break;
|
|
obj.lines = [];
|
|
for (ix=0; ix<win.gridheight; ix++) {
|
|
lineobj = win.lines[ix];
|
|
if (!lineobj.dirty)
|
|
continue;
|
|
lineobj.dirty = false;
|
|
ls = [];
|
|
lastpos = 0;
|
|
for (cx=0; cx<win.gridwidth; ) {
|
|
laststyle = lineobj.styles[cx];
|
|
lasthyperlink = lineobj.hyperlinks[cx];
|
|
for (; cx<win.gridwidth
|
|
&& lineobj.styles[cx] == laststyle
|
|
&& lineobj.hyperlinks[cx] == lasthyperlink;
|
|
cx++) { }
|
|
if (lastpos < cx) {
|
|
if (!lasthyperlink) {
|
|
ls.push(StyleNameMap[laststyle]);
|
|
ls.push(lineobj.chars.slice(lastpos, cx).join(''));
|
|
}
|
|
else {
|
|
robj = { style:StyleNameMap[laststyle], text:lineobj.chars.slice(lastpos, cx).join(''), hyperlink:lasthyperlink };
|
|
ls.push(robj);
|
|
}
|
|
lastpos = cx;
|
|
}
|
|
}
|
|
obj.lines.push({ line:ix, content:ls });
|
|
}
|
|
useobj = obj.lines.length;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
if (win.content.length) {
|
|
obj.draw = win.content.slice(0);
|
|
win.content.length = 0;
|
|
useobj = true;
|
|
}
|
|
/* Copy new drawing commands over to the reserve. Keep track
|
|
of the last (whole-window) fill command. */
|
|
var clearedat = -1;
|
|
if (obj.draw && obj.draw.length) {
|
|
for (ix=0; ix<obj.draw.length; ix++) {
|
|
var drawel = obj.draw[ix];
|
|
if (drawel.special == 'fill'
|
|
&& drawel.x === undefined && drawel.y === undefined
|
|
&& drawel.width === undefined && drawel.height === undefined) {
|
|
clearedat = win.reserve.length;
|
|
}
|
|
win.reserve.push(drawel);
|
|
}
|
|
}
|
|
if (clearedat >= 0) {
|
|
/* We're going to delete every command before the
|
|
fill, except that we save the last setcolor. */
|
|
var setcol = null;
|
|
for (ix=0; ix<win.reserve.length && ix<clearedat; ix++) {
|
|
var drawel = win.reserve[ix];
|
|
if (drawel.special == 'setcolor')
|
|
setcol = drawel;
|
|
}
|
|
win.reserve.splice(0, clearedat);
|
|
if (setcol)
|
|
win.reserve.unshift(setcol);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (useobj)
|
|
contentarray.push(obj);
|
|
}
|
|
|
|
inputarray = [];
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
obj = null;
|
|
if (win.char_request) {
|
|
obj = { id: win.disprock, type: 'char', gen: win.input_generation };
|
|
if (win.type == Const.wintype_TextGrid) {
|
|
if (gli_window_grid_canonicalize(win)) {
|
|
obj.xpos = win.gridwidth;
|
|
obj.ypos = win.gridheight-1;
|
|
}
|
|
else {
|
|
obj.xpos = win.cursorx;
|
|
obj.ypos = win.cursory;
|
|
}
|
|
}
|
|
}
|
|
if (win.line_request) {
|
|
initial = '';
|
|
if (current_partial_outputs) {
|
|
val = current_partial_outputs[win.disprock];
|
|
if (val)
|
|
initial = val;
|
|
}
|
|
/* Note that the initial and terminators fields will be ignored
|
|
if this is a continued (old) input request. So it doesn't
|
|
matter if they're wrong. */
|
|
obj = { id: win.disprock, type: 'line', gen: win.input_generation,
|
|
maxlen: win.linebuf.length, initial: initial };
|
|
if (win.line_input_terminators.length) {
|
|
obj.terminators = win.line_input_terminators;
|
|
}
|
|
if (win.type == Const.wintype_TextGrid) {
|
|
if (gli_window_grid_canonicalize(win)) {
|
|
obj.xpos = win.gridwidth;
|
|
obj.ypos = win.gridheight-1;
|
|
}
|
|
else {
|
|
obj.xpos = win.cursorx;
|
|
obj.ypos = win.cursory;
|
|
}
|
|
}
|
|
}
|
|
if (win.hyperlink_request) {
|
|
if (!obj)
|
|
obj = { id: win.disprock };
|
|
obj.hyperlink = true;
|
|
}
|
|
if (win.mouse_request) {
|
|
if (!obj)
|
|
obj = { id: win.disprock };
|
|
obj.mouse = true;
|
|
}
|
|
if (obj)
|
|
inputarray.push(obj);
|
|
}
|
|
|
|
dataobj.windows = winarray;
|
|
dataobj.content = contentarray;
|
|
dataobj.input = inputarray;
|
|
|
|
if (gli_timer_lastsent != gli_timer_interval) {
|
|
//qlog("### timer update: " + gli_timer_interval);
|
|
dataobj.timer = gli_timer_interval;
|
|
gli_timer_lastsent = gli_timer_interval;
|
|
}
|
|
|
|
if (ui_specialinput) {
|
|
//qlog("### special input: " + ui_specialinput.type);
|
|
dataobj.specialinput = ui_specialinput;
|
|
}
|
|
|
|
if (ui_disabled) {
|
|
//qlog("### disabling ui");
|
|
dataobj.disable = true;
|
|
}
|
|
|
|
/* Clean this up; it's only meaningful within one run/update cycle. */
|
|
current_partial_outputs = null;
|
|
|
|
/* If we're doing an autorestore, gli_autorestore_glkstate will
|
|
contain additional setup information for the first update()
|
|
call only. */
|
|
if (gli_autorestore_glkstate)
|
|
dataobj.autorestore = gli_autorestore_glkstate;
|
|
gli_autorestore_glkstate = null;
|
|
|
|
GlkOte.update(dataobj, gli_autorestore_glkstate);
|
|
|
|
if (option_before_select_hook) {
|
|
option_before_select_hook();
|
|
}
|
|
if (option_do_vm_autosave) {
|
|
if (has_exited) {
|
|
/* On quit or fatal error, delete the autosave. */
|
|
VM.do_autosave(-1);
|
|
}
|
|
else {
|
|
/* If this is a good time, autosave. */
|
|
var eventarg = GiDispa.check_autosave();
|
|
if (eventarg)
|
|
VM.do_autosave(eventarg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Wrap up the current display state as a (JSONable) object. This is
|
|
called from Quixe.vm_autosave.
|
|
*/
|
|
function save_allstate() {
|
|
var res = {};
|
|
|
|
if (gli_rootwin)
|
|
res.rootwin = gli_rootwin.disprock;
|
|
|
|
if (gli_currentstr)
|
|
res.currentstr = gli_currentstr.disprock;
|
|
|
|
if (gli_timer_interval)
|
|
res.timer_interval = gli_timer_interval;
|
|
|
|
res.windows = [];
|
|
for (var win = gli_windowlist; win; win = win.next) {
|
|
var obj = {
|
|
type: win.type, rock: win.rock, disprock: win.disprock,
|
|
style: win.style, hyperlink: win.hyperlink
|
|
};
|
|
if (win.parent)
|
|
obj.parent = win.parent.disprock;
|
|
obj.str = win.str.disprock;
|
|
if (win.echostr)
|
|
obj.echostr = win.echostr.disprock;
|
|
|
|
obj.bbox = {
|
|
left: win.bbox.left, right: win.bbox.right,
|
|
top: win.bbox.top, bottom: win.bbox.bottom
|
|
};
|
|
|
|
if (win.linebuf !== null) {
|
|
var info = GiDispa.get_retained_array(win.linebuf);
|
|
obj.linebuf = {
|
|
addr: info.addr,
|
|
len: info.len,
|
|
arr: info.arr.slice(0),
|
|
arg: info.arg.serialize()
|
|
};
|
|
}
|
|
obj.char_request = win.char_request;
|
|
obj.line_request = win.line_request;
|
|
obj.char_request_uni = win.char_request_uni;
|
|
obj.line_request_uni = win.line_request_uni;
|
|
obj.hyperlink_request = win.hyperlink_request;
|
|
obj.mouse_request = win.mouse_request;
|
|
obj.echo_line_input = win.echo_line_input;
|
|
obj.request_echo_line_input = win.request_echo_line_input;
|
|
obj.line_input_terminators = win.line_input_terminators.slice(0);
|
|
//### should have a request_line_input_terminators as well
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
obj.reserve = win.reserve.slice(0);
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
obj.gridwidth = win.gridwidth;
|
|
obj.gridheight = win.gridheight;
|
|
obj.lines = [];
|
|
for (var ix=0; ix<win.lines.length; ix++) {
|
|
var ln = win.lines[ix];
|
|
obj.lines.push({
|
|
chars: ln.chars.slice(0),
|
|
styles: ln.styles.slice(0),
|
|
hyperlinks: ln.hyperlinks.slice(0)
|
|
});
|
|
}
|
|
obj.cursorx = win.cursorx;
|
|
obj.cursory = win.cursory;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
obj.graphwidth = win.graphwidth;
|
|
obj.graphheight = win.graphheight;
|
|
obj.reserve = win.reserve.slice(0);
|
|
break;
|
|
case Const.wintype_Pair:
|
|
obj.pair_dir = win.pair_dir;
|
|
obj.pair_division = win.pair_division;
|
|
obj.pair_key = win.pair_key.disprock;
|
|
obj.pair_keydamage = false;
|
|
obj.pair_size = win.pair_size;
|
|
obj.pair_hasborder = win.pair_hasborder;
|
|
obj.pair_vertical = win.pair_vertical;
|
|
obj.pair_backward = win.pair_backward;
|
|
obj.child1 = win.child1.disprock;
|
|
obj.child2 = win.child2.disprock;
|
|
break;
|
|
}
|
|
|
|
res.windows.push(obj);
|
|
}
|
|
|
|
res.streams = [];
|
|
for (var str = gli_streamlist; str; str = str.next) {
|
|
var obj = {
|
|
type: str.type, rock: str.rock, disprock: str.disprock,
|
|
unicode: str.unicode, isbinary: str.isbinary,
|
|
readcount: str.readcount, writecount: str.writecount,
|
|
readable: str.readable, writable: str.writable,
|
|
streaming: str.streaming
|
|
};
|
|
|
|
switch (str.type) {
|
|
|
|
case strtype_Window:
|
|
if (str.win)
|
|
obj.win = str.win.disprock;
|
|
break;
|
|
|
|
case strtype_Memory:
|
|
if (str.buf !== null) {
|
|
var info = GiDispa.get_retained_array(str.buf);
|
|
obj.buf = {
|
|
addr: info.addr,
|
|
len: info.len,
|
|
arr: info.arr.slice(0),
|
|
arg: info.arg.serialize()
|
|
};
|
|
}
|
|
obj.buflen = str.buflen;
|
|
obj.bufpos = str.bufpos;
|
|
obj.bufeof = str.bufeof;
|
|
break;
|
|
|
|
case strtype_Resource:
|
|
obj.resfilenum = str.resfilenum;
|
|
// Don't need str.buf
|
|
obj.buflen = str.buflen;
|
|
obj.bufpos = str.bufpos;
|
|
obj.bufeof = str.bufeof;
|
|
break;
|
|
|
|
case strtype_File:
|
|
obj.origfmode = str.origfmode;
|
|
if (!Dialog.streaming) {
|
|
obj.ref = str.ref;
|
|
gli_stream_flush_file(str);
|
|
// Don't need str.buf
|
|
obj.buflen = str.buflen;
|
|
obj.bufpos = str.bufpos;
|
|
obj.bufeof = str.bufeof;
|
|
}
|
|
else {
|
|
str.fstream.fflush();
|
|
obj.ref = str.ref;
|
|
obj.filepos = str.fstream.ftell();
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
res.streams.push(obj);
|
|
}
|
|
|
|
res.filerefs = [];
|
|
for (var fref = gli_filereflist; fref; fref = fref.next) {
|
|
var obj = {
|
|
type: fref.type, rock: fref.rock, disprock: fref.disprock,
|
|
filename: fref.filename, textmode: fref.textmode,
|
|
filetype: fref.filetype, filetypename: fref.filetypename
|
|
};
|
|
|
|
obj.ref = fref.ref;
|
|
|
|
res.filerefs.push(obj);
|
|
}
|
|
|
|
// Ignore gli_schannellist, as it's currently always empty.
|
|
|
|
/* Save GlkOte-level information. This includes the overall metrics. */
|
|
res.glkote = GlkOte.save_allstate();
|
|
|
|
return res;
|
|
}
|
|
|
|
/* Take display information (created by save_allstate) and set up our
|
|
state to match it. Called from vm_autorestore.
|
|
*/
|
|
function restore_allstate(res)
|
|
{
|
|
if (gli_windowlist || gli_streamlist || gli_filereflist)
|
|
throw('restore_allstate: glkapi module has already been launched');
|
|
|
|
/* We build and register all the bare objects first. (In reverse
|
|
order so that the linked lists come out right way around.) */
|
|
|
|
for (var ix=res.windows.length-1; ix>=0; ix--) {
|
|
var obj = res.windows[ix];
|
|
var win = {
|
|
type: obj.type, rock: obj.rock, disprock: obj.disprock,
|
|
style: obj.style, hyperlink: obj.hyperlink
|
|
};
|
|
GiDispa.class_register('window', win, win.disprock);
|
|
|
|
win.prev = null;
|
|
win.next = gli_windowlist;
|
|
gli_windowlist = win;
|
|
if (win.next)
|
|
win.next.prev = win;
|
|
}
|
|
|
|
for (var ix=res.streams.length-1; ix>=0; ix--) {
|
|
var obj = res.streams[ix];
|
|
var str = {
|
|
type: obj.type, rock: obj.rock, disprock: obj.disprock,
|
|
unicode: obj.unicode, isbinary: obj.isbinary,
|
|
readcount: obj.readcount, writecount: obj.writecount,
|
|
readable: obj.readable, writable: obj.writable,
|
|
streaming: obj.streaming
|
|
};
|
|
GiDispa.class_register('stream', str, str.disprock);
|
|
|
|
str.prev = null;
|
|
str.next = gli_streamlist;
|
|
gli_streamlist = str;
|
|
if (str.next)
|
|
str.next.prev = str;
|
|
}
|
|
|
|
for (var ix=res.filerefs.length-1; ix>=0; ix--) {
|
|
var obj = res.filerefs[ix];
|
|
var fref = {
|
|
type: obj.type, rock: obj.rock, disprock: obj.disprock,
|
|
filename: obj.filename, textmode: obj.textmode,
|
|
filetype: obj.filetype, filetypename: obj.filetypename
|
|
};
|
|
GiDispa.class_register('fileref', fref, fref.disprock);
|
|
|
|
fref.prev = null;
|
|
fref.next = gli_filereflist;
|
|
gli_filereflist = fref;
|
|
if (fref.next)
|
|
fref.next.prev = fref;
|
|
}
|
|
|
|
/* ...Now we fill in the cross-references. */
|
|
|
|
for (var ix=0; ix<res.windows.length; ix++) {
|
|
var obj = res.windows[ix];
|
|
var win = GiDispa.class_obj_from_id('window', obj.disprock);
|
|
|
|
win.parent = GiDispa.class_obj_from_id('window', obj.parent);
|
|
win.str = GiDispa.class_obj_from_id('stream', obj.str);
|
|
win.echostr = GiDispa.class_obj_from_id('stream', obj.echostr);
|
|
|
|
win.bbox = {
|
|
left: obj.bbox.left, right: obj.bbox.right,
|
|
top: obj.bbox.top, bottom: obj.bbox.bottom
|
|
};
|
|
|
|
win.input_generation = null;
|
|
if (obj.char_request || obj.line_request)
|
|
win.input_generation = event_generation;
|
|
win.linebuf = null;
|
|
if (obj.linebuf !== undefined) {
|
|
// should clone that object
|
|
win.linebuf = obj.linebuf.arr;
|
|
GiDispa.retain_array(win.linebuf, obj.linebuf);
|
|
}
|
|
win.char_request = obj.char_request;
|
|
win.line_request = obj.line_request;
|
|
win.char_request_uni = obj.char_request_uni;
|
|
win.line_request_uni = obj.line_request_uni;
|
|
win.hyperlink_request = obj.hyperlink_request;
|
|
win.mouse_request = obj.mouse_request;
|
|
win.echo_line_input = obj.echo_line_input;
|
|
win.request_echo_line_input = obj.request_echo_line_input;
|
|
win.line_input_terminators = obj.line_input_terminators.slice(0);
|
|
//### should have a request_line_input_terminators as well
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
win.accum = [];
|
|
win.accumstyle = win.style;
|
|
win.accumhyperlink = win.hyperlink;
|
|
win.content = obj.reserve.slice(0);
|
|
win.clearcontent = false;
|
|
win.reserve = [];
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
win.gridwidth = obj.gridwidth;
|
|
win.gridheight = obj.gridheight;
|
|
win.lines = [];
|
|
for (var jx=0; jx<obj.lines.length; jx++) {
|
|
var ln = obj.lines[jx];
|
|
win.lines.push({
|
|
dirty: true,
|
|
chars: ln.chars.slice(0),
|
|
styles: ln.styles.slice(0),
|
|
hyperlinks: ln.hyperlinks.slice(0)
|
|
});
|
|
}
|
|
win.cursorx = obj.cursorx;
|
|
win.cursory = obj.cursory;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
win.graphwidth = obj.graphwidth;
|
|
win.graphheight = obj.graphheight;
|
|
win.content = obj.reserve.slice(0);
|
|
win.reserve = [];
|
|
break;
|
|
case Const.wintype_Pair:
|
|
win.pair_dir = obj.pair_dir;
|
|
win.pair_division = obj.pair_division;
|
|
win.pair_key = GiDispa.class_obj_from_id('window', obj.pair_key);
|
|
win.pair_keydamage = false;
|
|
win.pair_size = obj.pair_size;
|
|
win.pair_hasborder = obj.pair_hasborder;
|
|
win.pair_vertical = obj.pair_vertical;
|
|
win.pair_backward = obj.pair_backward;
|
|
win.child1 = GiDispa.class_obj_from_id('window', obj.child1);
|
|
win.child2 = GiDispa.class_obj_from_id('window', obj.child2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var ix=0; ix<res.streams.length; ix++) {
|
|
var obj = res.streams[ix];
|
|
var str = GiDispa.class_obj_from_id('stream', obj.disprock);
|
|
|
|
/* Defaults first... */
|
|
str.win = null;
|
|
str.ref = null;
|
|
str.file = null;
|
|
|
|
str.buf = null;
|
|
str.bufpos = 0;
|
|
str.buflen = 0;
|
|
str.bufeof = 0;
|
|
str.timer_id = null;
|
|
str.flush_func = null;
|
|
str.fstream = null;
|
|
|
|
switch (str.type) {
|
|
|
|
case strtype_Window:
|
|
str.win = GiDispa.class_obj_from_id('window', obj.win);
|
|
break;
|
|
|
|
case strtype_Memory:
|
|
if (obj.buf !== undefined) {
|
|
// should clone that object
|
|
str.buf = obj.buf.arr;
|
|
GiDispa.retain_array(str.buf, obj.buf);
|
|
}
|
|
str.buflen = obj.buflen;
|
|
str.bufpos = obj.bufpos;
|
|
str.bufeof = obj.bufeof;
|
|
break;
|
|
|
|
case strtype_Resource:
|
|
str.resfilenum = obj.resfilenum;
|
|
var el = GiLoad.find_data_chunk(str.resfilenum);
|
|
if (el) {
|
|
str.buf = el.data;
|
|
}
|
|
str.buflen = obj.buflen;
|
|
str.bufpos = obj.bufpos;
|
|
str.bufeof = obj.bufeof;
|
|
break;
|
|
|
|
case strtype_File:
|
|
str.origfmode = obj.origfmode;
|
|
if (!Dialog.streaming) {
|
|
str.ref = obj.ref;
|
|
str.buflen = obj.buflen;
|
|
str.bufpos = obj.bufpos;
|
|
str.bufeof = obj.bufeof;
|
|
|
|
var content = Dialog.file_read(str.ref);
|
|
if (content == null) {
|
|
/* The file was somehow deleted. Create an empty
|
|
file (even in read mode). */
|
|
content = [];
|
|
Dialog.file_write(str.ref, '', true);
|
|
}
|
|
str.buf = content;
|
|
|
|
/* If the file has been shortened, we might have to
|
|
trim bufeof to fit within it. The game might see
|
|
the file pos mysteriously move; sorry. */
|
|
str.bufeof = content.length;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufpos = str.bufeof;
|
|
}
|
|
else {
|
|
str.ref = obj.ref;
|
|
str.fstream = Dialog.file_fopen(str.origfmode, str.ref);
|
|
if (!str.fstream) {
|
|
/* This is the panic case. We can't reopen the stream,
|
|
but the game expects an open stream! We'll just
|
|
have to open a temporary file; the user will never
|
|
get their data, but at least the game won't crash.
|
|
(Better policy would be to prompt the user for
|
|
a new file location...) */
|
|
var tempref = Dialog.file_construct_temp_ref(str.ref.usage);
|
|
str.fstream = Dialog.file_fopen(str.origfmode, tempref);
|
|
if (!str.fstream)
|
|
throw('restore_allstate: could not reopen even a temp stream for: ' + str.ref.filename);
|
|
}
|
|
|
|
if (str.origfmode != Const.filemode_WriteAppend) {
|
|
/* Jump to the last known filepos. */
|
|
str.fstream.fseek(obj.filepos, Const.seekmode_Start);
|
|
}
|
|
|
|
str.buffer4 = str.fstream.BufferClass.alloc(4);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
for (var ix=0; ix<res.filerefs.length; ix++) {
|
|
var obj = res.filerefs[ix];
|
|
var fref = GiDispa.class_obj_from_id('fileref', obj.disprock);
|
|
|
|
fref.ref = obj.ref; // should deep clone
|
|
}
|
|
|
|
gli_rootwin = GiDispa.class_obj_from_id('window', res.rootwin);
|
|
gli_currentstr = GiDispa.class_obj_from_id('stream', res.currentstr);
|
|
|
|
if (res.timer_interval)
|
|
glk_request_timer_events(res.timer_interval);
|
|
|
|
/* Stash this for the next (first) GlkOte.update call. */
|
|
gli_autorestore_glkstate = res.glkote;
|
|
}
|
|
|
|
/* This is the handler for a VM fatal error. (Not for an error in our own
|
|
library!) We display the error message, and then push a final display
|
|
update, which kills all input fields in all windows.
|
|
*/
|
|
function fatal_error(msg) {
|
|
has_exited = true;
|
|
ui_disabled = true;
|
|
GlkOte.error(msg);
|
|
var dataobj = { type: 'update', gen: event_generation, disable: true };
|
|
dataobj.input = [];
|
|
GlkOte.update(dataobj);
|
|
}
|
|
|
|
/* All the numeric constants used by the Glk interface. We push these into
|
|
an object, for tidiness. */
|
|
|
|
var Const = {
|
|
gestalt_Version : 0,
|
|
gestalt_CharInput : 1,
|
|
gestalt_LineInput : 2,
|
|
gestalt_CharOutput : 3,
|
|
gestalt_CharOutput_CannotPrint : 0,
|
|
gestalt_CharOutput_ApproxPrint : 1,
|
|
gestalt_CharOutput_ExactPrint : 2,
|
|
gestalt_MouseInput : 4,
|
|
gestalt_Timer : 5,
|
|
gestalt_Graphics : 6,
|
|
gestalt_DrawImage : 7,
|
|
gestalt_Sound : 8,
|
|
gestalt_SoundVolume : 9,
|
|
gestalt_SoundNotify : 10,
|
|
gestalt_Hyperlinks : 11,
|
|
gestalt_HyperlinkInput : 12,
|
|
gestalt_SoundMusic : 13,
|
|
gestalt_GraphicsTransparency : 14,
|
|
gestalt_Unicode : 15,
|
|
gestalt_UnicodeNorm : 16,
|
|
gestalt_LineInputEcho : 17,
|
|
gestalt_LineTerminators : 18,
|
|
gestalt_LineTerminatorKey : 19,
|
|
gestalt_DateTime : 20,
|
|
gestalt_Sound2 : 21,
|
|
gestalt_ResourceStream : 22,
|
|
gestalt_GraphicsCharInput : 23,
|
|
|
|
keycode_Unknown : 0xffffffff,
|
|
keycode_Left : 0xfffffffe,
|
|
keycode_Right : 0xfffffffd,
|
|
keycode_Up : 0xfffffffc,
|
|
keycode_Down : 0xfffffffb,
|
|
keycode_Return : 0xfffffffa,
|
|
keycode_Delete : 0xfffffff9,
|
|
keycode_Escape : 0xfffffff8,
|
|
keycode_Tab : 0xfffffff7,
|
|
keycode_PageUp : 0xfffffff6,
|
|
keycode_PageDown : 0xfffffff5,
|
|
keycode_Home : 0xfffffff4,
|
|
keycode_End : 0xfffffff3,
|
|
keycode_Func1 : 0xffffffef,
|
|
keycode_Func2 : 0xffffffee,
|
|
keycode_Func3 : 0xffffffed,
|
|
keycode_Func4 : 0xffffffec,
|
|
keycode_Func5 : 0xffffffeb,
|
|
keycode_Func6 : 0xffffffea,
|
|
keycode_Func7 : 0xffffffe9,
|
|
keycode_Func8 : 0xffffffe8,
|
|
keycode_Func9 : 0xffffffe7,
|
|
keycode_Func10 : 0xffffffe6,
|
|
keycode_Func11 : 0xffffffe5,
|
|
keycode_Func12 : 0xffffffe4,
|
|
/* The last keycode is always (0x100000000 - keycode_MAXVAL) */
|
|
keycode_MAXVAL : 28,
|
|
|
|
evtype_None : 0,
|
|
evtype_Timer : 1,
|
|
evtype_CharInput : 2,
|
|
evtype_LineInput : 3,
|
|
evtype_MouseInput : 4,
|
|
evtype_Arrange : 5,
|
|
evtype_Redraw : 6,
|
|
evtype_SoundNotify : 7,
|
|
evtype_Hyperlink : 8,
|
|
evtype_VolumeNotify : 9,
|
|
|
|
style_Normal : 0,
|
|
style_Emphasized : 1,
|
|
style_Preformatted : 2,
|
|
style_Header : 3,
|
|
style_Subheader : 4,
|
|
style_Alert : 5,
|
|
style_Note : 6,
|
|
style_BlockQuote : 7,
|
|
style_Input : 8,
|
|
style_User1 : 9,
|
|
style_User2 : 10,
|
|
style_NUMSTYLES : 11,
|
|
|
|
wintype_AllTypes : 0,
|
|
wintype_Pair : 1,
|
|
wintype_Blank : 2,
|
|
wintype_TextBuffer : 3,
|
|
wintype_TextGrid : 4,
|
|
wintype_Graphics : 5,
|
|
|
|
winmethod_Left : 0x00,
|
|
winmethod_Right : 0x01,
|
|
winmethod_Above : 0x02,
|
|
winmethod_Below : 0x03,
|
|
winmethod_DirMask : 0x0f,
|
|
|
|
winmethod_Fixed : 0x10,
|
|
winmethod_Proportional : 0x20,
|
|
winmethod_DivisionMask : 0xf0,
|
|
|
|
winmethod_Border : 0x000,
|
|
winmethod_NoBorder : 0x100,
|
|
winmethod_BorderMask : 0x100,
|
|
|
|
fileusage_Data : 0x00,
|
|
fileusage_SavedGame : 0x01,
|
|
fileusage_Transcript : 0x02,
|
|
fileusage_InputRecord : 0x03,
|
|
fileusage_TypeMask : 0x0f,
|
|
|
|
fileusage_TextMode : 0x100,
|
|
fileusage_BinaryMode : 0x000,
|
|
|
|
filemode_Write : 0x01,
|
|
filemode_Read : 0x02,
|
|
filemode_ReadWrite : 0x03,
|
|
filemode_WriteAppend : 0x05,
|
|
|
|
seekmode_Start : 0,
|
|
seekmode_Current : 1,
|
|
seekmode_End : 2,
|
|
|
|
stylehint_Indentation : 0,
|
|
stylehint_ParaIndentation : 1,
|
|
stylehint_Justification : 2,
|
|
stylehint_Size : 3,
|
|
stylehint_Weight : 4,
|
|
stylehint_Oblique : 5,
|
|
stylehint_Proportional : 6,
|
|
stylehint_TextColor : 7,
|
|
stylehint_BackColor : 8,
|
|
stylehint_ReverseColor : 9,
|
|
stylehint_NUMHINTS : 10,
|
|
|
|
stylehint_just_LeftFlush : 0,
|
|
stylehint_just_LeftRight : 1,
|
|
stylehint_just_Centered : 2,
|
|
stylehint_just_RightFlush : 3,
|
|
|
|
imagealign_InlineUp : 1,
|
|
imagealign_InlineDown : 2,
|
|
imagealign_InlineCenter : 3,
|
|
imagealign_MarginLeft : 4,
|
|
imagealign_MarginRight : 5
|
|
|
|
};
|
|
|
|
var KeystrokeNameMap = {
|
|
/* The key values are taken from GlkOte's "char" event. A couple of them
|
|
are Javascript keywords, so they're in quotes, but that doesn't affect
|
|
the final structure. */
|
|
left : Const.keycode_Left,
|
|
right : Const.keycode_Right,
|
|
up : Const.keycode_Up,
|
|
down : Const.keycode_Down,
|
|
'return' : Const.keycode_Return,
|
|
'delete' : Const.keycode_Delete,
|
|
escape : Const.keycode_Escape,
|
|
tab : Const.keycode_Tab,
|
|
pageup : Const.keycode_PageUp,
|
|
pagedown : Const.keycode_PageDown,
|
|
home : Const.keycode_Home,
|
|
end : Const.keycode_End,
|
|
func1 : Const.keycode_Func1,
|
|
func2 : Const.keycode_Func2,
|
|
func3 : Const.keycode_Func3,
|
|
func4 : Const.keycode_Func4,
|
|
func5 : Const.keycode_Func5,
|
|
func6 : Const.keycode_Func6,
|
|
func7 : Const.keycode_Func7,
|
|
func8 : Const.keycode_Func8,
|
|
func9 : Const.keycode_Func9,
|
|
func10 : Const.keycode_Func10,
|
|
func11 : Const.keycode_Func11,
|
|
func12 : Const.keycode_Func12
|
|
};
|
|
|
|
/* The inverse of KeystrokeNameMap. We'll fill this in if needed. (It
|
|
generally isn't.) */
|
|
var KeystrokeValueMap = null;
|
|
|
|
var StyleNameMap = {
|
|
0 : 'normal',
|
|
1 : 'emphasized',
|
|
2 : 'preformatted',
|
|
3 : 'header',
|
|
4 : 'subheader',
|
|
5 : 'alert',
|
|
6 : 'note',
|
|
7 : 'blockquote',
|
|
8 : 'input',
|
|
9 : 'user1',
|
|
10 : 'user2'
|
|
};
|
|
|
|
var FileTypeMap = {
|
|
0: 'data',
|
|
1: 'save',
|
|
2: 'transcript',
|
|
3: 'command'
|
|
};
|
|
|
|
/* These tables were generated by casemap.py. */
|
|
/* Derived from Unicode data files, Unicode version 4.0.1. */
|
|
|
|
/* list all the special cases in unicode_upper_table */
|
|
var unicode_upper_table = {
|
|
181: 924, 223: [ 83,83 ], 255: 376, 305: 73, 329: [ 700,78 ],
|
|
383: 83, 405: 502, 414: 544, 447: 503, 454: 452,
|
|
457: 455, 460: 458, 477: 398, 496: [ 74,780 ], 499: 497,
|
|
595: 385, 596: 390, 598: 393, 599: 394, 601: 399,
|
|
603: 400, 608: 403, 611: 404, 616: 407, 617: 406,
|
|
623: 412, 626: 413, 629: 415, 640: 422, 643: 425,
|
|
648: 430, 650: 433, 651: 434, 658: 439, 837: 921,
|
|
912: [ 921,776,769 ], 940: 902, 941: 904, 942: 905, 943: 906,
|
|
944: [ 933,776,769 ], 962: 931, 972: 908, 973: 910, 974: 911,
|
|
976: 914, 977: 920, 981: 934, 982: 928, 1008: 922,
|
|
1010: 1017, 1013: 917, 1415: [ 1333,1362 ], 7830: [ 72,817 ], 7831: [ 84,776 ],
|
|
7832: [ 87,778 ], 7833: [ 89,778 ], 7834: [ 65,702 ], 7835: 7776, 8016: [ 933,787 ],
|
|
8018: [ 933,787,768 ], 8020: [ 933,787,769 ], 8022: [ 933,787,834 ], 8048: 8122, 8049: 8123,
|
|
8050: 8136, 8051: 8137, 8052: 8138, 8053: 8139, 8054: 8154,
|
|
8055: 8155, 8056: 8184, 8057: 8185, 8058: 8170, 8059: 8171,
|
|
8060: 8186, 8061: 8187, 8064: [ 7944,921 ], 8065: [ 7945,921 ], 8066: [ 7946,921 ],
|
|
8067: [ 7947,921 ], 8068: [ 7948,921 ], 8069: [ 7949,921 ], 8070: [ 7950,921 ], 8071: [ 7951,921 ],
|
|
8072: [ 7944,921 ], 8073: [ 7945,921 ], 8074: [ 7946,921 ], 8075: [ 7947,921 ], 8076: [ 7948,921 ],
|
|
8077: [ 7949,921 ], 8078: [ 7950,921 ], 8079: [ 7951,921 ], 8080: [ 7976,921 ], 8081: [ 7977,921 ],
|
|
8082: [ 7978,921 ], 8083: [ 7979,921 ], 8084: [ 7980,921 ], 8085: [ 7981,921 ], 8086: [ 7982,921 ],
|
|
8087: [ 7983,921 ], 8088: [ 7976,921 ], 8089: [ 7977,921 ], 8090: [ 7978,921 ], 8091: [ 7979,921 ],
|
|
8092: [ 7980,921 ], 8093: [ 7981,921 ], 8094: [ 7982,921 ], 8095: [ 7983,921 ], 8096: [ 8040,921 ],
|
|
8097: [ 8041,921 ], 8098: [ 8042,921 ], 8099: [ 8043,921 ], 8100: [ 8044,921 ], 8101: [ 8045,921 ],
|
|
8102: [ 8046,921 ], 8103: [ 8047,921 ], 8104: [ 8040,921 ], 8105: [ 8041,921 ], 8106: [ 8042,921 ],
|
|
8107: [ 8043,921 ], 8108: [ 8044,921 ], 8109: [ 8045,921 ], 8110: [ 8046,921 ], 8111: [ 8047,921 ],
|
|
8114: [ 8122,921 ], 8115: [ 913,921 ], 8116: [ 902,921 ], 8118: [ 913,834 ], 8119: [ 913,834,921 ],
|
|
8124: [ 913,921 ], 8126: 921, 8130: [ 8138,921 ], 8131: [ 919,921 ], 8132: [ 905,921 ],
|
|
8134: [ 919,834 ], 8135: [ 919,834,921 ], 8140: [ 919,921 ], 8146: [ 921,776,768 ], 8147: [ 921,776,769 ],
|
|
8150: [ 921,834 ], 8151: [ 921,776,834 ], 8162: [ 933,776,768 ], 8163: [ 933,776,769 ], 8164: [ 929,787 ],
|
|
8165: 8172, 8166: [ 933,834 ], 8167: [ 933,776,834 ], 8178: [ 8186,921 ], 8179: [ 937,921 ],
|
|
8180: [ 911,921 ], 8182: [ 937,834 ], 8183: [ 937,834,921 ], 8188: [ 937,921 ], 64256: [ 70,70 ],
|
|
64257: [ 70,73 ], 64258: [ 70,76 ], 64259: [ 70,70,73 ], 64260: [ 70,70,76 ], 64261: [ 83,84 ],
|
|
64262: [ 83,84 ], 64275: [ 1348,1350 ], 64276: [ 1348,1333 ], 64277: [ 1348,1339 ], 64278: [ 1358,1350 ],
|
|
64279: [ 1348,1341 ]
|
|
};
|
|
/* add all the regular cases to unicode_upper_table */
|
|
(function() {
|
|
var ls, ix, val;
|
|
var map = unicode_upper_table;
|
|
ls = [
|
|
7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943,
|
|
7952, 7953, 7954, 7955, 7956, 7957, 7968, 7969,
|
|
7970, 7971, 7972, 7973, 7974, 7975, 7984, 7985,
|
|
7986, 7987, 7988, 7989, 7990, 7991, 8000, 8001,
|
|
8002, 8003, 8004, 8005, 8017, 8019, 8021, 8023,
|
|
8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039,
|
|
8112, 8113, 8144, 8145, 8160, 8161,
|
|
];
|
|
for (ix=0; ix<54; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val+8;
|
|
}
|
|
for (val=257; val<=303; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=331; val<=375; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=505; val<=543; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=1121; val<=1153; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=1163; val<=1215; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=1233; val<=1269; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=7681; val<=7829; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
for (val=7841; val<=7929; val+=2) {
|
|
map[val] = val-1;
|
|
}
|
|
ls = [
|
|
307, 309, 311, 314, 316, 318, 320, 322,
|
|
324, 326, 328, 378, 380, 382, 387, 389,
|
|
392, 396, 402, 409, 417, 419, 421, 424,
|
|
429, 432, 436, 438, 441, 445, 453, 456,
|
|
459, 462, 464, 466, 468, 470, 472, 474,
|
|
476, 479, 481, 483, 485, 487, 489, 491,
|
|
493, 495, 498, 501, 547, 549, 551, 553,
|
|
555, 557, 559, 561, 563, 985, 987, 989,
|
|
991, 993, 995, 997, 999, 1001, 1003, 1005,
|
|
1007, 1016, 1019, 1218, 1220, 1222, 1224, 1226,
|
|
1228, 1230, 1273, 1281, 1283, 1285, 1287, 1289,
|
|
1291, 1293, 1295,
|
|
];
|
|
for (ix=0; ix<91; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val-1;
|
|
}
|
|
for (val=8560; val<=8575; val+=1) {
|
|
map[val] = val-16;
|
|
}
|
|
for (val=9424; val<=9449; val+=1) {
|
|
map[val] = val-26;
|
|
}
|
|
for (val=97; val<=122; val+=1) {
|
|
map[val] = val-32;
|
|
}
|
|
for (val=224; val<=246; val+=1) {
|
|
map[val] = val-32;
|
|
}
|
|
for (val=945; val<=961; val+=1) {
|
|
map[val] = val-32;
|
|
}
|
|
for (val=1072; val<=1103; val+=1) {
|
|
map[val] = val-32;
|
|
}
|
|
for (val=65345; val<=65370; val+=1) {
|
|
map[val] = val-32;
|
|
}
|
|
ls = [
|
|
248, 249, 250, 251, 252, 253, 254, 963,
|
|
964, 965, 966, 967, 968, 969, 970, 971,
|
|
];
|
|
for (ix=0; ix<16; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val-32;
|
|
}
|
|
for (val=66600; val<=66639; val+=1) {
|
|
map[val] = val-40;
|
|
}
|
|
for (val=1377; val<=1414; val+=1) {
|
|
map[val] = val-48;
|
|
}
|
|
for (val=1104; val<=1119; val+=1) {
|
|
map[val] = val-80;
|
|
}
|
|
map[1009] = 929;
|
|
})();
|
|
|
|
/* list all the special cases in unicode_lower_table */
|
|
var unicode_lower_table = {
|
|
304: [ 105,775 ], 376: 255, 385: 595, 390: 596, 393: 598,
|
|
394: 599, 398: 477, 399: 601, 400: 603, 403: 608,
|
|
404: 611, 406: 617, 407: 616, 412: 623, 413: 626,
|
|
415: 629, 422: 640, 425: 643, 430: 648, 433: 650,
|
|
434: 651, 439: 658, 452: 454, 455: 457, 458: 460,
|
|
497: 499, 502: 405, 503: 447, 544: 414, 902: 940,
|
|
904: 941, 905: 942, 906: 943, 908: 972, 910: 973,
|
|
911: 974, 1012: 952, 1017: 1010, 8122: 8048, 8123: 8049,
|
|
8124: 8115, 8136: 8050, 8137: 8051, 8138: 8052, 8139: 8053,
|
|
8140: 8131, 8154: 8054, 8155: 8055, 8170: 8058, 8171: 8059,
|
|
8172: 8165, 8184: 8056, 8185: 8057, 8186: 8060, 8187: 8061,
|
|
8188: 8179, 8486: 969, 8490: 107, 8491: 229
|
|
};
|
|
/* add all the regular cases to unicode_lower_table */
|
|
(function() {
|
|
var ls, ix, val;
|
|
var map = unicode_lower_table;
|
|
for (val=1024; val<=1039; val+=1) {
|
|
map[val] = val+80;
|
|
}
|
|
for (val=1329; val<=1366; val+=1) {
|
|
map[val] = val+48;
|
|
}
|
|
for (val=66560; val<=66599; val+=1) {
|
|
map[val] = val+40;
|
|
}
|
|
for (val=65; val<=90; val+=1) {
|
|
map[val] = val+32;
|
|
}
|
|
for (val=192; val<=214; val+=1) {
|
|
map[val] = val+32;
|
|
}
|
|
for (val=913; val<=929; val+=1) {
|
|
map[val] = val+32;
|
|
}
|
|
for (val=1040; val<=1071; val+=1) {
|
|
map[val] = val+32;
|
|
}
|
|
for (val=65313; val<=65338; val+=1) {
|
|
map[val] = val+32;
|
|
}
|
|
ls = [
|
|
216, 217, 218, 219, 220, 221, 222, 931,
|
|
932, 933, 934, 935, 936, 937, 938, 939,
|
|
];
|
|
for (ix=0; ix<16; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val+32;
|
|
}
|
|
for (val=9398; val<=9423; val+=1) {
|
|
map[val] = val+26;
|
|
}
|
|
for (val=8544; val<=8559; val+=1) {
|
|
map[val] = val+16;
|
|
}
|
|
for (val=256; val<=302; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=330; val<=374; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=504; val<=542; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=1120; val<=1152; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=1162; val<=1214; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=1232; val<=1268; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=7680; val<=7828; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
for (val=7840; val<=7928; val+=2) {
|
|
map[val] = val+1;
|
|
}
|
|
ls = [
|
|
306, 308, 310, 313, 315, 317, 319, 321,
|
|
323, 325, 327, 377, 379, 381, 386, 388,
|
|
391, 395, 401, 408, 416, 418, 420, 423,
|
|
428, 431, 435, 437, 440, 444, 453, 456,
|
|
459, 461, 463, 465, 467, 469, 471, 473,
|
|
475, 478, 480, 482, 484, 486, 488, 490,
|
|
492, 494, 498, 500, 546, 548, 550, 552,
|
|
554, 556, 558, 560, 562, 984, 986, 988,
|
|
990, 992, 994, 996, 998, 1000, 1002, 1004,
|
|
1006, 1015, 1018, 1217, 1219, 1221, 1223, 1225,
|
|
1227, 1229, 1272, 1280, 1282, 1284, 1286, 1288,
|
|
1290, 1292, 1294,
|
|
];
|
|
for (ix=0; ix<91; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val+1;
|
|
}
|
|
ls = [
|
|
7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951,
|
|
7960, 7961, 7962, 7963, 7964, 7965, 7976, 7977,
|
|
7978, 7979, 7980, 7981, 7982, 7983, 7992, 7993,
|
|
7994, 7995, 7996, 7997, 7998, 7999, 8008, 8009,
|
|
8010, 8011, 8012, 8013, 8025, 8027, 8029, 8031,
|
|
8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047,
|
|
8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079,
|
|
8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095,
|
|
8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111,
|
|
8120, 8121, 8152, 8153, 8168, 8169,
|
|
];
|
|
for (ix=0; ix<78; ix++) {
|
|
val = ls[ix];
|
|
map[val] = val-8;
|
|
}
|
|
})();
|
|
|
|
/* list all the special cases in unicode_title_table */
|
|
var unicode_title_table = {
|
|
223: [ 83,115 ], 452: 453, 453: 453, 454: 453, 455: 456,
|
|
456: 456, 457: 456, 458: 459, 459: 459, 460: 459,
|
|
497: 498, 498: 498, 499: 498, 1415: [ 1333,1410 ], 8114: [ 8122,837 ],
|
|
8115: 8124, 8116: [ 902,837 ], 8119: [ 913,834,837 ], 8124: 8124, 8130: [ 8138,837 ],
|
|
8131: 8140, 8132: [ 905,837 ], 8135: [ 919,834,837 ], 8140: 8140, 8178: [ 8186,837 ],
|
|
8179: 8188, 8180: [ 911,837 ], 8183: [ 937,834,837 ], 8188: 8188, 64256: [ 70,102 ],
|
|
64257: [ 70,105 ], 64258: [ 70,108 ], 64259: [ 70,102,105 ], 64260: [ 70,102,108 ], 64261: [ 83,116 ],
|
|
64262: [ 83,116 ], 64275: [ 1348,1398 ], 64276: [ 1348,1381 ], 64277: [ 1348,1387 ], 64278: [ 1358,1398 ],
|
|
64279: [ 1348,1389 ]
|
|
};
|
|
/* add all the regular cases to unicode_title_table */
|
|
(function() {
|
|
var ls, ix, val;
|
|
var map = unicode_title_table;
|
|
ls = [
|
|
8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079,
|
|
8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079,
|
|
8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095,
|
|
8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095,
|
|
8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111,
|
|
8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111,
|
|
];
|
|
for (ix=0; ix<48; ix++) {
|
|
val = ls[ix];
|
|
map[ix+8064] = val;
|
|
}
|
|
})();
|
|
|
|
/* list all the special cases in unicode_decomp_table */
|
|
var unicode_decomp_table = {
|
|
192: [ 65,768 ], 193: [ 65,769 ], 194: [ 65,770 ], 195: [ 65,771 ], 196: [ 65,776 ],
|
|
197: [ 65,778 ], 199: [ 67,807 ], 200: [ 69,768 ], 201: [ 69,769 ], 202: [ 69,770 ],
|
|
203: [ 69,776 ], 204: [ 73,768 ], 205: [ 73,769 ], 206: [ 73,770 ], 207: [ 73,776 ],
|
|
209: [ 78,771 ], 210: [ 79,768 ], 211: [ 79,769 ], 212: [ 79,770 ], 213: [ 79,771 ],
|
|
214: [ 79,776 ], 217: [ 85,768 ], 218: [ 85,769 ], 219: [ 85,770 ], 220: [ 85,776 ],
|
|
221: [ 89,769 ], 224: [ 97,768 ], 225: [ 97,769 ], 226: [ 97,770 ], 227: [ 97,771 ],
|
|
228: [ 97,776 ], 229: [ 97,778 ], 231: [ 99,807 ], 232: [ 101,768 ], 233: [ 101,769 ],
|
|
234: [ 101,770 ], 235: [ 101,776 ], 236: [ 105,768 ], 237: [ 105,769 ], 238: [ 105,770 ],
|
|
239: [ 105,776 ], 241: [ 110,771 ], 242: [ 111,768 ], 243: [ 111,769 ], 244: [ 111,770 ],
|
|
245: [ 111,771 ], 246: [ 111,776 ], 249: [ 117,768 ], 250: [ 117,769 ], 251: [ 117,770 ],
|
|
252: [ 117,776 ], 253: [ 121,769 ], 296: [ 73,771 ], 297: [ 105,771 ], 298: [ 73,772 ],
|
|
299: [ 105,772 ], 300: [ 73,774 ], 301: [ 105,774 ], 302: [ 73,808 ], 303: [ 105,808 ],
|
|
304: [ 73,775 ], 308: [ 74,770 ], 309: [ 106,770 ], 310: [ 75,807 ], 311: [ 107,807 ],
|
|
313: [ 76,769 ], 314: [ 108,769 ], 315: [ 76,807 ], 316: [ 108,807 ], 317: [ 76,780 ],
|
|
318: [ 108,780 ], 323: [ 78,769 ], 324: [ 110,769 ], 325: [ 78,807 ], 326: [ 110,807 ],
|
|
327: [ 78,780 ], 328: [ 110,780 ], 332: [ 79,772 ], 333: [ 111,772 ], 334: [ 79,774 ],
|
|
335: [ 111,774 ], 336: [ 79,779 ], 337: [ 111,779 ], 416: [ 79,795 ], 417: [ 111,795 ],
|
|
431: [ 85,795 ], 432: [ 117,795 ], 478: [ 65,776,772 ], 479: [ 97,776,772 ], 480: [ 65,775,772 ],
|
|
481: [ 97,775,772 ], 482: [ 198,772 ], 483: [ 230,772 ], 486: [ 71,780 ], 487: [ 103,780 ],
|
|
488: [ 75,780 ], 489: [ 107,780 ], 490: [ 79,808 ], 491: [ 111,808 ], 492: [ 79,808,772 ],
|
|
493: [ 111,808,772 ], 494: [ 439,780 ], 495: [ 658,780 ], 496: [ 106,780 ], 500: [ 71,769 ],
|
|
501: [ 103,769 ], 542: [ 72,780 ], 543: [ 104,780 ], 550: [ 65,775 ], 551: [ 97,775 ],
|
|
552: [ 69,807 ], 553: [ 101,807 ], 554: [ 79,776,772 ], 555: [ 111,776,772 ], 556: [ 79,771,772 ],
|
|
557: [ 111,771,772 ], 558: [ 79,775 ], 559: [ 111,775 ], 560: [ 79,775,772 ], 561: [ 111,775,772 ],
|
|
562: [ 89,772 ], 563: [ 121,772 ], 832: 768, 833: 769, 835: 787,
|
|
836: [ 776,769 ], 884: 697, 894: 59, 901: [ 168,769 ], 902: [ 913,769 ],
|
|
903: 183, 904: [ 917,769 ], 905: [ 919,769 ], 906: [ 921,769 ], 908: [ 927,769 ],
|
|
910: [ 933,769 ], 911: [ 937,769 ], 912: [ 953,776,769 ], 938: [ 921,776 ], 939: [ 933,776 ],
|
|
940: [ 945,769 ], 941: [ 949,769 ], 942: [ 951,769 ], 943: [ 953,769 ], 944: [ 965,776,769 ],
|
|
970: [ 953,776 ], 971: [ 965,776 ], 972: [ 959,769 ], 973: [ 965,769 ], 974: [ 969,769 ],
|
|
979: [ 978,769 ], 980: [ 978,776 ], 1024: [ 1045,768 ], 1025: [ 1045,776 ], 1027: [ 1043,769 ],
|
|
1031: [ 1030,776 ], 1036: [ 1050,769 ], 1037: [ 1048,768 ], 1038: [ 1059,774 ], 1049: [ 1048,774 ],
|
|
1081: [ 1080,774 ], 1104: [ 1077,768 ], 1105: [ 1077,776 ], 1107: [ 1075,769 ], 1111: [ 1110,776 ],
|
|
1116: [ 1082,769 ], 1117: [ 1080,768 ], 1118: [ 1091,774 ], 1142: [ 1140,783 ], 1143: [ 1141,783 ],
|
|
1217: [ 1046,774 ], 1218: [ 1078,774 ], 1232: [ 1040,774 ], 1233: [ 1072,774 ], 1234: [ 1040,776 ],
|
|
1235: [ 1072,776 ], 1238: [ 1045,774 ], 1239: [ 1077,774 ], 1242: [ 1240,776 ], 1243: [ 1241,776 ],
|
|
1244: [ 1046,776 ], 1245: [ 1078,776 ], 1246: [ 1047,776 ], 1247: [ 1079,776 ], 1250: [ 1048,772 ],
|
|
1251: [ 1080,772 ], 1252: [ 1048,776 ], 1253: [ 1080,776 ], 1254: [ 1054,776 ], 1255: [ 1086,776 ],
|
|
1258: [ 1256,776 ], 1259: [ 1257,776 ], 1260: [ 1069,776 ], 1261: [ 1101,776 ], 1262: [ 1059,772 ],
|
|
1263: [ 1091,772 ], 1264: [ 1059,776 ], 1265: [ 1091,776 ], 1266: [ 1059,779 ], 1267: [ 1091,779 ],
|
|
1268: [ 1063,776 ], 1269: [ 1095,776 ], 1272: [ 1067,776 ], 1273: [ 1099,776 ], 1570: [ 1575,1619 ],
|
|
1571: [ 1575,1620 ], 1572: [ 1608,1620 ], 1573: [ 1575,1621 ], 1574: [ 1610,1620 ], 1728: [ 1749,1620 ],
|
|
1730: [ 1729,1620 ], 1747: [ 1746,1620 ], 2345: [ 2344,2364 ], 2353: [ 2352,2364 ], 2356: [ 2355,2364 ],
|
|
2392: [ 2325,2364 ], 2393: [ 2326,2364 ], 2394: [ 2327,2364 ], 2395: [ 2332,2364 ], 2396: [ 2337,2364 ],
|
|
2397: [ 2338,2364 ], 2398: [ 2347,2364 ], 2399: [ 2351,2364 ], 2507: [ 2503,2494 ], 2508: [ 2503,2519 ],
|
|
2524: [ 2465,2492 ], 2525: [ 2466,2492 ], 2527: [ 2479,2492 ], 2611: [ 2610,2620 ], 2614: [ 2616,2620 ],
|
|
2649: [ 2582,2620 ], 2650: [ 2583,2620 ], 2651: [ 2588,2620 ], 2654: [ 2603,2620 ], 2888: [ 2887,2902 ],
|
|
2891: [ 2887,2878 ], 2892: [ 2887,2903 ], 2908: [ 2849,2876 ], 2909: [ 2850,2876 ], 2964: [ 2962,3031 ],
|
|
3018: [ 3014,3006 ], 3019: [ 3015,3006 ], 3020: [ 3014,3031 ], 3144: [ 3142,3158 ], 3264: [ 3263,3285 ],
|
|
3271: [ 3270,3285 ], 3272: [ 3270,3286 ], 3274: [ 3270,3266 ], 3275: [ 3270,3266,3285 ], 3402: [ 3398,3390 ],
|
|
3403: [ 3399,3390 ], 3404: [ 3398,3415 ], 3546: [ 3545,3530 ], 3548: [ 3545,3535 ], 3549: [ 3545,3535,3530 ],
|
|
3550: [ 3545,3551 ], 3907: [ 3906,4023 ], 3917: [ 3916,4023 ], 3922: [ 3921,4023 ], 3927: [ 3926,4023 ],
|
|
3932: [ 3931,4023 ], 3945: [ 3904,4021 ], 3955: [ 3953,3954 ], 3957: [ 3953,3956 ], 3958: [ 4018,3968 ],
|
|
3960: [ 4019,3968 ], 3969: [ 3953,3968 ], 3987: [ 3986,4023 ], 3997: [ 3996,4023 ], 4002: [ 4001,4023 ],
|
|
4007: [ 4006,4023 ], 4012: [ 4011,4023 ], 4025: [ 3984,4021 ], 4134: [ 4133,4142 ], 7835: [ 383,775 ],
|
|
7960: [ 917,787 ], 7961: [ 917,788 ], 7962: [ 917,787,768 ], 7963: [ 917,788,768 ], 7964: [ 917,787,769 ],
|
|
7965: [ 917,788,769 ], 8008: [ 927,787 ], 8009: [ 927,788 ], 8010: [ 927,787,768 ], 8011: [ 927,788,768 ],
|
|
8012: [ 927,787,769 ], 8013: [ 927,788,769 ], 8016: [ 965,787 ], 8017: [ 965,788 ], 8018: [ 965,787,768 ],
|
|
8019: [ 965,788,768 ], 8020: [ 965,787,769 ], 8021: [ 965,788,769 ], 8022: [ 965,787,834 ], 8023: [ 965,788,834 ],
|
|
8025: [ 933,788 ], 8027: [ 933,788,768 ], 8029: [ 933,788,769 ], 8118: [ 945,834 ], 8119: [ 945,834,837 ],
|
|
8120: [ 913,774 ], 8121: [ 913,772 ], 8122: [ 913,768 ], 8123: [ 913,769 ], 8124: [ 913,837 ],
|
|
8126: 953, 8129: [ 168,834 ], 8130: [ 951,768,837 ], 8131: [ 951,837 ], 8132: [ 951,769,837 ],
|
|
8134: [ 951,834 ], 8135: [ 951,834,837 ], 8136: [ 917,768 ], 8137: [ 917,769 ], 8138: [ 919,768 ],
|
|
8139: [ 919,769 ], 8140: [ 919,837 ], 8141: [ 8127,768 ], 8142: [ 8127,769 ], 8143: [ 8127,834 ],
|
|
8144: [ 953,774 ], 8145: [ 953,772 ], 8146: [ 953,776,768 ], 8147: [ 953,776,769 ], 8150: [ 953,834 ],
|
|
8151: [ 953,776,834 ], 8152: [ 921,774 ], 8153: [ 921,772 ], 8154: [ 921,768 ], 8155: [ 921,769 ],
|
|
8178: [ 969,768,837 ], 8179: [ 969,837 ], 8180: [ 969,769,837 ], 8182: [ 969,834 ], 8183: [ 969,834,837 ],
|
|
8184: [ 927,768 ], 8185: [ 927,769 ], 8186: [ 937,768 ], 8187: [ 937,769 ], 8188: [ 937,837 ],
|
|
8189: 180, 8192: 8194, 8193: 8195, 8486: 937, 8490: 75,
|
|
8491: [ 65,778 ], 8602: [ 8592,824 ], 8603: [ 8594,824 ], 8622: [ 8596,824 ], 8653: [ 8656,824 ],
|
|
8654: [ 8660,824 ], 8655: [ 8658,824 ], 8708: [ 8707,824 ], 8713: [ 8712,824 ], 8716: [ 8715,824 ],
|
|
8740: [ 8739,824 ], 8742: [ 8741,824 ], 8769: [ 8764,824 ], 8772: [ 8771,824 ], 8775: [ 8773,824 ],
|
|
8777: [ 8776,824 ], 8800: [ 61,824 ], 8802: [ 8801,824 ], 8813: [ 8781,824 ], 8814: [ 60,824 ],
|
|
8815: [ 62,824 ], 8816: [ 8804,824 ], 8817: [ 8805,824 ], 8820: [ 8818,824 ], 8821: [ 8819,824 ],
|
|
8824: [ 8822,824 ], 8825: [ 8823,824 ], 8832: [ 8826,824 ], 8833: [ 8827,824 ], 8836: [ 8834,824 ],
|
|
8837: [ 8835,824 ], 8840: [ 8838,824 ], 8841: [ 8839,824 ], 8876: [ 8866,824 ], 8877: [ 8872,824 ],
|
|
8878: [ 8873,824 ], 8879: [ 8875,824 ], 8928: [ 8828,824 ], 8929: [ 8829,824 ], 8930: [ 8849,824 ],
|
|
8931: [ 8850,824 ], 8938: [ 8882,824 ], 8939: [ 8883,824 ], 8940: [ 8884,824 ], 8941: [ 8885,824 ],
|
|
9001: 12296, 9002: 12297, 10972: [ 10973,824 ], 12364: [ 12363,12441 ], 12366: [ 12365,12441 ],
|
|
12368: [ 12367,12441 ], 12370: [ 12369,12441 ], 12372: [ 12371,12441 ], 12374: [ 12373,12441 ], 12376: [ 12375,12441 ],
|
|
12378: [ 12377,12441 ], 12380: [ 12379,12441 ], 12382: [ 12381,12441 ], 12384: [ 12383,12441 ], 12386: [ 12385,12441 ],
|
|
12389: [ 12388,12441 ], 12391: [ 12390,12441 ], 12393: [ 12392,12441 ], 12400: [ 12399,12441 ], 12401: [ 12399,12442 ],
|
|
12403: [ 12402,12441 ], 12404: [ 12402,12442 ], 12406: [ 12405,12441 ], 12407: [ 12405,12442 ], 12409: [ 12408,12441 ],
|
|
12410: [ 12408,12442 ], 12412: [ 12411,12441 ], 12413: [ 12411,12442 ], 12436: [ 12358,12441 ], 12446: [ 12445,12441 ],
|
|
12460: [ 12459,12441 ], 12462: [ 12461,12441 ], 12464: [ 12463,12441 ], 12466: [ 12465,12441 ], 12468: [ 12467,12441 ],
|
|
12470: [ 12469,12441 ], 12472: [ 12471,12441 ], 12474: [ 12473,12441 ], 12476: [ 12475,12441 ], 12478: [ 12477,12441 ],
|
|
12480: [ 12479,12441 ], 12482: [ 12481,12441 ], 12485: [ 12484,12441 ], 12487: [ 12486,12441 ], 12489: [ 12488,12441 ],
|
|
12496: [ 12495,12441 ], 12497: [ 12495,12442 ], 12499: [ 12498,12441 ], 12500: [ 12498,12442 ], 12502: [ 12501,12441 ],
|
|
12503: [ 12501,12442 ], 12505: [ 12504,12441 ], 12506: [ 12504,12442 ], 12508: [ 12507,12441 ], 12509: [ 12507,12442 ],
|
|
12532: [ 12454,12441 ], 12535: [ 12527,12441 ], 12536: [ 12528,12441 ], 12537: [ 12529,12441 ], 12538: [ 12530,12441 ],
|
|
12542: [ 12541,12441 ], 64016: 22618, 64018: 26228, 64021: 20958, 64022: 29482,
|
|
64023: 30410, 64024: 31036, 64025: 31070, 64026: 31077, 64027: 31119,
|
|
64028: 38742, 64029: 31934, 64030: 32701, 64032: 34322, 64034: 35576,
|
|
64037: 36920, 64038: 37117, 64042: 39151, 64043: 39164, 64044: 39208,
|
|
64045: 40372, 64285: [ 1497,1460 ], 64287: [ 1522,1463 ], 64298: [ 1513,1473 ], 64299: [ 1513,1474 ],
|
|
64300: [ 1513,1468,1473 ], 64301: [ 1513,1468,1474 ], 64302: [ 1488,1463 ], 64303: [ 1488,1464 ], 64304: [ 1488,1468 ],
|
|
64305: [ 1489,1468 ], 64306: [ 1490,1468 ], 64307: [ 1491,1468 ], 64308: [ 1492,1468 ], 64309: [ 1493,1468 ],
|
|
64310: [ 1494,1468 ], 64312: [ 1496,1468 ], 64313: [ 1497,1468 ], 64314: [ 1498,1468 ], 64315: [ 1499,1468 ],
|
|
64316: [ 1500,1468 ], 64318: [ 1502,1468 ], 64320: [ 1504,1468 ], 64321: [ 1505,1468 ], 64323: [ 1507,1468 ],
|
|
64324: [ 1508,1468 ], 64326: [ 1510,1468 ], 64327: [ 1511,1468 ], 64328: [ 1512,1468 ], 64329: [ 1513,1468 ],
|
|
64330: [ 1514,1468 ], 64331: [ 1493,1465 ], 64332: [ 1489,1471 ], 64333: [ 1499,1471 ], 64334: [ 1508,1471 ],
|
|
119134: [ 119127,119141 ], 119135: [ 119128,119141 ], 119136: [ 119128,119141,119150 ], 119137: [ 119128,119141,119151 ], 119138: [ 119128,119141,119152 ],
|
|
119139: [ 119128,119141,119153 ], 119140: [ 119128,119141,119154 ], 119227: [ 119225,119141 ], 119228: [ 119226,119141 ], 119229: [ 119225,119141,119150 ],
|
|
119230: [ 119226,119141,119150 ], 119231: [ 119225,119141,119151 ], 119232: [ 119226,119141,119151 ]
|
|
};
|
|
/* add all the regular cases to unicode_decomp_table */
|
|
(function() {
|
|
var ls, ix, val;
|
|
var map = unicode_decomp_table;
|
|
ls = [
|
|
[121,776], [65,772], [97,772], [65,774], [97,774], [65,808], [97,808], [67,769],
|
|
[99,769], [67,770], [99,770], [67,775], [99,775], [67,780], [99,780], [68,780],
|
|
[100,780],
|
|
];
|
|
for (ix=0; ix<17; ix++) {
|
|
val = ls[ix];
|
|
map[ix+255] = val;
|
|
}
|
|
ls = [
|
|
[69,772], [101,772], [69,774], [101,774], [69,775], [101,775], [69,808], [101,808],
|
|
[69,780], [101,780], [71,770], [103,770], [71,774], [103,774], [71,775], [103,775],
|
|
[71,807], [103,807], [72,770], [104,770],
|
|
];
|
|
for (ix=0; ix<20; ix++) {
|
|
val = ls[ix];
|
|
map[ix+274] = val;
|
|
}
|
|
ls = [
|
|
[82,769], [114,769], [82,807], [114,807], [82,780], [114,780], [83,769], [115,769],
|
|
[83,770], [115,770], [83,807], [115,807], [83,780], [115,780], [84,807], [116,807],
|
|
[84,780], [116,780],
|
|
];
|
|
for (ix=0; ix<18; ix++) {
|
|
val = ls[ix];
|
|
map[ix+340] = val;
|
|
}
|
|
ls = [
|
|
[85,771], [117,771], [85,772], [117,772], [85,774], [117,774], [85,778], [117,778],
|
|
[85,779], [117,779], [85,808], [117,808], [87,770], [119,770], [89,770], [121,770],
|
|
[89,776], [90,769], [122,769], [90,775], [122,775], [90,780], [122,780],
|
|
];
|
|
for (ix=0; ix<23; ix++) {
|
|
val = ls[ix];
|
|
map[ix+360] = val;
|
|
}
|
|
ls = [
|
|
[65,780], [97,780], [73,780], [105,780], [79,780], [111,780], [85,780], [117,780],
|
|
[85,776,772], [117,776,772], [85,776,769], [117,776,769], [85,776,780], [117,776,780], [85,776,768], [117,776,768],
|
|
];
|
|
for (ix=0; ix<16; ix++) {
|
|
val = ls[ix];
|
|
map[ix+461] = val;
|
|
}
|
|
ls = [
|
|
[78,768], [110,768], [65,778,769], [97,778,769], [198,769], [230,769], [216,769], [248,769],
|
|
[65,783], [97,783], [65,785], [97,785], [69,783], [101,783], [69,785], [101,785],
|
|
[73,783], [105,783], [73,785], [105,785], [79,783], [111,783], [79,785], [111,785],
|
|
[82,783], [114,783], [82,785], [114,785], [85,783], [117,783], [85,785], [117,785],
|
|
[83,806], [115,806], [84,806], [116,806],
|
|
];
|
|
for (ix=0; ix<36; ix++) {
|
|
val = ls[ix];
|
|
map[ix+504] = val;
|
|
}
|
|
ls = [
|
|
[65,805], [97,805], [66,775], [98,775], [66,803], [98,803], [66,817], [98,817],
|
|
[67,807,769], [99,807,769], [68,775], [100,775], [68,803], [100,803], [68,817], [100,817],
|
|
[68,807], [100,807], [68,813], [100,813], [69,772,768], [101,772,768], [69,772,769], [101,772,769],
|
|
[69,813], [101,813], [69,816], [101,816], [69,807,774], [101,807,774], [70,775], [102,775],
|
|
[71,772], [103,772], [72,775], [104,775], [72,803], [104,803], [72,776], [104,776],
|
|
[72,807], [104,807], [72,814], [104,814], [73,816], [105,816], [73,776,769], [105,776,769],
|
|
[75,769], [107,769], [75,803], [107,803], [75,817], [107,817], [76,803], [108,803],
|
|
[76,803,772], [108,803,772], [76,817], [108,817], [76,813], [108,813], [77,769], [109,769],
|
|
[77,775], [109,775], [77,803], [109,803], [78,775], [110,775], [78,803], [110,803],
|
|
[78,817], [110,817], [78,813], [110,813], [79,771,769], [111,771,769], [79,771,776], [111,771,776],
|
|
[79,772,768], [111,772,768], [79,772,769], [111,772,769], [80,769], [112,769], [80,775], [112,775],
|
|
[82,775], [114,775], [82,803], [114,803], [82,803,772], [114,803,772], [82,817], [114,817],
|
|
[83,775], [115,775], [83,803], [115,803], [83,769,775], [115,769,775], [83,780,775], [115,780,775],
|
|
[83,803,775], [115,803,775], [84,775], [116,775], [84,803], [116,803], [84,817], [116,817],
|
|
[84,813], [116,813], [85,804], [117,804], [85,816], [117,816], [85,813], [117,813],
|
|
[85,771,769], [117,771,769], [85,772,776], [117,772,776], [86,771], [118,771], [86,803], [118,803],
|
|
[87,768], [119,768], [87,769], [119,769], [87,776], [119,776], [87,775], [119,775],
|
|
[87,803], [119,803], [88,775], [120,775], [88,776], [120,776], [89,775], [121,775],
|
|
[90,770], [122,770], [90,803], [122,803], [90,817], [122,817], [104,817], [116,776],
|
|
[119,778], [121,778],
|
|
];
|
|
for (ix=0; ix<154; ix++) {
|
|
val = ls[ix];
|
|
map[ix+7680] = val;
|
|
}
|
|
ls = [
|
|
[65,803], [97,803], [65,777], [97,777], [65,770,769], [97,770,769], [65,770,768], [97,770,768],
|
|
[65,770,777], [97,770,777], [65,770,771], [97,770,771], [65,803,770], [97,803,770], [65,774,769], [97,774,769],
|
|
[65,774,768], [97,774,768], [65,774,777], [97,774,777], [65,774,771], [97,774,771], [65,803,774], [97,803,774],
|
|
[69,803], [101,803], [69,777], [101,777], [69,771], [101,771], [69,770,769], [101,770,769],
|
|
[69,770,768], [101,770,768], [69,770,777], [101,770,777], [69,770,771], [101,770,771], [69,803,770], [101,803,770],
|
|
[73,777], [105,777], [73,803], [105,803], [79,803], [111,803], [79,777], [111,777],
|
|
[79,770,769], [111,770,769], [79,770,768], [111,770,768], [79,770,777], [111,770,777], [79,770,771], [111,770,771],
|
|
[79,803,770], [111,803,770], [79,795,769], [111,795,769], [79,795,768], [111,795,768], [79,795,777], [111,795,777],
|
|
[79,795,771], [111,795,771], [79,795,803], [111,795,803], [85,803], [117,803], [85,777], [117,777],
|
|
[85,795,769], [117,795,769], [85,795,768], [117,795,768], [85,795,777], [117,795,777], [85,795,771], [117,795,771],
|
|
[85,795,803], [117,795,803], [89,768], [121,768], [89,803], [121,803], [89,777], [121,777],
|
|
[89,771], [121,771],
|
|
];
|
|
for (ix=0; ix<90; ix++) {
|
|
val = ls[ix];
|
|
map[ix+7840] = val;
|
|
}
|
|
ls = [
|
|
[945,787], [945,788], [945,787,768], [945,788,768], [945,787,769], [945,788,769], [945,787,834], [945,788,834],
|
|
[913,787], [913,788], [913,787,768], [913,788,768], [913,787,769], [913,788,769], [913,787,834], [913,788,834],
|
|
[949,787], [949,788], [949,787,768], [949,788,768], [949,787,769], [949,788,769],
|
|
];
|
|
for (ix=0; ix<22; ix++) {
|
|
val = ls[ix];
|
|
map[ix+7936] = val;
|
|
}
|
|
ls = [
|
|
[951,787], [951,788], [951,787,768], [951,788,768], [951,787,769], [951,788,769], [951,787,834], [951,788,834],
|
|
[919,787], [919,788], [919,787,768], [919,788,768], [919,787,769], [919,788,769], [919,787,834], [919,788,834],
|
|
[953,787], [953,788], [953,787,768], [953,788,768], [953,787,769], [953,788,769], [953,787,834], [953,788,834],
|
|
[921,787], [921,788], [921,787,768], [921,788,768], [921,787,769], [921,788,769], [921,787,834], [921,788,834],
|
|
[959,787], [959,788], [959,787,768], [959,788,768], [959,787,769], [959,788,769],
|
|
];
|
|
for (ix=0; ix<38; ix++) {
|
|
val = ls[ix];
|
|
map[ix+7968] = val;
|
|
}
|
|
ls = [
|
|
[933,788,834], [969,787], [969,788], [969,787,768], [969,788,768], [969,787,769], [969,788,769], [969,787,834],
|
|
[969,788,834], [937,787], [937,788], [937,787,768], [937,788,768], [937,787,769], [937,788,769], [937,787,834],
|
|
[937,788,834], [945,768], [945,769], [949,768], [949,769], [951,768], [951,769], [953,768],
|
|
[953,769], [959,768], [959,769], [965,768], [965,769], [969,768], [969,769],
|
|
];
|
|
for (ix=0; ix<31; ix++) {
|
|
val = ls[ix];
|
|
map[ix+8031] = val;
|
|
}
|
|
ls = [
|
|
[945,787,837], [945,788,837], [945,787,768,837], [945,788,768,837], [945,787,769,837], [945,788,769,837], [945,787,834,837], [945,788,834,837],
|
|
[913,787,837], [913,788,837], [913,787,768,837], [913,788,768,837], [913,787,769,837], [913,788,769,837], [913,787,834,837], [913,788,834,837],
|
|
[951,787,837], [951,788,837], [951,787,768,837], [951,788,768,837], [951,787,769,837], [951,788,769,837], [951,787,834,837], [951,788,834,837],
|
|
[919,787,837], [919,788,837], [919,787,768,837], [919,788,768,837], [919,787,769,837], [919,788,769,837], [919,787,834,837], [919,788,834,837],
|
|
[969,787,837], [969,788,837], [969,787,768,837], [969,788,768,837], [969,787,769,837], [969,788,769,837], [969,787,834,837], [969,788,834,837],
|
|
[937,787,837], [937,788,837], [937,787,768,837], [937,788,768,837], [937,787,769,837], [937,788,769,837], [937,787,834,837], [937,788,834,837],
|
|
[945,774], [945,772], [945,768,837], [945,837], [945,769,837],
|
|
];
|
|
for (ix=0; ix<53; ix++) {
|
|
val = ls[ix];
|
|
map[ix+8064] = val;
|
|
}
|
|
ls = [
|
|
[8190,768], [8190,769], [8190,834], [965,774], [965,772], [965,776,768], [965,776,769], [961,787],
|
|
[961,788], [965,834], [965,776,834], [933,774], [933,772], [933,768], [933,769], [929,788],
|
|
[168,768], [168,769], 96,
|
|
];
|
|
for (ix=0; ix<19; ix++) {
|
|
val = ls[ix];
|
|
map[ix+8157] = val;
|
|
}
|
|
ls = [
|
|
35912, 26356, 36554, 36040, 28369, 20018, 21477, 40860,
|
|
40860, 22865, 37329, 21895, 22856, 25078, 30313, 32645,
|
|
34367, 34746, 35064, 37007, 27138, 27931, 28889, 29662,
|
|
33853, 37226, 39409, 20098, 21365, 27396, 29211, 34349,
|
|
40478, 23888, 28651, 34253, 35172, 25289, 33240, 34847,
|
|
24266, 26391, 28010, 29436, 37070, 20358, 20919, 21214,
|
|
25796, 27347, 29200, 30439, 32769, 34310, 34396, 36335,
|
|
38706, 39791, 40442, 30860, 31103, 32160, 33737, 37636,
|
|
40575, 35542, 22751, 24324, 31840, 32894, 29282, 30922,
|
|
36034, 38647, 22744, 23650, 27155, 28122, 28431, 32047,
|
|
32311, 38475, 21202, 32907, 20956, 20940, 31260, 32190,
|
|
33777, 38517, 35712, 25295, 27138, 35582, 20025, 23527,
|
|
24594, 29575, 30064, 21271, 30971, 20415, 24489, 19981,
|
|
27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498,
|
|
27578, 36784, 27784, 25342, 33509, 25504, 30053, 20142,
|
|
20841, 20937, 26753, 31975, 33391, 35538, 37327, 21237,
|
|
21570, 22899, 24300, 26053, 28670, 31018, 38317, 39530,
|
|
40599, 40654, 21147, 26310, 27511, 36706, 24180, 24976,
|
|
25088, 25754, 28451, 29001, 29833, 31178, 32244, 32879,
|
|
36646, 34030, 36899, 37706, 21015, 21155, 21693, 28872,
|
|
35010, 35498, 24265, 24565, 25467, 27566, 31806, 29557,
|
|
20196, 22265, 23527, 23994, 24604, 29618, 29801, 32666,
|
|
32838, 37428, 38646, 38728, 38936, 20363, 31150, 37300,
|
|
38584, 24801, 20102, 20698, 23534, 23615, 26009, 27138,
|
|
29134, 30274, 34044, 36988, 40845, 26248, 38446, 21129,
|
|
26491, 26611, 27969, 28316, 29705, 30041, 30827, 32016,
|
|
39006, 20845, 25134, 38520, 20523, 23833, 28138, 36650,
|
|
24459, 24900, 26647, 29575, 38534, 21033, 21519, 23653,
|
|
26131, 26446, 26792, 27877, 29702, 30178, 32633, 35023,
|
|
35041, 37324, 38626, 21311, 28346, 21533, 29136, 29848,
|
|
34298, 38563, 40023, 40607, 26519, 28107, 33256, 31435,
|
|
31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050,
|
|
20999, 24230, 25299, 31958, 23429, 27934, 26292, 36667,
|
|
34892, 38477, 35211, 24275, 20800, 21952,
|
|
];
|
|
for (ix=0; ix<270; ix++) {
|
|
val = ls[ix];
|
|
map[ix+63744] = val;
|
|
}
|
|
ls = [
|
|
20398, 20711, 20813, 21193, 21220, 21329, 21917, 22022,
|
|
22120, 22592, 22696, 23652, 23662, 24724, 24936, 24974,
|
|
25074, 25935, 26082, 26257, 26757, 28023, 28186, 28450,
|
|
29038, 29227, 29730, 30865, 31038, 31049, 31048, 31056,
|
|
31062, 31069, 31117, 31118, 31296, 31361, 31680, 32244,
|
|
32265, 32321, 32626, 32773, 33261, 33401, 33401, 33879,
|
|
35088, 35222, 35585, 35641, 36051, 36104, 36790, 36920,
|
|
38627, 38911, 38971,
|
|
];
|
|
for (ix=0; ix<59; ix++) {
|
|
val = ls[ix];
|
|
map[ix+64048] = val;
|
|
}
|
|
ls = [
|
|
20029, 20024, 20033, 131362, 20320, 20398, 20411, 20482,
|
|
20602, 20633, 20711, 20687, 13470, 132666, 20813, 20820,
|
|
20836, 20855, 132380, 13497, 20839, 20877, 132427, 20887,
|
|
20900, 20172, 20908, 20917, 168415, 20981, 20995, 13535,
|
|
21051, 21062, 21106, 21111, 13589, 21191, 21193, 21220,
|
|
21242, 21253, 21254, 21271, 21321, 21329, 21338, 21363,
|
|
21373, 21375, 21375, 21375, 133676, 28784, 21450, 21471,
|
|
133987, 21483, 21489, 21510, 21662, 21560, 21576, 21608,
|
|
21666, 21750, 21776, 21843, 21859, 21892, 21892, 21913,
|
|
21931, 21939, 21954, 22294, 22022, 22295, 22097, 22132,
|
|
20999, 22766, 22478, 22516, 22541, 22411, 22578, 22577,
|
|
22700, 136420, 22770, 22775, 22790, 22810, 22818, 22882,
|
|
136872, 136938, 23020, 23067, 23079, 23000, 23142, 14062,
|
|
14076, 23304, 23358, 23358, 137672, 23491, 23512, 23527,
|
|
23539, 138008, 23551, 23558, 24403, 23586, 14209, 23648,
|
|
23662, 23744, 23693, 138724, 23875, 138726, 23918, 23915,
|
|
23932, 24033, 24034, 14383, 24061, 24104, 24125, 24169,
|
|
14434, 139651, 14460, 24240, 24243, 24246, 24266, 172946,
|
|
24318, 140081, 140081, 33281, 24354, 24354, 14535, 144056,
|
|
156122, 24418, 24427, 14563, 24474, 24525, 24535, 24569,
|
|
24705, 14650, 14620, 24724, 141012, 24775, 24904, 24908,
|
|
24910, 24908, 24954, 24974, 25010, 24996, 25007, 25054,
|
|
25074, 25078, 25104, 25115, 25181, 25265, 25300, 25424,
|
|
142092, 25405, 25340, 25448, 25475, 25572, 142321, 25634,
|
|
25541, 25513, 14894, 25705, 25726, 25757, 25719, 14956,
|
|
25935, 25964, 143370, 26083, 26360, 26185, 15129, 26257,
|
|
15112, 15076, 20882, 20885, 26368, 26268, 32941, 17369,
|
|
26391, 26395, 26401, 26462, 26451, 144323, 15177, 26618,
|
|
26501, 26706, 26757, 144493, 26766, 26655, 26900, 15261,
|
|
26946, 27043, 27114, 27304, 145059, 27355, 15384, 27425,
|
|
145575, 27476, 15438, 27506, 27551, 27578, 27579, 146061,
|
|
138507, 146170, 27726, 146620, 27839, 27853, 27751, 27926,
|
|
27966, 28023, 27969, 28009, 28024, 28037, 146718, 27956,
|
|
28207, 28270, 15667, 28363, 28359, 147153, 28153, 28526,
|
|
147294, 147342, 28614, 28729, 28702, 28699, 15766, 28746,
|
|
28797, 28791, 28845, 132389, 28997, 148067, 29084, 148395,
|
|
29224, 29237, 29264, 149000, 29312, 29333, 149301, 149524,
|
|
29562, 29579, 16044, 29605, 16056, 16056, 29767, 29788,
|
|
29809, 29829, 29898, 16155, 29988, 150582, 30014, 150674,
|
|
30064, 139679, 30224, 151457, 151480, 151620, 16380, 16392,
|
|
30452, 151795, 151794, 151833, 151859, 30494, 30495, 30495,
|
|
30538, 16441, 30603, 16454, 16534, 152605, 30798, 30860,
|
|
30924, 16611, 153126, 31062, 153242, 153285, 31119, 31211,
|
|
16687, 31296, 31306, 31311, 153980, 154279, 154279, 31470,
|
|
16898, 154539, 31686, 31689, 16935, 154752, 31954, 17056,
|
|
31976, 31971, 32000, 155526, 32099, 17153, 32199, 32258,
|
|
32325, 17204, 156200, 156231, 17241, 156377, 32634, 156478,
|
|
32661, 32762, 32773, 156890, 156963, 32864, 157096, 32880,
|
|
144223, 17365, 32946, 33027, 17419, 33086, 23221, 157607,
|
|
157621, 144275, 144284, 33281, 33284, 36766, 17515, 33425,
|
|
33419, 33437, 21171, 33457, 33459, 33469, 33510, 158524,
|
|
33509, 33565, 33635, 33709, 33571, 33725, 33767, 33879,
|
|
33619, 33738, 33740, 33756, 158774, 159083, 158933, 17707,
|
|
34033, 34035, 34070, 160714, 34148, 159532, 17757, 17761,
|
|
159665, 159954, 17771, 34384, 34396, 34407, 34409, 34473,
|
|
34440, 34574, 34530, 34681, 34600, 34667, 34694, 17879,
|
|
34785, 34817, 17913, 34912, 34915, 161383, 35031, 35038,
|
|
17973, 35066, 13499, 161966, 162150, 18110, 18119, 35488,
|
|
35565, 35722, 35925, 162984, 36011, 36033, 36123, 36215,
|
|
163631, 133124, 36299, 36284, 36336, 133342, 36564, 36664,
|
|
165330, 165357, 37012, 37105, 37137, 165678, 37147, 37432,
|
|
37591, 37592, 37500, 37881, 37909, 166906, 38283, 18837,
|
|
38327, 167287, 18918, 38595, 23986, 38691, 168261, 168474,
|
|
19054, 19062, 38880, 168970, 19122, 169110, 38923, 38923,
|
|
38953, 169398, 39138, 19251, 39209, 39335, 39362, 39422,
|
|
19406, 170800, 39698, 40000, 40189, 19662, 19693, 40295,
|
|
172238, 19704, 172293, 172558, 172689, 40635, 19798, 40697,
|
|
40702, 40709, 40719, 40726, 40763, 173568,
|
|
];
|
|
for (ix=0; ix<542; ix++) {
|
|
val = ls[ix];
|
|
map[ix+194560] = val;
|
|
}
|
|
})();
|
|
|
|
/* list all the special cases in unicode_combin_table */
|
|
var unicode_combin_table = {
|
|
768: 230, 769: 230, 770: 230, 771: 230, 772: 230,
|
|
773: 230, 774: 230, 775: 230, 776: 230, 777: 230,
|
|
778: 230, 779: 230, 780: 230, 781: 230, 782: 230,
|
|
783: 230, 784: 230, 785: 230, 786: 230, 787: 230,
|
|
788: 230, 789: 232, 790: 220, 791: 220, 792: 220,
|
|
793: 220, 794: 232, 795: 216, 796: 220, 797: 220,
|
|
798: 220, 799: 220, 800: 220, 801: 202, 802: 202,
|
|
803: 220, 804: 220, 805: 220, 806: 220, 807: 202,
|
|
808: 202, 809: 220, 810: 220, 811: 220, 812: 220,
|
|
813: 220, 814: 220, 815: 220, 816: 220, 817: 220,
|
|
818: 220, 819: 220, 820: 1, 821: 1, 822: 1,
|
|
823: 1, 824: 1, 825: 220, 826: 220, 827: 220,
|
|
828: 220, 829: 230, 830: 230, 831: 230, 832: 230,
|
|
833: 230, 834: 230, 835: 230, 836: 230, 837: 240,
|
|
838: 230, 839: 220, 840: 220, 841: 220, 842: 230,
|
|
843: 230, 844: 230, 845: 220, 846: 220, 848: 230,
|
|
849: 230, 850: 230, 851: 220, 852: 220, 853: 220,
|
|
854: 220, 855: 230, 861: 234, 862: 234, 863: 233,
|
|
864: 234, 865: 234, 866: 233, 867: 230, 868: 230,
|
|
869: 230, 870: 230, 871: 230, 872: 230, 873: 230,
|
|
874: 230, 875: 230, 876: 230, 877: 230, 878: 230,
|
|
879: 230, 1155: 230, 1156: 230, 1157: 230, 1158: 230,
|
|
1425: 220, 1426: 230, 1427: 230, 1428: 230, 1429: 230,
|
|
1430: 220, 1431: 230, 1432: 230, 1433: 230, 1434: 222,
|
|
1435: 220, 1436: 230, 1437: 230, 1438: 230, 1439: 230,
|
|
1440: 230, 1441: 230, 1443: 220, 1444: 220, 1445: 220,
|
|
1446: 220, 1447: 220, 1448: 230, 1449: 230, 1450: 220,
|
|
1451: 230, 1452: 230, 1453: 222, 1454: 228, 1455: 230,
|
|
1456: 10, 1457: 11, 1458: 12, 1459: 13, 1460: 14,
|
|
1461: 15, 1462: 16, 1463: 17, 1464: 18, 1465: 19,
|
|
1467: 20, 1468: 21, 1469: 22, 1471: 23, 1473: 24,
|
|
1474: 25, 1476: 230, 1552: 230, 1553: 230, 1554: 230,
|
|
1555: 230, 1556: 230, 1557: 230, 1611: 27, 1612: 28,
|
|
1613: 29, 1614: 30, 1615: 31, 1616: 32, 1617: 33,
|
|
1618: 34, 1619: 230, 1620: 230, 1621: 220, 1622: 220,
|
|
1623: 230, 1624: 230, 1648: 35, 1750: 230, 1751: 230,
|
|
1752: 230, 1753: 230, 1754: 230, 1755: 230, 1756: 230,
|
|
1759: 230, 1760: 230, 1761: 230, 1762: 230, 1763: 220,
|
|
1764: 230, 1767: 230, 1768: 230, 1770: 220, 1771: 230,
|
|
1772: 230, 1773: 220, 1809: 36, 1840: 230, 1841: 220,
|
|
1842: 230, 1843: 230, 1844: 220, 1845: 230, 1846: 230,
|
|
1847: 220, 1848: 220, 1849: 220, 1850: 230, 1851: 220,
|
|
1852: 220, 1853: 230, 1854: 220, 1855: 230, 1856: 230,
|
|
1857: 230, 1858: 220, 1859: 230, 1860: 220, 1861: 230,
|
|
1862: 220, 1863: 230, 1864: 220, 1865: 230, 1866: 230,
|
|
2364: 7, 2381: 9, 2385: 230, 2386: 220, 2387: 230,
|
|
2388: 230, 2492: 7, 2509: 9, 2620: 7, 2637: 9,
|
|
2748: 7, 2765: 9, 2876: 7, 2893: 9, 3021: 9,
|
|
3149: 9, 3157: 84, 3158: 91, 3260: 7, 3277: 9,
|
|
3405: 9, 3530: 9, 3640: 103, 3641: 103, 3642: 9,
|
|
3656: 107, 3657: 107, 3658: 107, 3659: 107, 3768: 118,
|
|
3769: 118, 3784: 122, 3785: 122, 3786: 122, 3787: 122,
|
|
3864: 220, 3865: 220, 3893: 220, 3895: 220, 3897: 216,
|
|
3953: 129, 3954: 130, 3956: 132, 3962: 130, 3963: 130,
|
|
3964: 130, 3965: 130, 3968: 130, 3970: 230, 3971: 230,
|
|
3972: 9, 3974: 230, 3975: 230, 4038: 220, 4151: 7,
|
|
4153: 9, 5908: 9, 5940: 9, 6098: 9, 6109: 230,
|
|
6313: 228, 6457: 222, 6458: 230, 6459: 220, 8400: 230,
|
|
8401: 230, 8402: 1, 8403: 1, 8404: 230, 8405: 230,
|
|
8406: 230, 8407: 230, 8408: 1, 8409: 1, 8410: 1,
|
|
8411: 230, 8412: 230, 8417: 230, 8421: 1, 8422: 1,
|
|
8423: 230, 8424: 220, 8425: 230, 8426: 1, 12330: 218,
|
|
12331: 228, 12332: 232, 12333: 222, 12334: 224, 12335: 224,
|
|
12441: 8, 12442: 8, 64286: 26, 65056: 230, 65057: 230,
|
|
65058: 230, 65059: 230, 119141: 216, 119142: 216, 119143: 1,
|
|
119144: 1, 119145: 1, 119149: 226, 119150: 216, 119151: 216,
|
|
119152: 216, 119153: 216, 119154: 216, 119163: 220, 119164: 220,
|
|
119165: 220, 119166: 220, 119167: 220, 119168: 220, 119169: 220,
|
|
119170: 220, 119173: 230, 119174: 230, 119175: 230, 119176: 230,
|
|
119177: 230, 119178: 220, 119179: 220, 119210: 230, 119211: 230,
|
|
119212: 230, 119213: 230
|
|
};
|
|
|
|
/* list all of unicode_compo_table */
|
|
var unicode_compo_table = {
|
|
60: { 824:8814 },
|
|
61: { 824:8800 },
|
|
62: { 824:8815 },
|
|
65: { 768:192, 769:193, 770:194, 771:195, 772:256, 774:258, 775:550, 776:196, 777:7842, 778:197, 780:461, 783:512, 785:514, 803:7840, 805:7680, 808:260 },
|
|
66: { 775:7682, 803:7684, 817:7686 },
|
|
67: { 769:262, 770:264, 775:266, 780:268, 807:199 },
|
|
68: { 775:7690, 780:270, 803:7692, 807:7696, 813:7698, 817:7694 },
|
|
69: { 768:200, 769:201, 770:202, 771:7868, 772:274, 774:276, 775:278, 776:203, 777:7866, 780:282, 783:516, 785:518, 803:7864, 807:552, 808:280, 813:7704, 816:7706 },
|
|
70: { 775:7710 },
|
|
71: { 769:500, 770:284, 772:7712, 774:286, 775:288, 780:486, 807:290 },
|
|
72: { 770:292, 775:7714, 776:7718, 780:542, 803:7716, 807:7720, 814:7722 },
|
|
73: { 768:204, 769:205, 770:206, 771:296, 772:298, 774:300, 775:304, 776:207, 777:7880, 780:463, 783:520, 785:522, 803:7882, 808:302, 816:7724 },
|
|
74: { 770:308 },
|
|
75: { 769:7728, 780:488, 803:7730, 807:310, 817:7732 },
|
|
76: { 769:313, 780:317, 803:7734, 807:315, 813:7740, 817:7738 },
|
|
77: { 769:7742, 775:7744, 803:7746 },
|
|
78: { 768:504, 769:323, 771:209, 775:7748, 780:327, 803:7750, 807:325, 813:7754, 817:7752 },
|
|
79: { 768:210, 769:211, 770:212, 771:213, 772:332, 774:334, 775:558, 776:214, 777:7886, 779:336, 780:465, 783:524, 785:526, 795:416, 803:7884, 808:490 },
|
|
80: { 769:7764, 775:7766 },
|
|
82: { 769:340, 775:7768, 780:344, 783:528, 785:530, 803:7770, 807:342, 817:7774 },
|
|
83: { 769:346, 770:348, 775:7776, 780:352, 803:7778, 806:536, 807:350 },
|
|
84: { 775:7786, 780:356, 803:7788, 806:538, 807:354, 813:7792, 817:7790 },
|
|
85: { 768:217, 769:218, 770:219, 771:360, 772:362, 774:364, 776:220, 777:7910, 778:366, 779:368, 780:467, 783:532, 785:534, 795:431, 803:7908, 804:7794, 808:370, 813:7798, 816:7796 },
|
|
86: { 771:7804, 803:7806 },
|
|
87: { 768:7808, 769:7810, 770:372, 775:7814, 776:7812, 803:7816 },
|
|
88: { 775:7818, 776:7820 },
|
|
89: { 768:7922, 769:221, 770:374, 771:7928, 772:562, 775:7822, 776:376, 777:7926, 803:7924 },
|
|
90: { 769:377, 770:7824, 775:379, 780:381, 803:7826, 817:7828 },
|
|
97: { 768:224, 769:225, 770:226, 771:227, 772:257, 774:259, 775:551, 776:228, 777:7843, 778:229, 780:462, 783:513, 785:515, 803:7841, 805:7681, 808:261 },
|
|
98: { 775:7683, 803:7685, 817:7687 },
|
|
99: { 769:263, 770:265, 775:267, 780:269, 807:231 },
|
|
100: { 775:7691, 780:271, 803:7693, 807:7697, 813:7699, 817:7695 },
|
|
101: { 768:232, 769:233, 770:234, 771:7869, 772:275, 774:277, 775:279, 776:235, 777:7867, 780:283, 783:517, 785:519, 803:7865, 807:553, 808:281, 813:7705, 816:7707 },
|
|
102: { 775:7711 },
|
|
103: { 769:501, 770:285, 772:7713, 774:287, 775:289, 780:487, 807:291 },
|
|
104: { 770:293, 775:7715, 776:7719, 780:543, 803:7717, 807:7721, 814:7723, 817:7830 },
|
|
105: { 768:236, 769:237, 770:238, 771:297, 772:299, 774:301, 776:239, 777:7881, 780:464, 783:521, 785:523, 803:7883, 808:303, 816:7725 },
|
|
106: { 770:309, 780:496 },
|
|
107: { 769:7729, 780:489, 803:7731, 807:311, 817:7733 },
|
|
108: { 769:314, 780:318, 803:7735, 807:316, 813:7741, 817:7739 },
|
|
109: { 769:7743, 775:7745, 803:7747 },
|
|
110: { 768:505, 769:324, 771:241, 775:7749, 780:328, 803:7751, 807:326, 813:7755, 817:7753 },
|
|
111: { 768:242, 769:243, 770:244, 771:245, 772:333, 774:335, 775:559, 776:246, 777:7887, 779:337, 780:466, 783:525, 785:527, 795:417, 803:7885, 808:491 },
|
|
112: { 769:7765, 775:7767 },
|
|
114: { 769:341, 775:7769, 780:345, 783:529, 785:531, 803:7771, 807:343, 817:7775 },
|
|
115: { 769:347, 770:349, 775:7777, 780:353, 803:7779, 806:537, 807:351 },
|
|
116: { 775:7787, 776:7831, 780:357, 803:7789, 806:539, 807:355, 813:7793, 817:7791 },
|
|
117: { 768:249, 769:250, 770:251, 771:361, 772:363, 774:365, 776:252, 777:7911, 778:367, 779:369, 780:468, 783:533, 785:535, 795:432, 803:7909, 804:7795, 808:371, 813:7799, 816:7797 },
|
|
118: { 771:7805, 803:7807 },
|
|
119: { 768:7809, 769:7811, 770:373, 775:7815, 776:7813, 778:7832, 803:7817 },
|
|
120: { 775:7819, 776:7821 },
|
|
121: { 768:7923, 769:253, 770:375, 771:7929, 772:563, 775:7823, 776:255, 777:7927, 778:7833, 803:7925 },
|
|
122: { 769:378, 770:7825, 775:380, 780:382, 803:7827, 817:7829 },
|
|
168: { 768:8173, 769:901, 834:8129 },
|
|
194: { 768:7846, 769:7844, 771:7850, 777:7848 },
|
|
196: { 772:478 },
|
|
197: { 769:506 },
|
|
198: { 769:508, 772:482 },
|
|
199: { 769:7688 },
|
|
202: { 768:7872, 769:7870, 771:7876, 777:7874 },
|
|
207: { 769:7726 },
|
|
212: { 768:7890, 769:7888, 771:7894, 777:7892 },
|
|
213: { 769:7756, 772:556, 776:7758 },
|
|
214: { 772:554 },
|
|
216: { 769:510 },
|
|
220: { 768:475, 769:471, 772:469, 780:473 },
|
|
226: { 768:7847, 769:7845, 771:7851, 777:7849 },
|
|
228: { 772:479 },
|
|
229: { 769:507 },
|
|
230: { 769:509, 772:483 },
|
|
231: { 769:7689 },
|
|
234: { 768:7873, 769:7871, 771:7877, 777:7875 },
|
|
239: { 769:7727 },
|
|
244: { 768:7891, 769:7889, 771:7895, 777:7893 },
|
|
245: { 769:7757, 772:557, 776:7759 },
|
|
246: { 772:555 },
|
|
248: { 769:511 },
|
|
252: { 768:476, 769:472, 772:470, 780:474 },
|
|
258: { 768:7856, 769:7854, 771:7860, 777:7858 },
|
|
259: { 768:7857, 769:7855, 771:7861, 777:7859 },
|
|
274: { 768:7700, 769:7702 },
|
|
275: { 768:7701, 769:7703 },
|
|
332: { 768:7760, 769:7762 },
|
|
333: { 768:7761, 769:7763 },
|
|
346: { 775:7780 },
|
|
347: { 775:7781 },
|
|
352: { 775:7782 },
|
|
353: { 775:7783 },
|
|
360: { 769:7800 },
|
|
361: { 769:7801 },
|
|
362: { 776:7802 },
|
|
363: { 776:7803 },
|
|
383: { 775:7835 },
|
|
416: { 768:7900, 769:7898, 771:7904, 777:7902, 803:7906 },
|
|
417: { 768:7901, 769:7899, 771:7905, 777:7903, 803:7907 },
|
|
431: { 768:7914, 769:7912, 771:7918, 777:7916, 803:7920 },
|
|
432: { 768:7915, 769:7913, 771:7919, 777:7917, 803:7921 },
|
|
439: { 780:494 },
|
|
490: { 772:492 },
|
|
491: { 772:493 },
|
|
550: { 772:480 },
|
|
551: { 772:481 },
|
|
552: { 774:7708 },
|
|
553: { 774:7709 },
|
|
558: { 772:560 },
|
|
559: { 772:561 },
|
|
658: { 780:495 },
|
|
776: { 769:836 },
|
|
913: { 768:8122, 769:902, 772:8121, 774:8120, 787:7944, 788:7945, 837:8124 },
|
|
917: { 768:8136, 769:904, 787:7960, 788:7961 },
|
|
919: { 768:8138, 769:905, 787:7976, 788:7977, 837:8140 },
|
|
921: { 768:8154, 769:906, 772:8153, 774:8152, 776:938, 787:7992, 788:7993 },
|
|
927: { 768:8184, 769:908, 787:8008, 788:8009 },
|
|
929: { 788:8172 },
|
|
933: { 768:8170, 769:910, 772:8169, 774:8168, 776:939, 788:8025 },
|
|
937: { 768:8186, 769:911, 787:8040, 788:8041, 837:8188 },
|
|
940: { 837:8116 },
|
|
942: { 837:8132 },
|
|
945: { 768:8048, 769:940, 772:8113, 774:8112, 787:7936, 788:7937, 834:8118, 837:8115 },
|
|
949: { 768:8050, 769:941, 787:7952, 788:7953 },
|
|
951: { 768:8052, 769:942, 787:7968, 788:7969, 834:8134, 837:8131 },
|
|
953: { 768:8054, 769:943, 772:8145, 774:8144, 776:970, 787:7984, 788:7985, 834:8150 },
|
|
959: { 768:8056, 769:972, 787:8000, 788:8001 },
|
|
961: { 787:8164, 788:8165 },
|
|
965: { 768:8058, 769:973, 772:8161, 774:8160, 776:971, 787:8016, 788:8017, 834:8166 },
|
|
969: { 768:8060, 769:974, 787:8032, 788:8033, 834:8182, 837:8179 },
|
|
970: { 768:8146, 769:912, 834:8151 },
|
|
971: { 768:8162, 769:944, 834:8167 },
|
|
974: { 837:8180 },
|
|
978: { 769:979, 776:980 },
|
|
1030: { 776:1031 },
|
|
1040: { 774:1232, 776:1234 },
|
|
1043: { 769:1027 },
|
|
1045: { 768:1024, 774:1238, 776:1025 },
|
|
1046: { 774:1217, 776:1244 },
|
|
1047: { 776:1246 },
|
|
1048: { 768:1037, 772:1250, 774:1049, 776:1252 },
|
|
1050: { 769:1036 },
|
|
1054: { 776:1254 },
|
|
1059: { 772:1262, 774:1038, 776:1264, 779:1266 },
|
|
1063: { 776:1268 },
|
|
1067: { 776:1272 },
|
|
1069: { 776:1260 },
|
|
1072: { 774:1233, 776:1235 },
|
|
1075: { 769:1107 },
|
|
1077: { 768:1104, 774:1239, 776:1105 },
|
|
1078: { 774:1218, 776:1245 },
|
|
1079: { 776:1247 },
|
|
1080: { 768:1117, 772:1251, 774:1081, 776:1253 },
|
|
1082: { 769:1116 },
|
|
1086: { 776:1255 },
|
|
1091: { 772:1263, 774:1118, 776:1265, 779:1267 },
|
|
1095: { 776:1269 },
|
|
1099: { 776:1273 },
|
|
1101: { 776:1261 },
|
|
1110: { 776:1111 },
|
|
1140: { 783:1142 },
|
|
1141: { 783:1143 },
|
|
1240: { 776:1242 },
|
|
1241: { 776:1243 },
|
|
1256: { 776:1258 },
|
|
1257: { 776:1259 },
|
|
1488: { 1463:64302, 1464:64303, 1468:64304 },
|
|
1489: { 1468:64305, 1471:64332 },
|
|
1490: { 1468:64306 },
|
|
1491: { 1468:64307 },
|
|
1492: { 1468:64308 },
|
|
1493: { 1465:64331, 1468:64309 },
|
|
1494: { 1468:64310 },
|
|
1496: { 1468:64312 },
|
|
1497: { 1460:64285, 1468:64313 },
|
|
1498: { 1468:64314 },
|
|
1499: { 1468:64315, 1471:64333 },
|
|
1500: { 1468:64316 },
|
|
1502: { 1468:64318 },
|
|
1504: { 1468:64320 },
|
|
1505: { 1468:64321 },
|
|
1507: { 1468:64323 },
|
|
1508: { 1468:64324, 1471:64334 },
|
|
1510: { 1468:64326 },
|
|
1511: { 1468:64327 },
|
|
1512: { 1468:64328 },
|
|
1513: { 1468:64329, 1473:64298, 1474:64299 },
|
|
1514: { 1468:64330 },
|
|
1522: { 1463:64287 },
|
|
1575: { 1619:1570, 1620:1571, 1621:1573 },
|
|
1608: { 1620:1572 },
|
|
1610: { 1620:1574 },
|
|
1729: { 1620:1730 },
|
|
1746: { 1620:1747 },
|
|
1749: { 1620:1728 },
|
|
2325: { 2364:2392 },
|
|
2326: { 2364:2393 },
|
|
2327: { 2364:2394 },
|
|
2332: { 2364:2395 },
|
|
2337: { 2364:2396 },
|
|
2338: { 2364:2397 },
|
|
2344: { 2364:2345 },
|
|
2347: { 2364:2398 },
|
|
2351: { 2364:2399 },
|
|
2352: { 2364:2353 },
|
|
2355: { 2364:2356 },
|
|
2465: { 2492:2524 },
|
|
2466: { 2492:2525 },
|
|
2479: { 2492:2527 },
|
|
2503: { 2494:2507, 2519:2508 },
|
|
2582: { 2620:2649 },
|
|
2583: { 2620:2650 },
|
|
2588: { 2620:2651 },
|
|
2603: { 2620:2654 },
|
|
2610: { 2620:2611 },
|
|
2616: { 2620:2614 },
|
|
2849: { 2876:2908 },
|
|
2850: { 2876:2909 },
|
|
2887: { 2878:2891, 2902:2888, 2903:2892 },
|
|
2962: { 3031:2964 },
|
|
3014: { 3006:3018, 3031:3020 },
|
|
3015: { 3006:3019 },
|
|
3142: { 3158:3144 },
|
|
3263: { 3285:3264 },
|
|
3270: { 3266:3274, 3285:3271, 3286:3272 },
|
|
3274: { 3285:3275 },
|
|
3398: { 3390:3402, 3415:3404 },
|
|
3399: { 3390:3403 },
|
|
3545: { 3530:3546, 3535:3548, 3551:3550 },
|
|
3548: { 3530:3549 },
|
|
3904: { 4021:3945 },
|
|
3906: { 4023:3907 },
|
|
3916: { 4023:3917 },
|
|
3921: { 4023:3922 },
|
|
3926: { 4023:3927 },
|
|
3931: { 4023:3932 },
|
|
3953: { 3954:3955, 3956:3957, 3968:3969 },
|
|
3984: { 4021:4025 },
|
|
3986: { 4023:3987 },
|
|
3996: { 4023:3997 },
|
|
4001: { 4023:4002 },
|
|
4006: { 4023:4007 },
|
|
4011: { 4023:4012 },
|
|
4018: { 3968:3958 },
|
|
4019: { 3968:3960 },
|
|
4133: { 4142:4134 },
|
|
7734: { 772:7736 },
|
|
7735: { 772:7737 },
|
|
7770: { 772:7772 },
|
|
7771: { 772:7773 },
|
|
7778: { 775:7784 },
|
|
7779: { 775:7785 },
|
|
7840: { 770:7852, 774:7862 },
|
|
7841: { 770:7853, 774:7863 },
|
|
7864: { 770:7878 },
|
|
7865: { 770:7879 },
|
|
7884: { 770:7896 },
|
|
7885: { 770:7897 },
|
|
7936: { 768:7938, 769:7940, 834:7942, 837:8064 },
|
|
7937: { 768:7939, 769:7941, 834:7943, 837:8065 },
|
|
7938: { 837:8066 },
|
|
7939: { 837:8067 },
|
|
7940: { 837:8068 },
|
|
7941: { 837:8069 },
|
|
7942: { 837:8070 },
|
|
7943: { 837:8071 },
|
|
7944: { 768:7946, 769:7948, 834:7950, 837:8072 },
|
|
7945: { 768:7947, 769:7949, 834:7951, 837:8073 },
|
|
7946: { 837:8074 },
|
|
7947: { 837:8075 },
|
|
7948: { 837:8076 },
|
|
7949: { 837:8077 },
|
|
7950: { 837:8078 },
|
|
7951: { 837:8079 },
|
|
7952: { 768:7954, 769:7956 },
|
|
7953: { 768:7955, 769:7957 },
|
|
7960: { 768:7962, 769:7964 },
|
|
7961: { 768:7963, 769:7965 },
|
|
7968: { 768:7970, 769:7972, 834:7974, 837:8080 },
|
|
7969: { 768:7971, 769:7973, 834:7975, 837:8081 },
|
|
7970: { 837:8082 },
|
|
7971: { 837:8083 },
|
|
7972: { 837:8084 },
|
|
7973: { 837:8085 },
|
|
7974: { 837:8086 },
|
|
7975: { 837:8087 },
|
|
7976: { 768:7978, 769:7980, 834:7982, 837:8088 },
|
|
7977: { 768:7979, 769:7981, 834:7983, 837:8089 },
|
|
7978: { 837:8090 },
|
|
7979: { 837:8091 },
|
|
7980: { 837:8092 },
|
|
7981: { 837:8093 },
|
|
7982: { 837:8094 },
|
|
7983: { 837:8095 },
|
|
7984: { 768:7986, 769:7988, 834:7990 },
|
|
7985: { 768:7987, 769:7989, 834:7991 },
|
|
7992: { 768:7994, 769:7996, 834:7998 },
|
|
7993: { 768:7995, 769:7997, 834:7999 },
|
|
8000: { 768:8002, 769:8004 },
|
|
8001: { 768:8003, 769:8005 },
|
|
8008: { 768:8010, 769:8012 },
|
|
8009: { 768:8011, 769:8013 },
|
|
8016: { 768:8018, 769:8020, 834:8022 },
|
|
8017: { 768:8019, 769:8021, 834:8023 },
|
|
8025: { 768:8027, 769:8029, 834:8031 },
|
|
8032: { 768:8034, 769:8036, 834:8038, 837:8096 },
|
|
8033: { 768:8035, 769:8037, 834:8039, 837:8097 },
|
|
8034: { 837:8098 },
|
|
8035: { 837:8099 },
|
|
8036: { 837:8100 },
|
|
8037: { 837:8101 },
|
|
8038: { 837:8102 },
|
|
8039: { 837:8103 },
|
|
8040: { 768:8042, 769:8044, 834:8046, 837:8104 },
|
|
8041: { 768:8043, 769:8045, 834:8047, 837:8105 },
|
|
8042: { 837:8106 },
|
|
8043: { 837:8107 },
|
|
8044: { 837:8108 },
|
|
8045: { 837:8109 },
|
|
8046: { 837:8110 },
|
|
8047: { 837:8111 },
|
|
8048: { 837:8114 },
|
|
8052: { 837:8130 },
|
|
8060: { 837:8178 },
|
|
8118: { 837:8119 },
|
|
8127: { 768:8141, 769:8142, 834:8143 },
|
|
8134: { 837:8135 },
|
|
8182: { 837:8183 },
|
|
8190: { 768:8157, 769:8158, 834:8159 },
|
|
8592: { 824:8602 },
|
|
8594: { 824:8603 },
|
|
8596: { 824:8622 },
|
|
8656: { 824:8653 },
|
|
8658: { 824:8655 },
|
|
8660: { 824:8654 },
|
|
8707: { 824:8708 },
|
|
8712: { 824:8713 },
|
|
8715: { 824:8716 },
|
|
8739: { 824:8740 },
|
|
8741: { 824:8742 },
|
|
8764: { 824:8769 },
|
|
8771: { 824:8772 },
|
|
8773: { 824:8775 },
|
|
8776: { 824:8777 },
|
|
8781: { 824:8813 },
|
|
8801: { 824:8802 },
|
|
8804: { 824:8816 },
|
|
8805: { 824:8817 },
|
|
8818: { 824:8820 },
|
|
8819: { 824:8821 },
|
|
8822: { 824:8824 },
|
|
8823: { 824:8825 },
|
|
8826: { 824:8832 },
|
|
8827: { 824:8833 },
|
|
8828: { 824:8928 },
|
|
8829: { 824:8929 },
|
|
8834: { 824:8836 },
|
|
8835: { 824:8837 },
|
|
8838: { 824:8840 },
|
|
8839: { 824:8841 },
|
|
8849: { 824:8930 },
|
|
8850: { 824:8931 },
|
|
8866: { 824:8876 },
|
|
8872: { 824:8877 },
|
|
8873: { 824:8878 },
|
|
8875: { 824:8879 },
|
|
8882: { 824:8938 },
|
|
8883: { 824:8939 },
|
|
8884: { 824:8940 },
|
|
8885: { 824:8941 },
|
|
10973: { 824:10972 },
|
|
12358: { 12441:12436 },
|
|
12363: { 12441:12364 },
|
|
12365: { 12441:12366 },
|
|
12367: { 12441:12368 },
|
|
12369: { 12441:12370 },
|
|
12371: { 12441:12372 },
|
|
12373: { 12441:12374 },
|
|
12375: { 12441:12376 },
|
|
12377: { 12441:12378 },
|
|
12379: { 12441:12380 },
|
|
12381: { 12441:12382 },
|
|
12383: { 12441:12384 },
|
|
12385: { 12441:12386 },
|
|
12388: { 12441:12389 },
|
|
12390: { 12441:12391 },
|
|
12392: { 12441:12393 },
|
|
12399: { 12441:12400, 12442:12401 },
|
|
12402: { 12441:12403, 12442:12404 },
|
|
12405: { 12441:12406, 12442:12407 },
|
|
12408: { 12441:12409, 12442:12410 },
|
|
12411: { 12441:12412, 12442:12413 },
|
|
12445: { 12441:12446 },
|
|
12454: { 12441:12532 },
|
|
12459: { 12441:12460 },
|
|
12461: { 12441:12462 },
|
|
12463: { 12441:12464 },
|
|
12465: { 12441:12466 },
|
|
12467: { 12441:12468 },
|
|
12469: { 12441:12470 },
|
|
12471: { 12441:12472 },
|
|
12473: { 12441:12474 },
|
|
12475: { 12441:12476 },
|
|
12477: { 12441:12478 },
|
|
12479: { 12441:12480 },
|
|
12481: { 12441:12482 },
|
|
12484: { 12441:12485 },
|
|
12486: { 12441:12487 },
|
|
12488: { 12441:12489 },
|
|
12495: { 12441:12496, 12442:12497 },
|
|
12498: { 12441:12499, 12442:12500 },
|
|
12501: { 12441:12502, 12442:12503 },
|
|
12504: { 12441:12505, 12442:12506 },
|
|
12507: { 12441:12508, 12442:12509 },
|
|
12527: { 12441:12535 },
|
|
12528: { 12441:12536 },
|
|
12529: { 12441:12537 },
|
|
12530: { 12441:12538 },
|
|
12541: { 12441:12542 },
|
|
64329: { 1473:64300, 1474:64301 },
|
|
119127: { 119141:119134 },
|
|
119128: { 119141:119135 },
|
|
119135: { 119150:119136, 119151:119137, 119152:119138, 119153:119139, 119154:119140 },
|
|
119225: { 119141:119227 },
|
|
119226: { 119141:119228 },
|
|
119227: { 119150:119229, 119151:119231 },
|
|
119228: { 119150:119230, 119151:119232 }
|
|
};
|
|
/* End of tables generated by casemap.py. */
|
|
|
|
|
|
/* Convert a 32-bit Unicode value to a JS string. */
|
|
function CharToString(val) {
|
|
if (val < 0x10000) {
|
|
return String.fromCharCode(val);
|
|
}
|
|
else {
|
|
val -= 0x10000;
|
|
return String.fromCharCode(0xD800 + (val >> 10), 0xDC00 + (val & 0x3FF));
|
|
}
|
|
}
|
|
|
|
/* Given an array, return an array of the same length with all the values
|
|
trimmed to the range 0-255. This may be the same array. */
|
|
function TrimArrayToBytes(arr) {
|
|
var ix, newarr;
|
|
var len = arr.length;
|
|
for (ix=0; ix<len; ix++) {
|
|
if (arr[ix] < 0 || arr[ix] >= 0x100)
|
|
break;
|
|
}
|
|
if (ix == len) {
|
|
return arr;
|
|
}
|
|
newarr = Array(len);
|
|
for (ix=0; ix<len; ix++) {
|
|
if (arr[ix] < 0 || arr[ix] >= 0x100)
|
|
newarr[ix] = 63; // '?'
|
|
else
|
|
newarr[ix] = arr[ix];
|
|
}
|
|
return newarr;
|
|
}
|
|
|
|
/* Convert an array of 8-bit values to a JS string, trimming if
|
|
necessary. */
|
|
function ByteArrayToString(arr) {
|
|
var ix, newarr;
|
|
var len = arr.length;
|
|
if (len == 0)
|
|
return '';
|
|
for (ix=0; ix<len; ix++) {
|
|
if (arr[ix] < 0 || arr[ix] >= 0x100)
|
|
break;
|
|
}
|
|
if (ix == len) {
|
|
return String.fromCharCode.apply(this, arr);
|
|
}
|
|
newarr = Array(len);
|
|
for (ix=0; ix<len; ix++) {
|
|
newarr[ix] = String.fromCharCode(arr[ix] & 0xFF);
|
|
}
|
|
return newarr.join('');
|
|
}
|
|
|
|
/* Convert an array of 32-bit Unicode values to a JS string. If they're
|
|
all in the 16-bit range, this is easy; otherwise we have to do
|
|
some munging. */
|
|
function UniArrayToString(arr) {
|
|
var ix, val, newarr;
|
|
var len = arr.length;
|
|
if (len == 0)
|
|
return '';
|
|
for (ix=0; ix<len; ix++) {
|
|
if (arr[ix] >= 0x10000)
|
|
break;
|
|
}
|
|
if (ix == len) {
|
|
return String.fromCharCode.apply(this, arr);
|
|
}
|
|
newarr = Array(len);
|
|
for (ix=0; ix<len; ix++) {
|
|
val = arr[ix];
|
|
if (val < 0x10000) {
|
|
newarr[ix] = String.fromCharCode(val);
|
|
}
|
|
else {
|
|
val -= 0x10000;
|
|
newarr[ix] = String.fromCharCode(0xD800 + (val >> 10), 0xDC00 + (val & 0x3FF));
|
|
}
|
|
}
|
|
return newarr.join('');
|
|
}
|
|
|
|
/* Convert an array of 32-bit Unicode values to an array of 8-bit byte
|
|
values, encoded UTF-8. If all the values are 0-127, this returns the
|
|
same array. Otherwise it returns a new (longer) array. */
|
|
function UniArrayToUTF8(arr) {
|
|
var count = 0;
|
|
|
|
for (var ix=0; ix<arr.length; ix++) {
|
|
var val = arr[ix];
|
|
if (val < 0x80) {
|
|
count += 1;
|
|
}
|
|
else if (val < 0x800) {
|
|
count += 2;
|
|
}
|
|
else if (val < 0x10000) {
|
|
count += 3;
|
|
}
|
|
else if (val < 0x200000) {
|
|
count += 4;
|
|
}
|
|
else {
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
if (count == arr.length)
|
|
return arr;
|
|
|
|
var res = [];
|
|
for (var ix=0; ix<arr.length; ix++) {
|
|
var val = arr[ix];
|
|
if (val < 0x80) {
|
|
res.push(val);
|
|
}
|
|
else if (val < 0x800) {
|
|
res.push(0xC0 | ((val & 0x7C0) >> 6));
|
|
res.push(0x80 | (val & 0x03F) );
|
|
}
|
|
else if (val < 0x10000) {
|
|
res.push(0xE0 | ((val & 0xF000) >> 12));
|
|
res.push(0x80 | ((val & 0x0FC0) >> 6));
|
|
res.push(0x80 | (val & 0x003F) );
|
|
}
|
|
else if (val < 0x200000) {
|
|
res.push(0xF0 | ((val & 0x1C0000) >> 18));
|
|
res.push(0x80 | ((val & 0x03F000) >> 12));
|
|
res.push(0x80 | ((val & 0x000FC0) >> 6));
|
|
res.push(0x80 | (val & 0x00003F) );
|
|
}
|
|
else {
|
|
res.push(63); // '?'
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/* Convert an array of 32-bit Unicode values to an array of 8-bit byte
|
|
values, encoded as big-endian words. */
|
|
function UniArrayToBE32(arr) {
|
|
var res = new Array(4*arr.length);
|
|
for (var ix=0; ix<arr.length; ix++) {
|
|
var val = arr[ix];
|
|
res[4*ix] = (val >> 24) & 0xFF;
|
|
res[4*ix+1] = (val >> 16) & 0xFF;
|
|
res[4*ix+2] = (val >> 8) & 0xFF;
|
|
res[4*ix+3] = (val) & 0xFF;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/* Log the message in the browser's error log, if it has one. (This shows
|
|
up in Safari, in Opera, and in Firefox if you have Firebug installed.)
|
|
*/
|
|
function qlog(msg) {
|
|
if (typeof console !== 'undefined' && console.log)
|
|
console.log(msg);
|
|
}
|
|
|
|
/* RefBox: Simple class used for "call-by-reference" Glk arguments. The object
|
|
is just a box containing a single value, which can be written and read.
|
|
*/
|
|
function RefBox() {
|
|
this.value = undefined;
|
|
this.set_value = function(val) {
|
|
this.value = val;
|
|
}
|
|
this.get_value = function() {
|
|
return this.value;
|
|
}
|
|
}
|
|
|
|
/* RefStruct: Used for struct-type Glk arguments. After creating the
|
|
object, you should call push_field() the appropriate number of times,
|
|
to set the initial field values. Then set_field() can be used to
|
|
change them, and get_fields() retrieves the list of all fields.
|
|
|
|
(The usage here is loose, since Javascript is forgiving about arrays.
|
|
Really the caller could call set_field() instead of push_field() --
|
|
or skip that step entirely, as long as the Glk function later calls
|
|
set_field() for each field. Which it should.)
|
|
*/
|
|
function RefStruct(numels) {
|
|
this.fields = [];
|
|
this.push_field = function(val) {
|
|
this.fields.push(val);
|
|
}
|
|
this.set_field = function(pos, val) {
|
|
this.fields[pos] = val;
|
|
}
|
|
this.get_field = function(pos) {
|
|
return this.fields[pos];
|
|
}
|
|
this.get_fields = function() {
|
|
return this.fields;
|
|
}
|
|
}
|
|
|
|
/* Dummy return value, which means that the Glk call is still in progress,
|
|
or will never return at all. This is used by glk_exit(), glk_select(),
|
|
and glk_fileref_create_by_prompt().
|
|
*/
|
|
var DidNotReturn = { dummy: 'Glk call has not yet returned' };
|
|
|
|
/* This returns a hint for whether the Glk call (by selector number)
|
|
might block or never return. True for glk_exit(), glk_select(),
|
|
and glk_fileref_create_by_prompt().
|
|
*/
|
|
function call_may_not_return(id) {
|
|
if (id == 0x001 || id == 0x0C0 || id == 0x062)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
var strtype_File = 1;
|
|
var strtype_Window = 2;
|
|
var strtype_Memory = 3;
|
|
var strtype_Resource = 4;
|
|
|
|
/* Extra update information -- autorestore only. */
|
|
var gli_autorestore_glkstate = null;
|
|
|
|
/* Beginning of linked list of windows. */
|
|
var gli_windowlist = null;
|
|
var gli_rootwin = null;
|
|
/* Set when any window is created, destroyed, or resized. */
|
|
var geometry_changed = true;
|
|
/* Received from GlkOte; describes the window size. */
|
|
var content_metrics = null;
|
|
|
|
/* Beginning of linked list of streams. */
|
|
var gli_streamlist = null;
|
|
/* Beginning of linked list of filerefs. */
|
|
var gli_filereflist = null;
|
|
/* Beginning of linked list of schannels. */
|
|
var gli_schannellist = null;
|
|
|
|
/* The current output stream. */
|
|
var gli_currentstr = null;
|
|
|
|
/* During a glk_select() block, this is the RefStruct which will contain
|
|
the result. */
|
|
var gli_selectref = null;
|
|
|
|
/* This is used to assigned disprock values to windows, when there is
|
|
no GiDispa layer to provide them. */
|
|
var gli_api_display_rocks = 1;
|
|
|
|
/* A positive number if the timer is set. */
|
|
var gli_timer_interval = null;
|
|
var gli_timer_started = null; /* when the setTimeout began */
|
|
var gli_timer_lastsent = null; /* last interval sent to GlkOte */
|
|
|
|
function gli_new_window(type, rock) {
|
|
var win = {};
|
|
win.type = type;
|
|
win.rock = rock;
|
|
win.disprock = undefined;
|
|
|
|
win.parent = null;
|
|
win.str = gli_stream_open_window(win);
|
|
win.echostr = null;
|
|
win.style = Const.style_Normal;
|
|
win.hyperlink = 0;
|
|
|
|
win.input_generation = null;
|
|
win.linebuf = null;
|
|
win.char_request = false;
|
|
win.line_request = false;
|
|
win.char_request_uni = false;
|
|
win.line_request_uni = false;
|
|
win.hyperlink_request = false;
|
|
win.mouse_request = false;
|
|
win.echo_line_input = true;
|
|
win.line_input_terminators = [];
|
|
win.request_echo_line_input = null; /* only used during a request */
|
|
|
|
/* window-type-specific info is set up in glk_window_open */
|
|
|
|
win.prev = null;
|
|
win.next = gli_windowlist;
|
|
gli_windowlist = win;
|
|
if (win.next)
|
|
win.next.prev = win;
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_register('window', win);
|
|
else
|
|
win.disprock = gli_api_display_rocks++;
|
|
/* We need to assign a disprock even if there's no GiDispa layer,
|
|
because GlkOte differentiates windows by their disprock. */
|
|
geometry_changed = true;
|
|
|
|
return win;
|
|
}
|
|
|
|
function gli_delete_window(win) {
|
|
var prev, next;
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_unregister('window', win);
|
|
geometry_changed = true;
|
|
|
|
win.echostr = null;
|
|
if (win.str) {
|
|
gli_delete_stream(win.str);
|
|
win.str = null;
|
|
}
|
|
|
|
prev = win.prev;
|
|
next = win.next;
|
|
win.prev = null;
|
|
win.next = null;
|
|
|
|
if (prev)
|
|
prev.next = next;
|
|
else
|
|
gli_windowlist = next;
|
|
if (next)
|
|
next.prev = prev;
|
|
|
|
win.parent = null;
|
|
win.rock = null;
|
|
win.disprock = null;
|
|
}
|
|
|
|
function gli_windows_unechostream(str) {
|
|
var win;
|
|
|
|
for (win=gli_windowlist; win; win=win.next) {
|
|
if (win.echostr === str)
|
|
win.echostr = null;
|
|
}
|
|
}
|
|
|
|
/* Add a (Javascript) string to the given window's display. */
|
|
function gli_window_put_string(win, val) {
|
|
var ix, ch;
|
|
|
|
//### might be efficient to split the implementation up into
|
|
//### gli_window_buffer_put_string(), etc, since many functions
|
|
//### know the window type when they call this
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
if (win.style != win.accumstyle
|
|
|| win.hyperlink != win.accumhyperlink)
|
|
gli_window_buffer_deaccumulate(win);
|
|
win.accum.push(val);
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
for (ix=0; ix<val.length; ix++) {
|
|
ch = val.charAt(ix);
|
|
|
|
/* Canonicalize the cursor position. This is like calling
|
|
gli_window_grid_canonicalize(), but I've inlined it. */
|
|
if (win.cursorx < 0)
|
|
win.cursorx = 0;
|
|
else if (win.cursorx >= win.gridwidth) {
|
|
win.cursorx = 0;
|
|
win.cursory++;
|
|
}
|
|
if (win.cursory < 0)
|
|
win.cursory = 0;
|
|
else if (win.cursory >= win.gridheight)
|
|
break; /* outside the window */
|
|
|
|
if (ch == "\n") {
|
|
/* a newline just moves the cursor. */
|
|
win.cursory++;
|
|
win.cursorx = 0;
|
|
continue;
|
|
}
|
|
|
|
lineobj = win.lines[win.cursory];
|
|
lineobj.dirty = true;
|
|
lineobj.chars[win.cursorx] = ch;
|
|
lineobj.styles[win.cursorx] = win.style;
|
|
lineobj.hyperlinks[win.cursorx] = win.hyperlink;
|
|
|
|
win.cursorx++;
|
|
/* We can leave the cursor outside the window, since it will be
|
|
canonicalized next time a character is printed. */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Canonicalize the cursor position. That is, the cursor may have
|
|
been left outside the window area; wrap it if necessary.
|
|
|
|
Returns true if the cursor winds up wrapped outside the window entirely;
|
|
false if the cursor winds up at a legal printing position.
|
|
*/
|
|
function gli_window_grid_canonicalize(win) {
|
|
if (win.cursorx < 0)
|
|
win.cursorx = 0;
|
|
else if (win.cursorx >= win.gridwidth) {
|
|
win.cursorx = 0;
|
|
win.cursory++;
|
|
}
|
|
if (win.cursory < 0)
|
|
win.cursory = 0;
|
|
else if (win.cursory >= win.gridheight)
|
|
return true; /* outside the window */
|
|
return false;
|
|
}
|
|
|
|
/* Take the accumulation of strings (since the last style change) and
|
|
assemble them into a buffer window update. This must be called
|
|
after each style change; it must also be called right before
|
|
GlkOte.update(). (Actually we call it right before win.accum.push
|
|
if the style has changed -- there's no need to call for *every* style
|
|
change if no text is being pushed out in between.)
|
|
*/
|
|
function gli_window_buffer_deaccumulate(win) {
|
|
var conta = win.content;
|
|
var stylename = StyleNameMap[win.accumstyle];
|
|
var text, ls, ix, obj, arr;
|
|
|
|
if (win.accum.length) {
|
|
text = win.accum.join('');
|
|
ls = text.split('\n');
|
|
for (ix=0; ix<ls.length; ix++) {
|
|
arr = undefined;
|
|
if (ix == 0) {
|
|
if (ls[ix]) {
|
|
if (conta.length == 0) {
|
|
arr = [];
|
|
conta.push({ content: arr, append: true });
|
|
}
|
|
else {
|
|
obj = conta[conta.length-1];
|
|
if (!obj.content) {
|
|
arr = [];
|
|
obj.content = arr;
|
|
}
|
|
else {
|
|
arr = obj.content;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (ls[ix]) {
|
|
arr = [];
|
|
conta.push({ content: arr });
|
|
}
|
|
else {
|
|
conta.push({ });
|
|
}
|
|
}
|
|
if (arr !== undefined) {
|
|
if (!win.accumhyperlink) {
|
|
arr.push(stylename);
|
|
arr.push(ls[ix]);
|
|
}
|
|
else {
|
|
arr.push({ style:stylename, text:ls[ix], hyperlink:win.accumhyperlink });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
win.accum.length = 0;
|
|
win.accumstyle = win.style;
|
|
win.accumhyperlink = win.hyperlink;
|
|
}
|
|
|
|
/* Add a special object onto a buffer window update. This resets the
|
|
accumulator.
|
|
*/
|
|
function gli_window_buffer_put_special(win, special, flowbreak) {
|
|
gli_window_buffer_deaccumulate(win);
|
|
|
|
var conta = win.content;
|
|
var arr = undefined;
|
|
var obj;
|
|
|
|
/* The next bit is a simplified version of the array-append code
|
|
from deaccumulate(). It's simpler because we have exactly one
|
|
item to add. */
|
|
|
|
if (conta.length == 0) {
|
|
arr = [];
|
|
obj = { content: arr, append: true };
|
|
if (flowbreak)
|
|
obj.flowbreak = true;
|
|
conta.push(obj);
|
|
}
|
|
else {
|
|
obj = conta[conta.length-1];
|
|
if (flowbreak)
|
|
obj.flowbreak = true;
|
|
if (!obj.content) {
|
|
arr = [];
|
|
obj.content = arr;
|
|
}
|
|
else {
|
|
arr = obj.content;
|
|
}
|
|
}
|
|
|
|
if (arr !== undefined && special !== undefined) {
|
|
arr.push(special);
|
|
}
|
|
}
|
|
|
|
function gli_window_close(win, recurse) {
|
|
var wx;
|
|
|
|
for (wx=win.parent; wx; wx=wx.parent) {
|
|
if (wx.type == Const.wintype_Pair) {
|
|
if (wx.pair_key === win) {
|
|
wx.pair_key = null;
|
|
wx.pair_keydamage = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GiDispa && win.linebuf) {
|
|
GiDispa.unretain_array(win.linebuf);
|
|
win.linebuf = null;
|
|
}
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_Pair:
|
|
if (recurse) {
|
|
if (win.child1)
|
|
gli_window_close(win.child1, true);
|
|
if (win.child2)
|
|
gli_window_close(win.child2, true);
|
|
}
|
|
win.child1 = null;
|
|
win.child2 = null;
|
|
win.pair_key = null;
|
|
break;
|
|
case Const.wintype_TextBuffer:
|
|
win.accum = null;
|
|
win.content = null;
|
|
win.reserve = null;
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
win.lines = null;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
win.content = null;
|
|
win.reserve = null;
|
|
break;
|
|
}
|
|
|
|
gli_delete_window(win);
|
|
}
|
|
|
|
function gli_window_rearrange(win, box) {
|
|
var width, height, oldwidth, oldheight;
|
|
var min, max, diff, splitwid, ix, cx, lineobj;
|
|
var box1, box2, ch1, ch2;
|
|
|
|
geometry_changed = true;
|
|
win.bbox = box;
|
|
|
|
switch (win.type) {
|
|
|
|
case Const.wintype_TextGrid:
|
|
/* Compute the new grid size. */
|
|
width = box.right - box.left;
|
|
height = box.bottom - box.top;
|
|
oldheight = win.gridheight;
|
|
win.gridwidth = Math.max(0, Math.floor((width-content_metrics.gridmarginx) / content_metrics.gridcharwidth));
|
|
win.gridheight = Math.max(0, Math.floor((height-content_metrics.gridmarginy) / content_metrics.gridcharheight));
|
|
|
|
/* Now we have to resize the win.lines array, in two dimensions. */
|
|
if (oldheight > win.gridheight) {
|
|
win.lines.length = win.gridheight;
|
|
}
|
|
else if (oldheight < win.gridheight) {
|
|
for (ix=oldheight; ix<win.gridheight; ix++) {
|
|
win.lines[ix] = { chars:[], styles:[], hyperlinks:[],
|
|
dirty:true };
|
|
}
|
|
}
|
|
for (ix=0; ix<win.gridheight; ix++) {
|
|
lineobj = win.lines[ix];
|
|
oldwidth = lineobj.chars.length;
|
|
if (oldwidth > win.gridwidth) {
|
|
lineobj.dirty = true;
|
|
lineobj.chars.length = win.gridwidth;
|
|
lineobj.styles.length = win.gridwidth;
|
|
lineobj.hyperlinks.length = win.gridwidth;
|
|
}
|
|
else if (oldwidth < win.gridwidth) {
|
|
lineobj.dirty = true;
|
|
for (cx=oldwidth; cx<win.gridwidth; cx++) {
|
|
lineobj.chars[cx] = ' ';
|
|
lineobj.styles[cx] = Const.style_Normal;
|
|
lineobj.hyperlinks[cx] = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Const.wintype_Graphics:
|
|
/* Compute the new canvas size. */
|
|
width = box.right - box.left;
|
|
height = box.bottom - box.top;
|
|
win.graphwidth = Math.max(0, width - content_metrics.graphicsmarginx);
|
|
win.graphheight = Math.max(0, height - content_metrics.graphicsmarginy);
|
|
break;
|
|
|
|
case Const.wintype_Pair:
|
|
if (win.pair_vertical) {
|
|
min = win.bbox.left;
|
|
max = win.bbox.right;
|
|
splitwid = content_metrics.inspacingx;
|
|
}
|
|
else {
|
|
min = win.bbox.top;
|
|
max = win.bbox.bottom;
|
|
splitwid = content_metrics.inspacingy;
|
|
}
|
|
if (!win.pair_hasborder)
|
|
splitwid = 0;
|
|
diff = max - min;
|
|
|
|
if (win.pair_division == Const.winmethod_Proportional) {
|
|
split = Math.floor((diff * win.pair_size) / 100);
|
|
}
|
|
else if (win.pair_division == Const.winmethod_Fixed) {
|
|
split = 0;
|
|
if (win.pair_key && win.pair_key.type == Const.wintype_TextBuffer) {
|
|
if (!win.pair_vertical)
|
|
split = (win.pair_size * content_metrics.buffercharheight + content_metrics.buffermarginy);
|
|
else
|
|
split = (win.pair_size * content_metrics.buffercharwidth + content_metrics.buffermarginx);
|
|
}
|
|
if (win.pair_key && win.pair_key.type == Const.wintype_TextGrid) {
|
|
if (!win.pair_vertical)
|
|
split = (win.pair_size * content_metrics.gridcharheight + content_metrics.gridmarginy);
|
|
else
|
|
split = (win.pair_size * content_metrics.gridcharwidth + content_metrics.gridmarginx);
|
|
}
|
|
if (win.pair_key && win.pair_key.type == Const.wintype_Graphics) {
|
|
if (!win.pair_vertical)
|
|
split = win.pair_size + content_metrics.graphicsmarginy;
|
|
else
|
|
split = win.pair_size + content_metrics.graphicsmarginx;
|
|
}
|
|
split = Math.ceil(split);
|
|
}
|
|
else {
|
|
/* default behavior for unknown division method */
|
|
split = Math.floor(diff / 2);
|
|
}
|
|
|
|
/* Split is now a number between 0 and diff. Convert that to a number
|
|
between min and max; also apply upside-down-ness. */
|
|
if (!win.pair_backward) {
|
|
split = max-split-splitwid;
|
|
}
|
|
else {
|
|
split = min+split;
|
|
}
|
|
|
|
/* Make sure it's really between min and max. */
|
|
if (min >= max) {
|
|
split = min;
|
|
}
|
|
else {
|
|
split = Math.min(Math.max(split, min), max-splitwid);
|
|
}
|
|
|
|
win.pair_splitpos = split;
|
|
win.pair_splitwidth = splitwid;
|
|
if (win.pair_vertical) {
|
|
box1 = {
|
|
left: win.bbox.left,
|
|
right: win.pair_splitpos,
|
|
top: win.bbox.top,
|
|
bottom: win.bbox.bottom
|
|
};
|
|
box2 = {
|
|
left: box1.right + win.pair_splitwidth,
|
|
right: win.bbox.right,
|
|
top: win.bbox.top,
|
|
bottom: win.bbox.bottom
|
|
};
|
|
}
|
|
else {
|
|
box1 = {
|
|
top: win.bbox.top,
|
|
bottom: win.pair_splitpos,
|
|
left: win.bbox.left,
|
|
right: win.bbox.right
|
|
};
|
|
box2 = {
|
|
top: box1.bottom + win.pair_splitwidth,
|
|
bottom: win.bbox.bottom,
|
|
left: win.bbox.left,
|
|
right: win.bbox.right
|
|
};
|
|
}
|
|
if (!win.pair_backward) {
|
|
ch1 = win.child1;
|
|
ch2 = win.child2;
|
|
}
|
|
else {
|
|
ch1 = win.child2;
|
|
ch2 = win.child1;
|
|
}
|
|
|
|
gli_window_rearrange(ch1, box1);
|
|
gli_window_rearrange(ch2, box2);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
function gli_new_stream(type, readable, writable, rock) {
|
|
var str = {};
|
|
str.type = type;
|
|
str.rock = rock;
|
|
str.disprock = undefined;
|
|
|
|
str.unicode = false;
|
|
/* isbinary is only meaningful for Resource and streaming-File streams */
|
|
str.isbinary = false;
|
|
str.streaming = false;
|
|
str.ref = null;
|
|
str.win = null;
|
|
str.file = null;
|
|
|
|
/* for buffer mode */
|
|
str.buf = null;
|
|
str.bufpos = 0;
|
|
str.buflen = 0;
|
|
str.bufeof = 0;
|
|
str.timer_id = null;
|
|
str.flush_func = null;
|
|
|
|
/* for streaming mode */
|
|
str.fstream = null;
|
|
|
|
str.readcount = 0;
|
|
str.writecount = 0;
|
|
str.readable = readable;
|
|
str.writable = writable;
|
|
|
|
str.prev = null;
|
|
str.next = gli_streamlist;
|
|
gli_streamlist = str;
|
|
if (str.next)
|
|
str.next.prev = str;
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_register('stream', str);
|
|
|
|
return str;
|
|
}
|
|
|
|
function gli_delete_stream(str) {
|
|
var prev, next;
|
|
|
|
if (str === gli_currentstr) {
|
|
gli_currentstr = null;
|
|
}
|
|
|
|
gli_windows_unechostream(str);
|
|
|
|
if (str.type == strtype_Memory) {
|
|
if (GiDispa)
|
|
GiDispa.unretain_array(str.buf);
|
|
}
|
|
else if (str.type == strtype_File) {
|
|
if (str.fstream) {
|
|
str.fstream.fclose();
|
|
str.fstream = null;
|
|
}
|
|
}
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_unregister('stream', str);
|
|
|
|
prev = str.prev;
|
|
next = str.next;
|
|
str.prev = null;
|
|
str.next = null;
|
|
|
|
if (prev)
|
|
prev.next = next;
|
|
else
|
|
gli_streamlist = next;
|
|
if (next)
|
|
next.prev = prev;
|
|
|
|
str.fstream = null;
|
|
str.buf = null;
|
|
str.readable = false;
|
|
str.writable = false;
|
|
str.ref = null;
|
|
str.win = null;
|
|
str.file = null;
|
|
str.rock = null;
|
|
str.disprock = null;
|
|
}
|
|
|
|
function gli_stream_open_window(win) {
|
|
var str;
|
|
str = gli_new_stream(strtype_Window, false, true, 0);
|
|
str.unicode = true;
|
|
str.win = win;
|
|
return str;
|
|
}
|
|
|
|
/* This is called on every write to a file stream. If a file is being
|
|
written intermittently (a transcript file, for example) we'd like to
|
|
flush the output every few seconds, in case the user closes the
|
|
browser without closing the file ("script off").
|
|
|
|
We do this by setting a ten-second timer (if there isn't one set already).
|
|
The timer calls a flush method on the stream.
|
|
|
|
(If autosave is on, we'll wind up flushing on most glk_select calls,
|
|
which isn't quite as nicely paced. But it's a minor problem.)
|
|
*/
|
|
function gli_stream_dirty_file(str) {
|
|
if (str.streaming)
|
|
GlkOte.log('### gli_stream_dirty_file called for streaming file!');
|
|
if (str.timer_id === null) {
|
|
if (str.flush_func === null) {
|
|
/* Bodge together a closure to act as a stream method. */
|
|
str.flush_func = function() { gli_stream_flush_file(str); };
|
|
}
|
|
str.timer_id = setTimeout(str.flush_func, 10000);
|
|
}
|
|
}
|
|
|
|
/* Write out the contents of a file stream to the "disk file". Because
|
|
localStorage doesn't support appending, we have to dump the entire
|
|
buffer out.
|
|
*/
|
|
function gli_stream_flush_file(str) {
|
|
if (str.streaming)
|
|
GlkOte.log('### gli_stream_flush_file called for streaming file!');
|
|
if (!(str.timer_id === null)) {
|
|
clearTimeout(str.timer_id);
|
|
}
|
|
str.timer_id = null;
|
|
Dialog.file_write(str.ref, str.buf);
|
|
}
|
|
|
|
function gli_new_fileref(filename, usage, rock, ref) {
|
|
var fref = {};
|
|
fref.filename = filename;
|
|
fref.rock = rock;
|
|
fref.disprock = undefined;
|
|
|
|
fref.textmode = ((usage & Const.fileusage_TextMode) != 0);
|
|
fref.filetype = (usage & Const.fileusage_TypeMask);
|
|
fref.filetypename = FileTypeMap[fref.filetype];
|
|
if (!fref.filetypename) {
|
|
fref.filetypename = 'xxx';
|
|
}
|
|
|
|
if (!ref) {
|
|
var gameid = '';
|
|
if (fref.filetype == Const.fileusage_SavedGame)
|
|
gameid = VM.get_signature();
|
|
ref = Dialog.file_construct_ref(fref.filename, fref.filetypename, gameid);
|
|
}
|
|
fref.ref = ref;
|
|
|
|
fref.prev = null;
|
|
fref.next = gli_filereflist;
|
|
gli_filereflist = fref;
|
|
if (fref.next)
|
|
fref.next.prev = fref;
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_register('fileref', fref);
|
|
|
|
return fref;
|
|
}
|
|
|
|
function gli_delete_fileref(fref) {
|
|
var prev, next;
|
|
|
|
if (GiDispa)
|
|
GiDispa.class_unregister('fileref', fref);
|
|
|
|
prev = fref.prev;
|
|
next = fref.next;
|
|
fref.prev = null;
|
|
fref.next = null;
|
|
|
|
if (prev)
|
|
prev.next = next;
|
|
else
|
|
gli_filereflist = next;
|
|
if (next)
|
|
next.prev = prev;
|
|
|
|
fref.filename = null;
|
|
fref.ref = null;
|
|
fref.rock = null;
|
|
fref.disprock = null;
|
|
}
|
|
|
|
/* Write one character (given as a Unicode value) to a stream.
|
|
This is called by both the one-byte and four-byte character APIs.
|
|
*/
|
|
function gli_put_char(str, ch) {
|
|
if (!str || !str.writable)
|
|
throw('gli_put_char: invalid stream');
|
|
|
|
if (!str.unicode) {
|
|
if (ch < 0 || ch >= 0x100)
|
|
ch = 63; // '?'
|
|
}
|
|
|
|
str.writecount += 1;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
if (!str.unicode) {
|
|
str.buffer4[0] = ch;
|
|
str.fstream.fwrite(str.buffer4, 1);
|
|
}
|
|
else {
|
|
if (!str.isbinary) {
|
|
/* cheap UTF-8 stream */
|
|
var len;
|
|
if (ch < 0x10000) {
|
|
len = str.buffer4.write(String.fromCharCode(ch));
|
|
str.fstream.fwrite(str.buffer4, len); // utf8
|
|
}
|
|
else {
|
|
/* String.fromCharCode chokes on astral characters;
|
|
do it the hard way */
|
|
var arr8 = UniArrayToUTF8([ch]);
|
|
var buf = str.fstream.BufferClass.from(arr8);
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
}
|
|
else {
|
|
/* cheap big-endian stream */
|
|
str.buffer4.writeUInt32BE(ch, 0, true);
|
|
str.fstream.fwrite(str.buffer4, 4);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* non-streaming... */
|
|
gli_stream_dirty_file(str);
|
|
if (!str.unicode || (ch < 0x80 && !str.isbinary)) {
|
|
if (str.bufpos < str.buflen) {
|
|
str.buf[str.bufpos] = ch;
|
|
str.bufpos += 1;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
}
|
|
}
|
|
else {
|
|
var arr;
|
|
if (!str.isbinary)
|
|
arr = UniArrayToUTF8([ch]);
|
|
else
|
|
arr = UniArrayToBE32([ch]);
|
|
var len = arr.length;
|
|
if (len > str.buflen-str.bufpos)
|
|
len = str.buflen-str.bufpos;
|
|
for (ix=0; ix<len; ix++)
|
|
str.buf[str.bufpos+ix] = arr[ix];
|
|
str.bufpos += len;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
}
|
|
}
|
|
break;
|
|
case strtype_Memory:
|
|
if (str.bufpos < str.buflen) {
|
|
str.buf[str.bufpos] = ch;
|
|
str.bufpos += 1;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
}
|
|
break;
|
|
case strtype_Window:
|
|
if (str.win.line_request)
|
|
throw('gli_put_char: window has pending line request');
|
|
gli_window_put_string(str.win, CharToString(ch));
|
|
if (str.win.echostr)
|
|
gli_put_char(str.win.echostr, ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Write characters (given as an array of Unicode values) to a stream.
|
|
This is called by both the one-byte and four-byte character APIs.
|
|
The "allbytes" argument is a hint that all the array values are
|
|
already in the range 0-255.
|
|
*/
|
|
function gli_put_array(str, arr, allbytes) {
|
|
var ix, len, val;
|
|
|
|
if (!str || !str.writable)
|
|
throw('gli_put_array: invalid stream');
|
|
|
|
if (!str.unicode && !allbytes) {
|
|
arr = TrimArrayToBytes(arr);
|
|
allbytes = true;
|
|
}
|
|
|
|
str.writecount += arr.length;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
if (!str.unicode) {
|
|
var buf = str.fstream.BufferClass.from(arr);
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
else {
|
|
if (!str.isbinary) {
|
|
/* cheap UTF-8 stream */
|
|
var arr8 = UniArrayToUTF8(arr);
|
|
var buf = str.fstream.BufferClass.from(arr8);
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
else {
|
|
/* cheap big-endian stream */
|
|
var buf = str.fstream.BufferClass.alloc(4*arr.length);
|
|
for (ix=0; ix<arr.length; ix++) {
|
|
buf.writeUInt32BE(arr[ix], 4*ix, true);
|
|
}
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* non-streaming... */
|
|
gli_stream_dirty_file(str);
|
|
var arr8;
|
|
if (!str.unicode) {
|
|
arr8 = arr;
|
|
}
|
|
else {
|
|
if (!str.isbinary)
|
|
arr8 = UniArrayToUTF8(arr);
|
|
else
|
|
arr8 = UniArrayToBE32(arr);
|
|
}
|
|
var len = arr8.length;
|
|
if (len > str.buflen-str.bufpos)
|
|
len = str.buflen-str.bufpos;
|
|
for (ix=0; ix<len; ix++)
|
|
str.buf[str.bufpos+ix] = arr8[ix];
|
|
str.bufpos += len;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
}
|
|
break;
|
|
case strtype_Memory:
|
|
len = arr.length;
|
|
if (len > str.buflen-str.bufpos)
|
|
len = str.buflen-str.bufpos;
|
|
for (ix=0; ix<len; ix++)
|
|
str.buf[str.bufpos+ix] = arr[ix];
|
|
str.bufpos += len;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
break;
|
|
case strtype_Window:
|
|
if (str.win.line_request)
|
|
throw('gli_put_array: window has pending line request');
|
|
if (allbytes)
|
|
val = String.fromCharCode.apply(this, arr);
|
|
else
|
|
val = UniArrayToString(arr);
|
|
gli_window_put_string(str.win, val);
|
|
if (str.win.echostr)
|
|
gli_put_array(str.win.echostr, arr, allbytes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function gli_get_char(str, want_unicode) {
|
|
var ch;
|
|
|
|
if (!str || !str.readable)
|
|
return -1;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
if (!str.unicode) {
|
|
var len = str.fstream.fread(str.buffer4, 1);
|
|
if (!len)
|
|
return -1;
|
|
str.readcount++;
|
|
return str.buffer4[0];
|
|
}
|
|
else {
|
|
if (!str.isbinary) {
|
|
/* slightly less cheap UTF8 stream */
|
|
var val0, val1, val2, val3;
|
|
var len = str.fstream.fread(str.buffer4, 1);
|
|
if (!len)
|
|
return -1;
|
|
val0 = str.buffer4[0];
|
|
if (val0 < 0x80) {
|
|
ch = val0;
|
|
}
|
|
else {
|
|
var len = str.fstream.fread(str.buffer4, 1);
|
|
if (!len)
|
|
return -1;
|
|
val1 = str.buffer4[0];
|
|
if ((val1 & 0xC0) != 0x80)
|
|
return -1;
|
|
if ((val0 & 0xE0) == 0xC0) {
|
|
ch = (val0 & 0x1F) << 6;
|
|
ch |= (val1 & 0x3F);
|
|
}
|
|
else {
|
|
var len = str.fstream.fread(str.buffer4, 1);
|
|
if (!len)
|
|
return -1;
|
|
val2 = str.buffer4[0];
|
|
if ((val2 & 0xC0) != 0x80)
|
|
return -1;
|
|
if ((val0 & 0xF0) == 0xE0) {
|
|
ch = (((val0 & 0xF)<<12) & 0x0000F000);
|
|
ch |= (((val1 & 0x3F)<<6) & 0x00000FC0);
|
|
ch |= (((val2 & 0x3F)) & 0x0000003F);
|
|
}
|
|
else if ((val0 & 0xF0) == 0xF0) {
|
|
var len = str.fstream.fread(str.buffer4, 1);
|
|
if (!len)
|
|
return -1;
|
|
val3 = str.buffer4[0];
|
|
if ((val3 & 0xC0) != 0x80)
|
|
return -1;
|
|
ch = (((val0 & 0x7)<<18) & 0x1C0000);
|
|
ch |= (((val1 & 0x3F)<<12) & 0x03F000);
|
|
ch |= (((val2 & 0x3F)<<6) & 0x000FC0);
|
|
ch |= (((val3 & 0x3F)) & 0x00003F);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* cheap big-endian stream */
|
|
var len = str.fstream.fread(str.buffer4, 4);
|
|
if (len < 4)
|
|
return -1;
|
|
/*### or buf.readUInt32BE(0, true) */
|
|
ch = (str.buffer4[0] << 24);
|
|
ch |= (str.buffer4[1] << 16);
|
|
ch |= (str.buffer4[2] << 8);
|
|
ch |= str.buffer4[3];
|
|
}
|
|
str.readcount++;
|
|
ch >>>= 0;
|
|
if (!want_unicode && ch >= 0x100)
|
|
return 63; // return '?'
|
|
return ch;
|
|
}
|
|
}
|
|
/* non-streaming, fall through to resource... */
|
|
case strtype_Resource:
|
|
if (str.unicode) {
|
|
if (str.isbinary) {
|
|
/* cheap big-endian stream */
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
ch = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
ch = (ch << 8) | (str.buf[str.bufpos] & 0xFF);
|
|
str.bufpos++;
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
ch = (ch << 8) | (str.buf[str.bufpos] & 0xFF);
|
|
str.bufpos++;
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
ch = (ch << 8) | (str.buf[str.bufpos] & 0xFF);
|
|
str.bufpos++;
|
|
}
|
|
else {
|
|
/* slightly less cheap UTF8 stream */
|
|
var val0, val1, val2, val3;
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
val0 = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
if (val0 < 0x80) {
|
|
ch = val0;
|
|
}
|
|
else {
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
val1 = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
if ((val1 & 0xC0) != 0x80)
|
|
return -1;
|
|
if ((val0 & 0xE0) == 0xC0) {
|
|
ch = (val0 & 0x1F) << 6;
|
|
ch |= (val1 & 0x3F);
|
|
}
|
|
else {
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
val2 = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
if ((val2 & 0xC0) != 0x80)
|
|
return -1;
|
|
if ((val0 & 0xF0) == 0xE0) {
|
|
ch = (((val0 & 0xF)<<12) & 0x0000F000);
|
|
ch |= (((val1 & 0x3F)<<6) & 0x00000FC0);
|
|
ch |= (((val2 & 0x3F)) & 0x0000003F);
|
|
}
|
|
else if ((val0 & 0xF0) == 0xF0) {
|
|
if (str.bufpos >= str.bufeof)
|
|
return -1;
|
|
val3 = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
if ((val3 & 0xC0) != 0x80)
|
|
return -1;
|
|
ch = (((val0 & 0x7)<<18) & 0x1C0000);
|
|
ch |= (((val1 & 0x3F)<<12) & 0x03F000);
|
|
ch |= (((val2 & 0x3F)<<6) & 0x000FC0);
|
|
ch |= (((val3 & 0x3F)) & 0x00003F);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
str.readcount++;
|
|
ch >>>= 0;
|
|
if (!want_unicode && ch >= 0x100)
|
|
return 63; // return '?'
|
|
return ch;
|
|
}
|
|
/* non-unicode file/resource, fall through to memory... */
|
|
case strtype_Memory:
|
|
if (str.bufpos < str.bufeof) {
|
|
ch = str.buf[str.bufpos];
|
|
str.bufpos++;
|
|
str.readcount++;
|
|
if (!want_unicode && ch >= 0x100)
|
|
return 63; // return '?'
|
|
return ch;
|
|
}
|
|
else {
|
|
return -1; // end of stream
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
function gli_get_line(str, buf, want_unicode) {
|
|
if (!str || !str.readable)
|
|
return 0;
|
|
|
|
var len = buf.length;
|
|
var gotnewline;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
if (len == 0)
|
|
return 0;
|
|
len -= 1; /* for the terminal null */
|
|
gotnewline = false;
|
|
for (lx=0; lx<len && !gotnewline; lx++) {
|
|
ch = gli_get_char(str, want_unicode);
|
|
if (ch == -1)
|
|
break;
|
|
buf[lx] = ch;
|
|
gotnewline = (ch == 10);
|
|
}
|
|
return lx;
|
|
}
|
|
/* non-streaming, fall through to resource... */
|
|
case strtype_Resource:
|
|
if (str.unicode) {
|
|
if (len == 0)
|
|
return 0;
|
|
len -= 1; /* for the terminal null */
|
|
gotnewline = false;
|
|
for (lx=0; lx<len && !gotnewline; lx++) {
|
|
ch = gli_get_char(str, want_unicode);
|
|
if (ch == -1)
|
|
break;
|
|
buf[lx] = ch;
|
|
gotnewline = (ch == 10);
|
|
}
|
|
return lx;
|
|
}
|
|
/* non-unicode file/resource, fall through to memory... */
|
|
case strtype_Memory:
|
|
if (len == 0)
|
|
return 0;
|
|
len -= 1; /* for the terminal null */
|
|
if (str.bufpos >= str.bufeof) {
|
|
len = 0;
|
|
}
|
|
else {
|
|
if (str.bufpos + len > str.bufeof) {
|
|
len = str.bufeof - str.bufpos;
|
|
}
|
|
}
|
|
gotnewline = false;
|
|
if (!want_unicode) {
|
|
for (lx=0; lx<len && !gotnewline; lx++) {
|
|
ch = str.buf[str.bufpos++];
|
|
if (!want_unicode && ch >= 0x100)
|
|
ch = 63; // ch = '?'
|
|
buf[lx] = ch;
|
|
gotnewline = (ch == 10);
|
|
}
|
|
}
|
|
else {
|
|
for (lx=0; lx<len && !gotnewline; lx++) {
|
|
ch = str.buf[str.bufpos++];
|
|
buf[lx] = ch;
|
|
gotnewline = (ch == 10);
|
|
}
|
|
}
|
|
str.readcount += lx;
|
|
return lx;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function gli_get_buffer(str, buf, want_unicode) {
|
|
if (!str || !str.readable)
|
|
return 0;
|
|
|
|
var len = buf.length;
|
|
var lx, ch;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
for (lx=0; lx<len; lx++) {
|
|
ch = gli_get_char(str, want_unicode);
|
|
if (ch == -1)
|
|
break;
|
|
buf[lx] = ch;
|
|
}
|
|
return lx;
|
|
}
|
|
/* non-streaming, fall through to resource... */
|
|
case strtype_Resource:
|
|
if (str.unicode) {
|
|
for (lx=0; lx<len; lx++) {
|
|
ch = gli_get_char(str, want_unicode);
|
|
if (ch == -1)
|
|
break;
|
|
buf[lx] = ch;
|
|
}
|
|
return lx;
|
|
}
|
|
/* non-unicode file/resource, fall through to memory... */
|
|
case strtype_Memory:
|
|
if (str.bufpos >= str.bufeof) {
|
|
len = 0;
|
|
}
|
|
else {
|
|
if (str.bufpos + len > str.bufeof) {
|
|
len = str.bufeof - str.bufpos;
|
|
}
|
|
}
|
|
if (!want_unicode) {
|
|
for (lx=0; lx<len; lx++) {
|
|
ch = str.buf[str.bufpos++];
|
|
if (!want_unicode && ch >= 0x100)
|
|
ch = 63; // ch = '?'
|
|
buf[lx] = ch;
|
|
}
|
|
}
|
|
else {
|
|
for (lx=0; lx<len; lx++) {
|
|
buf[lx] = str.buf[str.bufpos++];
|
|
}
|
|
}
|
|
str.readcount += len;
|
|
return len;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function gli_stream_fill_result(str, result) {
|
|
if (!result)
|
|
return;
|
|
result.set_field(0, str.readcount);
|
|
result.set_field(1, str.writecount);
|
|
}
|
|
|
|
function glk_put_jstring(val, allbytes) {
|
|
glk_put_jstring_stream(gli_currentstr, val, allbytes);
|
|
}
|
|
|
|
function glk_put_jstring_stream(str, val, allbytes) {
|
|
var ix, len;
|
|
|
|
if (!str || !str.writable)
|
|
throw('glk_put_jstring: invalid stream');
|
|
|
|
str.writecount += val.length;
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
if (!str.unicode) {
|
|
// if !allbytes, we just give up on non-Latin-1 characters
|
|
var buf = str.fstream.BufferClass.from(val, 'binary');
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
else {
|
|
if (!str.isbinary) {
|
|
/* cheap UTF-8 stream */
|
|
var buf = str.fstream.BufferClass.from(val); // utf8
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
else {
|
|
/* cheap big-endian stream */
|
|
var buf = str.fstream.BufferClass.alloc(4*val.length);
|
|
for (ix=0; ix<val.length; ix++) {
|
|
buf.writeUInt32BE(val.charCodeAt(ix), 4*ix, true);
|
|
}
|
|
str.fstream.fwrite(buf);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* non-streaming... */
|
|
gli_stream_dirty_file(str);
|
|
var arr = [];
|
|
for (ix=0; ix<val.length; ix++)
|
|
arr.push(val.charCodeAt(ix));
|
|
var arr8;
|
|
if (!str.unicode) {
|
|
arr8 = arr;
|
|
}
|
|
else {
|
|
if (!str.isbinary)
|
|
arr8 = UniArrayToUTF8(arr);
|
|
else
|
|
arr8 = UniArrayToBE32(arr);
|
|
}
|
|
var len = arr8.length;
|
|
if (len > str.buflen-str.bufpos)
|
|
len = str.buflen-str.bufpos;
|
|
for (ix=0; ix<len; ix++)
|
|
str.buf[str.bufpos+ix] = arr8[ix];
|
|
str.bufpos += len;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
}
|
|
break;
|
|
case strtype_Memory:
|
|
len = val.length;
|
|
if (len > str.buflen-str.bufpos)
|
|
len = str.buflen-str.bufpos;
|
|
if (str.unicode || allbytes) {
|
|
for (ix=0; ix<len; ix++)
|
|
str.buf[str.bufpos+ix] = val.charCodeAt(ix);
|
|
}
|
|
else {
|
|
for (ix=0; ix<len; ix++) {
|
|
var ch = val.charCodeAt(ix);
|
|
if (ch < 0 || ch >= 0x100)
|
|
ch = 63; // '?'
|
|
str.buf[str.bufpos+ix] = ch;
|
|
}
|
|
}
|
|
str.bufpos += len;
|
|
if (str.bufpos > str.bufeof)
|
|
str.bufeof = str.bufpos;
|
|
break;
|
|
case strtype_Window:
|
|
if (str.win.line_request)
|
|
throw('glk_put_jstring: window has pending line request');
|
|
gli_window_put_string(str.win, val);
|
|
if (str.win.echostr)
|
|
glk_put_jstring_stream(str.win.echostr, val, allbytes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function gli_set_style(str, val) {
|
|
if (!str || !str.writable)
|
|
throw('gli_set_style: invalid stream');
|
|
|
|
if (val >= Const.style_NUMSTYLES)
|
|
val = 0;
|
|
|
|
if (str.type == strtype_Window) {
|
|
str.win.style = val;
|
|
if (str.win.echostr)
|
|
gli_set_style(str.win.echostr, val);
|
|
}
|
|
}
|
|
|
|
function gli_set_hyperlink(str, val) {
|
|
if (!str || !str.writable)
|
|
throw('gli_set_hyperlink: invalid stream');
|
|
|
|
if (str.type == strtype_Window) {
|
|
str.win.hyperlink = val;
|
|
if (str.win.echostr)
|
|
gli_set_hyperlink(str.win.echostr, val);
|
|
}
|
|
}
|
|
|
|
/* The catalog of Glk API functions. */
|
|
|
|
function glk_exit() {
|
|
/* For safety, this is fast and idempotent. */
|
|
has_exited = true;
|
|
ui_disabled = true;
|
|
gli_selectref = null;
|
|
if (option_exit_warning)
|
|
GlkOte.warning(option_exit_warning);
|
|
update('exit');
|
|
return DidNotReturn;
|
|
}
|
|
|
|
function glk_tick() {
|
|
/* Do nothing. */
|
|
}
|
|
|
|
function glk_gestalt(sel, val) {
|
|
return glk_gestalt_ext(sel, val, null);
|
|
}
|
|
|
|
function glk_gestalt_ext(sel, val, arr) {
|
|
switch (sel) {
|
|
|
|
case 0: // gestalt_Version
|
|
/* This implements Glk spec version 0.7.4. */
|
|
return 0x00000704;
|
|
|
|
case 1: // gestalt_CharInput
|
|
/* This is not a terrific approximation. Return false for function
|
|
keys, control keys, and the high-bit non-printables. For
|
|
everything else in the Unicode range, return true. */
|
|
if (val <= Const.keycode_Left && val >= Const.keycode_End)
|
|
return 1;
|
|
if (val >= 0x100000000-Const.keycode_MAXVAL)
|
|
return 0;
|
|
if (val > 0x10FFFF)
|
|
return 0;
|
|
if ((val >= 0 && val < 32) || (val >= 127 && val < 160))
|
|
return 0;
|
|
return 1;
|
|
|
|
case 2: // gestalt_LineInput
|
|
/* Same as the above, except no special keys. */
|
|
if (val > 0x10FFFF)
|
|
return 0;
|
|
if ((val >= 0 && val < 32) || (val >= 127 && val < 160))
|
|
return 0;
|
|
return 1;
|
|
|
|
case 3: // gestalt_CharOutput
|
|
/* Same thing again. We assume that all printable characters,
|
|
as well as the placeholders for nonprintables, are one character
|
|
wide. */
|
|
if ((val > 0x10FFFF)
|
|
|| (val >= 0 && val < 32)
|
|
|| (val >= 127 && val < 160)) {
|
|
if (arr)
|
|
arr[0] = 1;
|
|
return 0; // gestalt_CharOutput_CannotPrint
|
|
}
|
|
if (arr)
|
|
arr[0] = 1;
|
|
return 2; // gestalt_CharOutput_ExactPrint
|
|
|
|
case 4: // gestalt_MouseInput
|
|
if (val == Const.wintype_TextGrid)
|
|
return 1;
|
|
if (support.graphics && val == Const.wintype_Graphics)
|
|
return 1;
|
|
return 0;
|
|
|
|
case 5: // gestalt_Timer
|
|
return support.timer || 0;
|
|
|
|
case 6: // gestalt_Graphics
|
|
return support.graphics || 0;
|
|
|
|
case 7: // gestalt_DrawImage
|
|
if (support.graphics && (val == Const.wintype_TextBuffer || val == Const.wintype_Graphics))
|
|
return 1;
|
|
return 0;
|
|
|
|
case 8: // gestalt_Sound
|
|
return 0;
|
|
|
|
case 9: // gestalt_SoundVolume
|
|
return 0;
|
|
|
|
case 10: // gestalt_SoundNotify
|
|
return 0;
|
|
|
|
case 11: // gestalt_Hyperlinks
|
|
return support.hyperlinks || 0;
|
|
|
|
case 12: // gestalt_HyperlinkInput
|
|
if (support.hyperlinks && (val == Const.wintype_TextBuffer || val == Const.wintype_TextGrid))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
|
|
case 13: // gestalt_SoundMusic
|
|
return 0;
|
|
|
|
case 14: // gestalt_GraphicsTransparency
|
|
return support.graphics || 0;
|
|
|
|
case 15: // gestalt_Unicode
|
|
return 1;
|
|
|
|
case 16: // gestalt_UnicodeNorm
|
|
return 1;
|
|
|
|
case 17: // gestalt_LineInputEcho
|
|
return 1;
|
|
|
|
case 18: // gestalt_LineTerminators
|
|
return 1;
|
|
|
|
case 19: // gestalt_LineTerminatorKey
|
|
/* Really this result should be inspected from glkote.js. Since it
|
|
isn't, be sure to keep these values in sync with
|
|
terminator_key_names. */
|
|
if (val == Const.keycode_Escape)
|
|
return 1;
|
|
if (val >= Const.keycode_Func12 && val <= Const.keycode_Func1)
|
|
return 1;
|
|
return 0;
|
|
|
|
case 20: // gestalt_DateTime
|
|
return 1;
|
|
|
|
case 21: // gestalt_Sound2
|
|
return 0;
|
|
|
|
case 22: // gestalt_ResourceStream
|
|
return 1;
|
|
|
|
case 23: // gestalt_GraphicsCharInput
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (option_glk_gestalt_hook) {
|
|
var res = option_glk_gestalt_hook(sel, val, arr);
|
|
if (res !== undefined)
|
|
return res;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function glk_window_iterate(win, rockref) {
|
|
if (!win)
|
|
win = gli_windowlist;
|
|
else
|
|
win = win.next;
|
|
|
|
if (win) {
|
|
if (rockref)
|
|
rockref.set_value(win.rock);
|
|
return win;
|
|
}
|
|
|
|
if (rockref)
|
|
rockref.set_value(0);
|
|
return null;
|
|
}
|
|
|
|
function glk_window_get_rock(win) {
|
|
if (!win)
|
|
throw('glk_window_get_rock: invalid window');
|
|
return win.rock;
|
|
}
|
|
|
|
function glk_window_get_root() {
|
|
return gli_rootwin;
|
|
}
|
|
|
|
function glk_window_open(splitwin, method, size, wintype, rock) {
|
|
var oldparent, box, val;
|
|
var pairwin, newwin;
|
|
|
|
if (!gli_rootwin) {
|
|
if (splitwin)
|
|
throw('glk_window_open: splitwin must be null for first window');
|
|
|
|
oldparent = null;
|
|
box = {
|
|
left: content_metrics.outspacingx,
|
|
top: content_metrics.outspacingy,
|
|
right: content_metrics.width-content_metrics.outspacingx,
|
|
bottom: content_metrics.height-content_metrics.outspacingy
|
|
};
|
|
}
|
|
else {
|
|
if (!splitwin)
|
|
throw('glk_window_open: splitwin must not be null');
|
|
|
|
val = (method & Const.winmethod_DivisionMask);
|
|
if (val != Const.winmethod_Fixed && val != Const.winmethod_Proportional)
|
|
throw('glk_window_open: invalid method (not fixed or proportional)');
|
|
|
|
val = (method & Const.winmethod_DirMask);
|
|
if (val != Const.winmethod_Above && val != Const.winmethod_Below
|
|
&& val != Const.winmethod_Left && val != Const.winmethod_Right)
|
|
throw('glk_window_open: invalid method (bad direction)');
|
|
|
|
box = splitwin.bbox;
|
|
|
|
oldparent = splitwin.parent;
|
|
if (oldparent && oldparent.type != Const.wintype_Pair)
|
|
throw('glk_window_open: parent window is not Pair');
|
|
}
|
|
|
|
newwin = gli_new_window(wintype, rock);
|
|
|
|
switch (newwin.type) {
|
|
case Const.wintype_TextBuffer:
|
|
/* accum is a list of strings of a given style; newly-printed text
|
|
is pushed onto the list. accumstyle is the style of that text.
|
|
Anything printed in a different style (or hyperlink value)
|
|
triggers a call to gli_window_buffer_deaccumulate, which cleans
|
|
out accum and adds the results to the content array. The content
|
|
is in GlkOte format.
|
|
*/
|
|
newwin.accum = [];
|
|
newwin.accumstyle = null;
|
|
newwin.accumhyperlink = 0;
|
|
newwin.content = [];
|
|
newwin.clearcontent = false;
|
|
newwin.reserve = []; /* autosave of recent content */
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
/* lines is a list of line objects. A line looks like
|
|
{ chars: [...], styles: [...], hyperlinks: [...], dirty: bool }.
|
|
*/
|
|
newwin.gridwidth = 0;
|
|
newwin.gridheight = 0;
|
|
newwin.lines = [];
|
|
newwin.cursorx = 0;
|
|
newwin.cursory = 0;
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
if (!support.graphics) {
|
|
/* Graphics windows not supported; silently return null */
|
|
gli_delete_window(newwin);
|
|
return null;
|
|
}
|
|
newwin.content = [];
|
|
newwin.reserve = []; /* autosave of recent content */
|
|
break;
|
|
case Const.wintype_Blank:
|
|
break;
|
|
case Const.wintype_Pair:
|
|
throw('glk_window_open: cannot open pair window directly')
|
|
default:
|
|
/* Silently return null */
|
|
gli_delete_window(newwin);
|
|
return null;
|
|
}
|
|
|
|
if (!splitwin) {
|
|
gli_rootwin = newwin;
|
|
gli_window_rearrange(newwin, box);
|
|
}
|
|
else {
|
|
/* create pairwin, with newwin as the key */
|
|
pairwin = gli_new_window(Const.wintype_Pair, 0);
|
|
pairwin.pair_dir = method & Const.winmethod_DirMask;
|
|
pairwin.pair_division = method & Const.winmethod_DivisionMask;
|
|
pairwin.pair_key = newwin;
|
|
pairwin.pair_keydamage = false;
|
|
pairwin.pair_size = size;
|
|
pairwin.pair_hasborder = ((method & Const.winmethod_BorderMask) == Const.winmethod_Border);
|
|
pairwin.pair_vertical = (pairwin.pair_dir == Const.winmethod_Left || pairwin.pair_dir == Const.winmethod_Right);
|
|
pairwin.pair_backward = (pairwin.pair_dir == Const.winmethod_Left || pairwin.pair_dir == Const.winmethod_Above);
|
|
|
|
pairwin.child1 = splitwin;
|
|
pairwin.child2 = newwin;
|
|
splitwin.parent = pairwin;
|
|
newwin.parent = pairwin;
|
|
pairwin.parent = oldparent;
|
|
|
|
if (oldparent) {
|
|
if (oldparent.child1 == splitwin)
|
|
oldparent.child1 = pairwin;
|
|
else
|
|
oldparent.child2 = pairwin;
|
|
}
|
|
else {
|
|
gli_rootwin = pairwin;
|
|
}
|
|
|
|
gli_window_rearrange(pairwin, box);
|
|
}
|
|
|
|
return newwin;
|
|
}
|
|
|
|
function glk_window_close(win, statsref) {
|
|
if (!win)
|
|
throw('glk_window_close: invalid window');
|
|
|
|
if (win === gli_rootwin || !win.parent) {
|
|
/* close the root window, which means all windows. */
|
|
|
|
gli_rootwin = null;
|
|
|
|
/* begin (simpler) closation */
|
|
|
|
gli_stream_fill_result(win.str, statsref);
|
|
gli_window_close(win, true);
|
|
}
|
|
else {
|
|
/* have to jigger parent */
|
|
var pairwin, grandparwin, sibwin, box, wx, keydamage_flag;
|
|
|
|
pairwin = win.parent;
|
|
if (win === pairwin.child1)
|
|
sibwin = pairwin.child2;
|
|
else if (win === pairwin.child2)
|
|
sibwin = pairwin.child1;
|
|
else
|
|
throw('glk_window_close: window tree is corrupted');
|
|
|
|
box = pairwin.bbox;
|
|
|
|
grandparwin = pairwin.parent;
|
|
if (!grandparwin) {
|
|
gli_rootwin = sibwin;
|
|
sibwin.parent = null;
|
|
}
|
|
else {
|
|
if (grandparwin.child1 === pairwin)
|
|
grandparwin.child1 = sibwin;
|
|
else
|
|
grandparwin.child2 = sibwin;
|
|
sibwin.parent = grandparwin;
|
|
}
|
|
|
|
/* Begin closation */
|
|
|
|
gli_stream_fill_result(win.str, statsref);
|
|
|
|
/* Close the child window (and descendants), so that key-deletion can
|
|
crawl up the tree to the root window. */
|
|
gli_window_close(win, true);
|
|
|
|
/* This probably isn't necessary, but the child *is* gone, so just
|
|
in case. */
|
|
if (win === pairwin.child1) {
|
|
pairwin.child1 = null;
|
|
}
|
|
else if (win === pairwin.child2) {
|
|
pairwin.child2 = null;
|
|
}
|
|
|
|
/* Now we can delete the parent pair. */
|
|
gli_window_close(pairwin, false);
|
|
|
|
keydamage_flag = false;
|
|
for (wx=sibwin; wx; wx=wx.parent) {
|
|
if (wx.type == Const.wintype_Pair) {
|
|
if (wx.pair_keydamage) {
|
|
keydamage_flag = true;
|
|
wx.pair_keydamage = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (keydamage_flag) {
|
|
box = content_box;
|
|
gli_window_rearrange(gli_rootwin, box);
|
|
}
|
|
else {
|
|
gli_window_rearrange(sibwin, box);
|
|
}
|
|
}
|
|
}
|
|
|
|
function glk_window_get_size(win, widthref, heightref) {
|
|
if (!win)
|
|
throw('glk_window_get_size: invalid window');
|
|
|
|
var wid = 0;
|
|
var hgt = 0;
|
|
var boxwidth, boxheight;
|
|
|
|
switch (win.type) {
|
|
|
|
case Const.wintype_TextGrid:
|
|
boxwidth = win.bbox.right - win.bbox.left;
|
|
boxheight = win.bbox.bottom - win.bbox.top;
|
|
wid = Math.max(0, Math.floor((boxwidth-content_metrics.gridmarginx) / content_metrics.gridcharwidth));
|
|
hgt = Math.max(0, Math.floor((boxheight-content_metrics.gridmarginy) / content_metrics.gridcharheight));
|
|
break;
|
|
|
|
case Const.wintype_TextBuffer:
|
|
boxwidth = win.bbox.right - win.bbox.left;
|
|
boxheight = win.bbox.bottom - win.bbox.top;
|
|
wid = Math.max(0, Math.floor((boxwidth-content_metrics.buffermarginx) / content_metrics.buffercharwidth));
|
|
hgt = Math.max(0, Math.floor((boxheight-content_metrics.buffermarginy) / content_metrics.buffercharheight));
|
|
break;
|
|
|
|
case Const.wintype_Graphics:
|
|
boxwidth = win.bbox.right - win.bbox.left;
|
|
boxheight = win.bbox.bottom - win.bbox.top;
|
|
wid = boxwidth - content_metrics.graphicsmarginx;
|
|
hgt = boxheight - content_metrics.graphicsmarginy;
|
|
break;
|
|
}
|
|
|
|
if (widthref)
|
|
widthref.set_value(wid);
|
|
if (heightref)
|
|
heightref.set_value(hgt);
|
|
}
|
|
|
|
function glk_window_set_arrangement(win, method, size, keywin) {
|
|
var wx, newdir, newvertical, newbackward;
|
|
|
|
if (!win)
|
|
throw('glk_window_set_arrangement: invalid window');
|
|
if (win.type != Const.wintype_Pair)
|
|
throw('glk_window_set_arrangement: not a pair window');
|
|
|
|
if (keywin) {
|
|
if (keywin.type == Const.wintype_Pair)
|
|
throw('glk_window_set_arrangement: keywin cannot be a pair window');
|
|
for (wx=keywin; wx; wx=wx.parent) {
|
|
if (wx == win)
|
|
break;
|
|
}
|
|
if (!wx)
|
|
throw('glk_window_set_arrangement: keywin must be a descendant');
|
|
}
|
|
|
|
newdir = method & Const.winmethod_DirMask;
|
|
newvertical = (newdir == Const.winmethod_Left || newdir == Const.winmethod_Right);
|
|
newbackward = (newdir == Const.winmethod_Left || newdir == Const.winmethod_Above);
|
|
if (!keywin)
|
|
keywin = win.pair_key;
|
|
|
|
if (newvertical && !win.pair_vertical)
|
|
throw('glk_window_set_arrangement: split must stay horizontal');
|
|
if (!newvertical && win.pair_vertical)
|
|
throw('glk_window_set_arrangement: split must stay vertical');
|
|
|
|
if (keywin && keywin.type == Const.wintype_Blank
|
|
&& (method & Const.winmethod_DivisionMask) == Const.winmethod_Fixed)
|
|
throw('glk_window_set_arrangement: a blank window cannot have a fixed size');
|
|
|
|
if ((newbackward && !win.pair_backward) || (!newbackward && win.pair_backward)) {
|
|
/* switch the children */
|
|
wx = win.child1;
|
|
win.child1 = win.child2;
|
|
win.child2 = wx;
|
|
}
|
|
|
|
/* set up everything else */
|
|
win.pair_dir = newdir;
|
|
win.pair_division = (method & Const.winmethod_DivisionMask);
|
|
win.pair_key = keywin;
|
|
win.pair_size = size;
|
|
|
|
win.pair_hasborder = ((method & Const.winmethod_BorderMask) == Const.winmethod_Border);
|
|
win.pair_vertical = (win.pair_dir == Const.winmethod_Left || win.pair_dir == Const.winmethod_Right);
|
|
win.pair_backward = (win.pair_dir == Const.winmethod_Left || win.pair_dir == Const.winmethod_Above);
|
|
|
|
gli_window_rearrange(win, win.bbox);
|
|
}
|
|
|
|
function glk_window_get_arrangement(win, methodref, sizeref, keywinref) {
|
|
if (!win)
|
|
throw('glk_window_get_arrangement: invalid window');
|
|
if (win.type != Const.wintype_Pair)
|
|
throw('glk_window_get_arrangement: not a pair window');
|
|
|
|
if (sizeref)
|
|
sizeref.set_value(win.pair_size);
|
|
if (keywinref)
|
|
keywinref.set_value(win.pair_key);
|
|
if (methodref)
|
|
methodref.set_value(win.pair_dir | win.pair_division | (win.pair_hasborder ? Const.winmethod_Border : Const.winmethod_NoBorder));
|
|
}
|
|
|
|
function glk_window_get_type(win) {
|
|
if (!win)
|
|
throw('glk_window_get_type: invalid window');
|
|
return win.type;
|
|
}
|
|
|
|
function glk_window_get_parent(win) {
|
|
if (!win)
|
|
throw('glk_window_get_parent: invalid window');
|
|
return win.parent;
|
|
}
|
|
|
|
function glk_window_clear(win) {
|
|
var ix, cx, lineobj;
|
|
|
|
if (!win)
|
|
throw('glk_window_clear: invalid window');
|
|
|
|
if (win.line_request) {
|
|
throw('glk_window_clear: window has pending line request');
|
|
}
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
win.accum.length = 0;
|
|
win.accumstyle = null;
|
|
win.accumhyperlink = 0;
|
|
win.content.length = 0;
|
|
win.clearcontent = true;
|
|
break;
|
|
case Const.wintype_TextGrid:
|
|
win.cursorx = 0;
|
|
win.cursory = 0;
|
|
for (ix=0; ix<win.gridheight; ix++) {
|
|
lineobj = win.lines[ix];
|
|
lineobj.dirty = true;
|
|
for (cx=0; cx<win.gridwidth; cx++) {
|
|
lineobj.chars[cx] = ' ';
|
|
lineobj.styles[cx] = Const.style_Normal;
|
|
lineobj.hyperlinks[cx] = 0;
|
|
}
|
|
}
|
|
break;
|
|
case Const.wintype_Graphics:
|
|
/* If the background color has been set, we must retain that entry.
|
|
(The last setcolor, if there are several.) */
|
|
var setcol = null;
|
|
for (var ix=0; ix<win.content.length; ix++) {
|
|
if (win.content[ix].special == 'setcolor')
|
|
setcol = win.content[ix];
|
|
}
|
|
win.content.length = 0;
|
|
if (setcol !== null)
|
|
win.content.push(setcol);
|
|
win.content.push({ special: 'fill' }); /* clear to background color */
|
|
break;
|
|
}
|
|
}
|
|
|
|
function glk_window_move_cursor(win, xpos, ypos) {
|
|
if (!win)
|
|
throw('glk_window_move_cursor: invalid window');
|
|
|
|
if (win.type == Const.wintype_TextGrid) {
|
|
/* No bounds-checking; we canonicalize when we print. */
|
|
win.cursorx = xpos;
|
|
win.cursory = ypos;
|
|
}
|
|
else {
|
|
throw('glk_window_move_cursor: not a grid window');
|
|
}
|
|
}
|
|
|
|
function glk_window_get_stream(win) {
|
|
if (!win)
|
|
throw('glk_window_get_stream: invalid window');
|
|
return win.str;
|
|
}
|
|
|
|
function glk_window_set_echo_stream(win, str) {
|
|
if (!win)
|
|
throw('glk_window_set_echo_stream: invalid window');
|
|
win.echostr = str;
|
|
}
|
|
|
|
function glk_window_get_echo_stream(win) {
|
|
if (!win)
|
|
throw('glk_window_get_echo_stream: invalid window');
|
|
return win.echostr;
|
|
}
|
|
|
|
function glk_set_window(win) {
|
|
if (!win)
|
|
gli_currentstr = null;
|
|
else
|
|
gli_currentstr = win.str;
|
|
}
|
|
|
|
function glk_window_get_sibling(win) {
|
|
var parent, sib;
|
|
if (!win)
|
|
throw('glk_window_get_sibling: invalid window');
|
|
parent = win.parent;
|
|
if (!parent)
|
|
return null;
|
|
if (win === parent.child1)
|
|
return parent.child2;
|
|
else if (win === parent.child2)
|
|
return parent.child1;
|
|
else
|
|
throw('glk_window_get_sibling: window tree is corrupted');
|
|
}
|
|
|
|
function glk_stream_iterate(str, rockref) {
|
|
if (!str)
|
|
str = gli_streamlist;
|
|
else
|
|
str = str.next;
|
|
|
|
if (str) {
|
|
if (rockref)
|
|
rockref.set_value(str.rock);
|
|
return str;
|
|
}
|
|
|
|
if (rockref)
|
|
rockref.set_value(0);
|
|
return null;
|
|
}
|
|
|
|
function glk_stream_get_rock(str) {
|
|
if (!str)
|
|
throw('glk_stream_get_rock: invalid stream');
|
|
return str.rock;
|
|
}
|
|
|
|
function glk_stream_open_file(fref, fmode, rock) {
|
|
if (!fref)
|
|
throw('glk_stream_open_file: invalid fileref');
|
|
|
|
var str;
|
|
var fstream;
|
|
|
|
if (fmode != Const.filemode_Read
|
|
&& fmode != Const.filemode_Write
|
|
&& fmode != Const.filemode_ReadWrite
|
|
&& fmode != Const.filemode_WriteAppend)
|
|
throw('glk_stream_open_file: illegal filemode');
|
|
|
|
if (fmode == Const.filemode_Read && !Dialog.file_ref_exists(fref.ref))
|
|
return null;
|
|
|
|
if (!Dialog.streaming) {
|
|
var content = null;
|
|
if (fmode != Const.filemode_Write) {
|
|
content = Dialog.file_read(fref.ref);
|
|
}
|
|
if (content == null) {
|
|
content = [];
|
|
if (fmode != Const.filemode_Read) {
|
|
/* We just created this file. (Or perhaps we're in Write mode
|
|
and we're truncating.) Write immediately, to create it and
|
|
get the creation date right. */
|
|
Dialog.file_write(fref.ref, '', true);
|
|
}
|
|
}
|
|
if (content.length == null)
|
|
throw('glk_stream_open_file: data read had no length');
|
|
}
|
|
else {
|
|
fstream = Dialog.file_fopen(fmode, fref.ref);
|
|
if (!fstream)
|
|
return null;
|
|
}
|
|
|
|
str = gli_new_stream(strtype_File,
|
|
(fmode != Const.filemode_Write),
|
|
(fmode != Const.filemode_Read),
|
|
rock);
|
|
str.unicode = false;
|
|
str.isbinary = !fref.textmode;
|
|
str.ref = fref.ref;
|
|
str.origfmode = fmode;
|
|
|
|
if (!Dialog.streaming) {
|
|
str.streaming = false;
|
|
str.buf = content;
|
|
str.buflen = 0xFFFFFFFF; /* enormous */
|
|
if (fmode == Const.filemode_Write)
|
|
str.bufeof = 0;
|
|
else
|
|
str.bufeof = content.length;
|
|
if (fmode == Const.filemode_WriteAppend)
|
|
str.bufpos = str.bufeof;
|
|
else
|
|
str.bufpos = 0;
|
|
}
|
|
else {
|
|
str.streaming = true;
|
|
str.fstream = fstream;
|
|
/* We'll want a Buffer object around for short and writes. */
|
|
str.buffer4 = fstream.BufferClass.alloc(4);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_stream_open_memory(buf, fmode, rock) {
|
|
var str;
|
|
|
|
if (fmode != Const.filemode_Read
|
|
&& fmode != Const.filemode_Write
|
|
&& fmode != Const.filemode_ReadWrite)
|
|
throw('glk_stream_open_memory: illegal filemode');
|
|
|
|
str = gli_new_stream(strtype_Memory,
|
|
(fmode != Const.filemode_Write),
|
|
(fmode != Const.filemode_Read),
|
|
rock);
|
|
str.unicode = false;
|
|
|
|
if (buf) {
|
|
str.buf = buf;
|
|
str.buflen = buf.length;
|
|
str.bufpos = 0;
|
|
if (fmode == Const.filemode_Write)
|
|
str.bufeof = 0;
|
|
else
|
|
str.bufeof = str.buflen;
|
|
if (GiDispa)
|
|
GiDispa.retain_array(buf);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_stream_open_resource(filenum, rock) {
|
|
var str;
|
|
|
|
if (!GiLoad || !GiLoad.find_data_chunk)
|
|
return null;
|
|
var el = GiLoad.find_data_chunk(filenum);
|
|
if (!el)
|
|
return null;
|
|
|
|
var buf = el.data;
|
|
var isbinary = (el.type == 'BINA');
|
|
|
|
str = gli_new_stream(strtype_Resource,
|
|
true,
|
|
false,
|
|
rock);
|
|
str.unicode = false;
|
|
str.isbinary = isbinary;
|
|
|
|
str.resfilenum = filenum;
|
|
|
|
/* Resource streams always use buffer mode. */
|
|
str.streaming = false;
|
|
|
|
/* We have been handed an array of bytes. (They're big-endian four-byte
|
|
chunks, or perhaps a UTF-8 byte sequence, rather than native-endian
|
|
four-byte integers). We'll have to do the translation in the get()
|
|
functions. */
|
|
|
|
if (buf) {
|
|
str.buf = buf;
|
|
str.buflen = buf.length;
|
|
str.bufpos = 0;
|
|
str.bufeof = str.buflen;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_stream_open_resource_uni(filenum, rock) {
|
|
var str;
|
|
|
|
if (!GiLoad || !GiLoad.find_data_chunk)
|
|
return null;
|
|
var el = GiLoad.find_data_chunk(filenum);
|
|
if (!el)
|
|
return null;
|
|
|
|
var buf = el.data;
|
|
var isbinary = (el.type == 'BINA');
|
|
|
|
str = gli_new_stream(strtype_Resource,
|
|
true,
|
|
false,
|
|
rock);
|
|
str.unicode = true;
|
|
str.isbinary = isbinary;
|
|
|
|
str.resfilenum = filenum;
|
|
|
|
/* Resource streams always use buffer mode. */
|
|
str.streaming = false;
|
|
|
|
/* We have been handed an array of bytes. (They're big-endian four-byte
|
|
chunks, or perhaps a UTF-8 byte sequence, rather than native-endian
|
|
four-byte integers). We'll have to do the translation in the get()
|
|
functions. */
|
|
|
|
if (buf) {
|
|
str.buf = buf;
|
|
str.buflen = buf.length;
|
|
str.bufpos = 0;
|
|
str.bufeof = str.buflen;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_stream_close(str, result) {
|
|
if (!str)
|
|
throw('glk_stream_close: invalid stream');
|
|
|
|
if (str.type == strtype_Window)
|
|
throw('glk_stream_close: cannot close window stream');
|
|
|
|
if (str.type == strtype_File && str.writable) {
|
|
if (!str.streaming) {
|
|
if (!(str.timer_id === null)) {
|
|
clearTimeout(str.timer_id);
|
|
str.timer_id = null;
|
|
}
|
|
Dialog.file_write(str.ref, str.buf);
|
|
}
|
|
}
|
|
|
|
gli_stream_fill_result(str, result);
|
|
gli_delete_stream(str);
|
|
}
|
|
|
|
function glk_stream_set_position(str, pos, seekmode) {
|
|
if (!str)
|
|
throw('glk_stream_set_position: invalid stream');
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
str.fstream.fseek(pos, seekmode);
|
|
break;
|
|
}
|
|
//### check if file has been modified? This is a half-decent time.
|
|
/* fall through to memory... */
|
|
case strtype_Resource:
|
|
/* fall through to memory... */
|
|
case strtype_Memory:
|
|
if (seekmode == Const.seekmode_Current) {
|
|
pos = str.bufpos + pos;
|
|
}
|
|
else if (seekmode == Const.seekmode_End) {
|
|
pos = str.bufeof + pos;
|
|
}
|
|
else {
|
|
/* pos = pos */
|
|
}
|
|
if (pos < 0)
|
|
pos = 0;
|
|
if (pos > str.bufeof)
|
|
pos = str.bufeof;
|
|
str.bufpos = pos;
|
|
}
|
|
}
|
|
|
|
function glk_stream_get_position(str) {
|
|
if (!str)
|
|
throw('glk_stream_get_position: invalid stream');
|
|
|
|
switch (str.type) {
|
|
case strtype_File:
|
|
if (str.streaming) {
|
|
return str.fstream.ftell();
|
|
}
|
|
/* fall through to memory... */
|
|
case strtype_Resource:
|
|
/* fall through to memory... */
|
|
case strtype_Memory:
|
|
return str.bufpos;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function glk_stream_set_current(str) {
|
|
gli_currentstr = str;
|
|
}
|
|
|
|
function glk_stream_get_current() {
|
|
return gli_currentstr;
|
|
}
|
|
|
|
function glk_fileref_create_temp(usage, rock) {
|
|
var filetype = (usage & Const.fileusage_TypeMask);
|
|
var filetypename = FileTypeMap[filetype];
|
|
var ref = Dialog.file_construct_temp_ref(filetypename);
|
|
fref = gli_new_fileref(ref.filename, usage, rock, ref);
|
|
return fref;
|
|
}
|
|
|
|
function glk_fileref_create_by_name(usage, filename, rock) {
|
|
/* Filenames that do not come from the user must be cleaned up. */
|
|
filename = Dialog.file_clean_fixed_name(filename, (usage & Const.fileusage_TypeMask));
|
|
|
|
fref = gli_new_fileref(filename, usage, rock, null);
|
|
return fref;
|
|
}
|
|
|
|
function glk_fileref_create_by_prompt(usage, fmode, rock) {
|
|
var modename;
|
|
|
|
var filetype = (usage & Const.fileusage_TypeMask);
|
|
var filetypename = FileTypeMap[filetype];
|
|
if (!filetypename) {
|
|
filetypename = 'xxx';
|
|
}
|
|
|
|
switch (fmode) {
|
|
case Const.filemode_Write:
|
|
modename = 'write';
|
|
break;
|
|
case Const.filemode_ReadWrite:
|
|
modename = 'readwrite';
|
|
break;
|
|
case Const.filemode_WriteAppend:
|
|
modename = 'writeappend';
|
|
break;
|
|
case Const.filemode_Read:
|
|
default:
|
|
modename = 'read';
|
|
break;
|
|
}
|
|
|
|
var special = {
|
|
type: 'fileref_prompt',
|
|
filetype: filetypename,
|
|
filemode: modename
|
|
};
|
|
var callback = {
|
|
usage: usage,
|
|
rock: rock
|
|
};
|
|
|
|
if (filetype == Const.fileusage_SavedGame)
|
|
special.gameid = VM.get_signature();
|
|
|
|
ui_specialinput = special;
|
|
ui_specialcallback = callback;
|
|
gli_selectref = null;
|
|
return DidNotReturn;
|
|
}
|
|
|
|
function gli_fileref_create_by_prompt_callback(obj) {
|
|
var ref = obj.value;
|
|
var usage = ui_specialcallback.usage;
|
|
var rock = ui_specialcallback.rock;
|
|
|
|
var fref = null;
|
|
if (ref) {
|
|
fref = gli_new_fileref(ref.filename, usage, rock, ref);
|
|
}
|
|
|
|
// If reading a file which doesn't exist, return null
|
|
if ( ui_specialinput.filemode === 'read' && !Dialog.file_ref_exists( fref.ref ) )
|
|
{
|
|
glk_fileref_destroy( fref );
|
|
fref = null;
|
|
}
|
|
|
|
ui_specialinput = null;
|
|
ui_specialcallback = null;
|
|
|
|
if (GiDispa)
|
|
GiDispa.prepare_resume(fref);
|
|
VM.resume(fref);
|
|
}
|
|
|
|
function glk_fileref_destroy(fref) {
|
|
if (!fref)
|
|
throw('glk_fileref_destroy: invalid fileref');
|
|
gli_delete_fileref(fref);
|
|
}
|
|
|
|
function glk_fileref_iterate(fref, rockref) {
|
|
if (!fref)
|
|
fref = gli_filereflist;
|
|
else
|
|
fref = fref.next;
|
|
|
|
if (fref) {
|
|
if (rockref)
|
|
rockref.set_value(fref.rock);
|
|
return fref;
|
|
}
|
|
|
|
if (rockref)
|
|
rockref.set_value(0);
|
|
return null;
|
|
}
|
|
|
|
function glk_fileref_get_rock(fref) {
|
|
if (!fref)
|
|
throw('glk_fileref_get_rock: invalid fileref');
|
|
return fref.rock;
|
|
}
|
|
|
|
function glk_fileref_delete_file(fref) {
|
|
if (!fref)
|
|
throw('glk_fileref_delete_file: invalid fileref');
|
|
Dialog.file_remove_ref(fref.ref);
|
|
}
|
|
|
|
function glk_fileref_does_file_exist(fref) {
|
|
if (!fref)
|
|
throw('glk_fileref_does_file_exist: invalid fileref');
|
|
if (Dialog.file_ref_exists(fref.ref))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
function glk_fileref_create_from_fileref(usage, oldfref, rock) {
|
|
if (!oldfref)
|
|
throw('glk_fileref_create_from_fileref: invalid fileref');
|
|
|
|
var fref = gli_new_fileref(oldfref.filename, usage, rock, null);
|
|
return fref;
|
|
}
|
|
|
|
function glk_put_char(ch) {
|
|
gli_put_char(gli_currentstr, ch & 0xFF);
|
|
}
|
|
|
|
function glk_put_char_stream(str, ch) {
|
|
gli_put_char(str, ch & 0xFF);
|
|
}
|
|
|
|
function glk_put_string(val) {
|
|
glk_put_jstring_stream(gli_currentstr, val, true);
|
|
}
|
|
|
|
function glk_put_string_stream(str, val) {
|
|
glk_put_jstring_stream(str, val, true);
|
|
}
|
|
|
|
function glk_put_buffer(arr) {
|
|
arr = TrimArrayToBytes(arr);
|
|
gli_put_array(gli_currentstr, arr, true);
|
|
}
|
|
|
|
function glk_put_buffer_stream(str, arr) {
|
|
arr = TrimArrayToBytes(arr);
|
|
gli_put_array(str, arr, true);
|
|
}
|
|
|
|
function glk_set_style(val) {
|
|
gli_set_style(gli_currentstr, val);
|
|
}
|
|
|
|
function glk_set_style_stream(str, val) {
|
|
gli_set_style(str, val);
|
|
}
|
|
|
|
function glk_get_char_stream(str) {
|
|
if (!str)
|
|
throw('glk_get_char_stream: invalid stream');
|
|
return gli_get_char(str, false);
|
|
}
|
|
|
|
function glk_get_line_stream(str, buf) {
|
|
if (!str)
|
|
throw('glk_get_line_stream: invalid stream');
|
|
return gli_get_line(str, buf, false);
|
|
}
|
|
|
|
function glk_get_buffer_stream(str, buf) {
|
|
if (!str)
|
|
throw('glk_get_buffer_stream: invalid stream');
|
|
return gli_get_buffer(str, buf, false);
|
|
}
|
|
|
|
function glk_char_to_lower(val) {
|
|
if (val >= 0x41 && val <= 0x5A)
|
|
return val + 0x20;
|
|
if (val >= 0xC0 && val <= 0xDE && val != 0xD7)
|
|
return val + 0x20;
|
|
return val;
|
|
}
|
|
|
|
function glk_char_to_upper(val) {
|
|
if (val >= 0x61 && val <= 0x7A)
|
|
return val - 0x20;
|
|
if (val >= 0xE0 && val <= 0xFE && val != 0xF7)
|
|
return val - 0x20;
|
|
return val;
|
|
}
|
|
|
|
/* Style hints are not supported. We will use the new style system. */
|
|
function glk_stylehint_set(wintype, styl, hint, value) { }
|
|
function glk_stylehint_clear(wintype, styl, hint) { }
|
|
function glk_style_distinguish(win, styl1, styl2) {
|
|
return 0;
|
|
}
|
|
function glk_style_measure(win, styl, hint, resultref) {
|
|
if (resultref)
|
|
resultref.set_value(0);
|
|
return 0;
|
|
}
|
|
|
|
function glk_select(eventref) {
|
|
gli_selectref = eventref;
|
|
return DidNotReturn;
|
|
}
|
|
|
|
function glk_select_poll(eventref) {
|
|
/* Because the Javascript interpreter is single-threaded, we cannot
|
|
have gotten a timer event since the last glk_select call. */
|
|
|
|
eventref.set_field(0, Const.evtype_None);
|
|
eventref.set_field(1, null);
|
|
eventref.set_field(2, 0);
|
|
eventref.set_field(3, 0);
|
|
|
|
if (gli_timer_interval) {
|
|
var now = Date.now();
|
|
if (now - gli_timer_started > gli_timer_interval) {
|
|
/* We're past the timer interval, even though we got no
|
|
event. Let's pretend we did, reset it, and return a
|
|
timer event. */
|
|
gli_timer_started = Date.now();
|
|
/* Resend timer request at next update. */
|
|
gli_timer_lastsent = null;
|
|
|
|
eventref.set_field(0, Const.evtype_Timer);
|
|
}
|
|
}
|
|
}
|
|
|
|
function glk_request_line_event(win, buf, initlen) {
|
|
if (!win)
|
|
throw('glk_request_line_event: invalid window');
|
|
if (win.char_request || win.line_request)
|
|
throw('glk_request_line_event: window already has keyboard request');
|
|
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
if (initlen) {
|
|
/* This will be copied into the next update. */
|
|
var ls = buf.slice(0, initlen);
|
|
if (!current_partial_outputs)
|
|
current_partial_outputs = {};
|
|
current_partial_outputs[win.disprock] = ByteArrayToString(ls);
|
|
}
|
|
win.line_request = true;
|
|
win.line_request_uni = false;
|
|
if (win.type == Const.wintype_TextBuffer)
|
|
win.request_echo_line_input = win.echo_line_input;
|
|
else
|
|
win.request_echo_line_input = true;
|
|
win.input_generation = event_generation;
|
|
win.linebuf = buf;
|
|
if (GiDispa)
|
|
GiDispa.retain_array(buf);
|
|
}
|
|
else {
|
|
throw('glk_request_line_event: window does not support keyboard input');
|
|
}
|
|
}
|
|
|
|
function glk_cancel_line_event(win, eventref) {
|
|
if (!win)
|
|
throw('glk_cancel_line_event: invalid window');
|
|
|
|
if (!win.line_request) {
|
|
if (eventref) {
|
|
eventref.set_field(0, Const.evtype_None);
|
|
eventref.set_field(1, null);
|
|
eventref.set_field(2, 0);
|
|
eventref.set_field(3, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
var input = "";
|
|
var ix, val;
|
|
|
|
if (current_partial_inputs) {
|
|
val = current_partial_inputs[win.disprock];
|
|
if (val)
|
|
input = val;
|
|
}
|
|
|
|
if (input.length > win.linebuf.length)
|
|
input = input.slice(0, win.linebuf.length);
|
|
|
|
if (win.request_echo_line_input) {
|
|
ix = win.style;
|
|
gli_set_style(win.str, Const.style_Input);
|
|
gli_window_put_string(win, input);
|
|
if (win.echostr)
|
|
glk_put_jstring_stream(win.echostr, input);
|
|
gli_set_style(win.str, ix);
|
|
gli_window_put_string(win, "\n");
|
|
if (win.echostr)
|
|
glk_put_jstring_stream(win.echostr, "\n");
|
|
}
|
|
|
|
for (ix=0; ix<input.length; ix++)
|
|
win.linebuf[ix] = input.charCodeAt(ix);
|
|
|
|
if (eventref) {
|
|
eventref.set_field(0, Const.evtype_LineInput);
|
|
eventref.set_field(1, win);
|
|
eventref.set_field(2, input.length);
|
|
eventref.set_field(3, 0);
|
|
}
|
|
|
|
if (GiDispa)
|
|
GiDispa.unretain_array(win.linebuf);
|
|
win.line_request = false;
|
|
win.line_request_uni = false;
|
|
win.request_echo_line_input = null;
|
|
win.input_generation = null;
|
|
win.linebuf = null;
|
|
}
|
|
|
|
function glk_request_char_event(win) {
|
|
if (!win)
|
|
throw('glk_request_char_event: invalid window');
|
|
if (win.char_request || win.line_request)
|
|
throw('glk_request_char_event: window already has keyboard request');
|
|
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
win.char_request = true;
|
|
win.char_request_uni = false;
|
|
win.input_generation = event_generation;
|
|
}
|
|
else {
|
|
/* ### wintype_Graphics could accept char input if we set up the focus to allow it. See gestalt_GraphicsCharInput. */
|
|
throw('glk_request_char_event: window does not support keyboard input');
|
|
}
|
|
}
|
|
|
|
function glk_cancel_char_event(win) {
|
|
if (!win)
|
|
throw('glk_cancel_char_event: invalid window');
|
|
|
|
win.char_request = false;
|
|
win.char_request_uni = false;
|
|
}
|
|
|
|
function glk_set_echo_line_event(win, val) {
|
|
if (!win)
|
|
throw('glk_set_echo_line_event: invalid window');
|
|
|
|
win.echo_line_input = (val != 0);
|
|
}
|
|
|
|
function glk_set_terminators_line_event(win, arr) {
|
|
if (!win)
|
|
throw('glk_set_terminators_line_event: invalid window');
|
|
|
|
if (KeystrokeValueMap === null) {
|
|
/* First, we have to build this map. (It's only used by this
|
|
function, which is why the constructor code is here. */
|
|
KeystrokeValueMap = {};
|
|
for (var val in KeystrokeNameMap) {
|
|
KeystrokeValueMap[KeystrokeNameMap[val]] = val;
|
|
}
|
|
}
|
|
|
|
var res = [];
|
|
if (arr) {
|
|
for (var ix=0; ix<arr.length; ix++) {
|
|
var val = KeystrokeValueMap[arr[ix]];
|
|
if (val)
|
|
res.push(val);
|
|
}
|
|
}
|
|
win.line_input_terminators = res;
|
|
}
|
|
|
|
function glk_request_mouse_event(win) {
|
|
if (!win)
|
|
throw('glk_request_mouse_event: invalid window');
|
|
if (win.type == Const.wintype_TextGrid
|
|
|| win.type == Const.wintype_Graphics) {
|
|
win.mouse_request = true;
|
|
}
|
|
/* else ignore request */
|
|
}
|
|
|
|
function glk_cancel_mouse_event(win) {
|
|
if (!win)
|
|
throw('glk_cancel_mouse_event: invalid window');
|
|
win.mouse_request = false;
|
|
}
|
|
|
|
function glk_request_timer_events(msec) {
|
|
if (!msec) {
|
|
gli_timer_interval = null;
|
|
gli_timer_started = null;
|
|
}
|
|
else {
|
|
gli_timer_interval = msec;
|
|
gli_timer_started = Date.now();
|
|
}
|
|
}
|
|
|
|
/* Graphics functions. */
|
|
|
|
function glk_image_get_info(imgid, widthref, heightref) {
|
|
if (!GiLoad || !GiLoad.get_image_info)
|
|
return null;
|
|
|
|
var info = GiLoad.get_image_info(imgid);
|
|
if (info) {
|
|
if (widthref)
|
|
widthref.set_value(info.width);
|
|
if (heightref)
|
|
heightref.set_value(info.height);
|
|
return 1;
|
|
}
|
|
if (widthref)
|
|
widthref.set_value(0);
|
|
if (heightref)
|
|
heightref.set_value(0);
|
|
return 0;
|
|
}
|
|
|
|
function glk_image_draw(win, imgid, val1, val2) {
|
|
if (!win)
|
|
throw('glk_image_draw: invalid window');
|
|
|
|
if (!GiLoad || !GiLoad.get_image_info)
|
|
return 0;
|
|
var info = GiLoad.get_image_info(imgid);
|
|
if (!info)
|
|
return 0;
|
|
|
|
var img = { special:'image', image:imgid,
|
|
url:info.url, alttext:info.alttext,
|
|
width:info.width, height:info.height };
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
var alignment = 'inlineup';
|
|
switch (val1) {
|
|
case Const.imagealign_InlineUp:
|
|
alignment = 'inlineup';
|
|
break;
|
|
case Const.imagealign_InlineDown:
|
|
alignment = 'inlinedown';
|
|
break;
|
|
case Const.imagealign_InlineCenter:
|
|
alignment = 'inlinecenter';
|
|
break;
|
|
case Const.imagealign_MarginLeft:
|
|
alignment = 'marginleft';
|
|
break;
|
|
case Const.imagealign_MarginRight:
|
|
alignment = 'marginright';
|
|
break;
|
|
}
|
|
img.alignment = alignment;
|
|
if (win.hyperlink)
|
|
img.hyperlink = win.hyperlink;
|
|
gli_window_buffer_put_special(win, img);
|
|
return 1;
|
|
|
|
case Const.wintype_Graphics:
|
|
img.x = val1;
|
|
img.y = val2;
|
|
win.content.push(img);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function glk_image_draw_scaled(win, imgid, val1, val2, width, height) {
|
|
if (!win)
|
|
throw('glk_image_draw_scaled: invalid window');
|
|
|
|
if (!GiLoad || !GiLoad.get_image_info)
|
|
return 0;
|
|
var info = GiLoad.get_image_info(imgid);
|
|
if (!info)
|
|
return 0;
|
|
|
|
/* Same as above, except we use the passed-in width and height
|
|
values */
|
|
var img = { special:'image', image:imgid,
|
|
url:info.url, alttext:info.alttext,
|
|
width:width, height:height };
|
|
|
|
switch (win.type) {
|
|
case Const.wintype_TextBuffer:
|
|
var alignment = 'inlineup';
|
|
switch (val1) {
|
|
case Const.imagealign_InlineUp:
|
|
alignment = 'inlineup';
|
|
break;
|
|
case Const.imagealign_InlineDown:
|
|
alignment = 'inlinedown';
|
|
break;
|
|
case Const.imagealign_InlineCenter:
|
|
alignment = 'inlinecenter';
|
|
break;
|
|
case Const.imagealign_MarginLeft:
|
|
alignment = 'marginleft';
|
|
break;
|
|
case Const.imagealign_MarginRight:
|
|
alignment = 'marginright';
|
|
break;
|
|
}
|
|
img.alignment = alignment;
|
|
if (win.hyperlink)
|
|
img.hyperlink = win.hyperlink;
|
|
gli_window_buffer_put_special(win, img);
|
|
return 1;
|
|
|
|
case Const.wintype_Graphics:
|
|
img.x = val1;
|
|
img.y = val2;
|
|
/* width, height already set */
|
|
win.content.push(img);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function glk_window_flow_break(win) {
|
|
if (!win)
|
|
throw('glk_window_flow_break: invalid window');
|
|
|
|
if (win.type == Const.wintype_TextBuffer)
|
|
gli_window_buffer_put_special(win, undefined, true);
|
|
}
|
|
|
|
function glk_window_erase_rect(win, left, top, width, height) {
|
|
if (!win)
|
|
throw('glk_window_erase_rect: invalid window');
|
|
if (win.type != Const.wintype_Graphics)
|
|
throw('glk_window_erase_rect: not a graphics window');
|
|
|
|
win.content.push({ special:'fill', x:left, y:top, width:width, height:height });
|
|
}
|
|
|
|
function glk_window_fill_rect(win, color, left, top, width, height) {
|
|
if (!win)
|
|
throw('glk_window_fill_rect: invalid window');
|
|
if (win.type != Const.wintype_Graphics)
|
|
throw('glk_window_fill_rect: not a graphics window');
|
|
|
|
var colstr = gli_color_to_css(color);
|
|
win.content.push({ special:'fill', color:colstr, x:left, y:top, width:width, height:height });
|
|
}
|
|
|
|
function glk_window_set_background_color(win, color) {
|
|
if (!win)
|
|
throw('glk_window_set_background_color: invalid window');
|
|
if (win.type != Const.wintype_Graphics)
|
|
throw('glk_window_set_background_color: not a graphics window');
|
|
|
|
var colstr = gli_color_to_css(color);
|
|
win.content.push({ special:'setcolor', color:colstr });
|
|
}
|
|
|
|
/* Convert a Glk numeric color value to a CSS-compatible string.
|
|
*/
|
|
function gli_color_to_css(color) {
|
|
var res = (color & 0xFFFFFF).toString(16);
|
|
while (res.length < 6) {
|
|
res = '0' + res;
|
|
}
|
|
return '#' + res.toUpperCase();
|
|
}
|
|
|
|
function glk_schannel_iterate(schan, rockref) {
|
|
if (!schan)
|
|
schan = gli_schannellist;
|
|
else
|
|
schan = schan.next;
|
|
|
|
if (schan) {
|
|
if (rockref)
|
|
rockref.set_value(schan.rock);
|
|
return schan;
|
|
}
|
|
|
|
if (rockref)
|
|
rockref.set_value(0);
|
|
return null;
|
|
}
|
|
|
|
function glk_schannel_get_rock(schan) {
|
|
if (!schan)
|
|
throw('glk_schannel_get_rock: invalid schannel');
|
|
return schan.rock;
|
|
}
|
|
|
|
function glk_schannel_create(rock) {
|
|
return null;
|
|
}
|
|
|
|
function glk_schannel_destroy(schan) {
|
|
throw('glk_schannel_destroy: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_play(schan, sndid) {
|
|
throw('glk_schannel_play: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_play_ext(schan, sndid, repeats, notify) {
|
|
throw('glk_schannel_play_ext: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_stop(schan) {
|
|
throw('glk_schannel_stop: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_set_volume(schan, vol) {
|
|
throw('glk_schannel_set_volume: invalid schannel');
|
|
}
|
|
|
|
function glk_sound_load_hint(sndid, flag) {
|
|
}
|
|
|
|
function glk_schannel_create_ext(rock, vol) {
|
|
return null;
|
|
}
|
|
|
|
function glk_schannel_play_multi(schans, sndids, notify) {
|
|
throw('glk_schannel_play_multi: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_pause(schan) {
|
|
throw('glk_schannel_pause: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_unpause(schan) {
|
|
throw('glk_schannel_unpause: invalid schannel');
|
|
}
|
|
|
|
function glk_schannel_set_volume_ext(schan, vol, duration, notify) {
|
|
throw('glk_schannel_set_volume_ext: invalid schannel');
|
|
}
|
|
|
|
function glk_set_hyperlink(val) {
|
|
gli_set_hyperlink(gli_currentstr, val);
|
|
}
|
|
|
|
function glk_set_hyperlink_stream(str, val) {
|
|
gli_set_hyperlink(str, val);
|
|
}
|
|
|
|
function glk_request_hyperlink_event(win) {
|
|
if (!win)
|
|
throw('glk_request_hyperlink_event: invalid window');
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
win.hyperlink_request = true;
|
|
}
|
|
}
|
|
|
|
function glk_cancel_hyperlink_event(win) {
|
|
if (!win)
|
|
throw('glk_cancel_hyperlink_event: invalid window');
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
win.hyperlink_request = false;
|
|
}
|
|
}
|
|
|
|
function glk_buffer_to_lower_case_uni(arr, numchars) {
|
|
var ix, jx, pos, val, origval;
|
|
var arrlen = arr.length;
|
|
var src = arr.slice(0, numchars);
|
|
|
|
if (arrlen < numchars)
|
|
throw('buffer_to_lower_case_uni: numchars exceeds array length');
|
|
|
|
pos = 0;
|
|
for (ix=0; ix<numchars; ix++) {
|
|
origval = src[ix];
|
|
val = unicode_lower_table[origval];
|
|
if (val === undefined) {
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
else if (!(val instanceof Array)) {
|
|
arr[pos] = val;
|
|
pos++;
|
|
}
|
|
else {
|
|
for (jx=0; jx<val.length; jx++) {
|
|
arr[pos] = val[jx];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* in case we stretched the array */
|
|
arr.length = arrlen;
|
|
|
|
return pos;
|
|
}
|
|
|
|
function glk_buffer_to_upper_case_uni(arr, numchars) {
|
|
var ix, jx, pos, val, origval;
|
|
var arrlen = arr.length;
|
|
var src = arr.slice(0, numchars);
|
|
|
|
if (arrlen < numchars)
|
|
throw('buffer_to_upper_case_uni: numchars exceeds array length');
|
|
|
|
pos = 0;
|
|
for (ix=0; ix<numchars; ix++) {
|
|
origval = src[ix];
|
|
val = unicode_upper_table[origval];
|
|
if (val === undefined) {
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
else if (!(val instanceof Array)) {
|
|
arr[pos] = val;
|
|
pos++;
|
|
}
|
|
else {
|
|
for (jx=0; jx<val.length; jx++) {
|
|
arr[pos] = val[jx];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* in case we stretched the array */
|
|
arr.length = arrlen;
|
|
|
|
return pos;
|
|
}
|
|
|
|
function glk_buffer_to_title_case_uni(arr, numchars, lowerrest) {
|
|
var ix, jx, pos, val, origval;
|
|
var arrlen = arr.length;
|
|
var src = arr.slice(0, numchars);
|
|
|
|
if (arrlen < numchars)
|
|
throw('buffer_to_title_case_uni: numchars exceeds array length');
|
|
|
|
pos = 0;
|
|
|
|
if (numchars == 0)
|
|
return 0;
|
|
|
|
ix = 0;
|
|
{
|
|
origval = src[ix];
|
|
val = unicode_title_table[origval];
|
|
if (val === undefined) {
|
|
val = unicode_upper_table[origval];
|
|
}
|
|
if (val === undefined) {
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
else if (!(val instanceof Array)) {
|
|
arr[pos] = val;
|
|
pos++;
|
|
}
|
|
else {
|
|
for (jx=0; jx<val.length; jx++) {
|
|
arr[pos] = val[jx];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!lowerrest) {
|
|
for (ix=1; ix<numchars; ix++) {
|
|
origval = src[ix];
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
}
|
|
else {
|
|
for (ix=1; ix<numchars; ix++) {
|
|
origval = src[ix];
|
|
val = unicode_lower_table[origval];
|
|
if (val === undefined) {
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
else if (!(val instanceof Array)) {
|
|
arr[pos] = val;
|
|
pos++;
|
|
}
|
|
else {
|
|
for (jx=0; jx<val.length; jx++) {
|
|
arr[pos] = val[jx];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* in case we stretched the array */
|
|
arr.length = arrlen;
|
|
|
|
return pos;
|
|
}
|
|
|
|
function gli_buffer_canon_decompose_uni(arr, numchars) {
|
|
/* This is a utility function to decompose an array. The behavior is
|
|
almost the same as glk_buffer_canon_decompose_uni(), except that
|
|
this *doesn't* trim the array down to its original length. That
|
|
is, this decomposition can cause the array to grow. */
|
|
|
|
/* The algorithm for the canonical decomposition of a string: For
|
|
each character, look up the decomposition in the decomp table.
|
|
Append the decomposition to the buffer. Finally, sort every
|
|
substring of the buffer which is made up of combining
|
|
characters (characters with a nonzero combining class). */
|
|
|
|
var src = arr.slice(0, numchars);
|
|
var pos, ix, jx, origval, val;
|
|
var grpstart, grpend, kx, tmp;
|
|
|
|
pos = 0;
|
|
for (ix=0; ix<numchars; ix++) {
|
|
origval = src[ix];
|
|
val = unicode_decomp_table[origval];
|
|
if (val === undefined) {
|
|
arr[pos] = origval;
|
|
pos++;
|
|
}
|
|
else if (!(val instanceof Array)) {
|
|
arr[pos] = val;
|
|
pos++;
|
|
}
|
|
else {
|
|
for (jx=0; jx<val.length; jx++) {
|
|
arr[pos] = val[jx];
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now we sort groups of combining characters. This should be a
|
|
stable sort by the combining-class number. We're lazy and
|
|
nearly all groups are short, so we'll just bubble-sort. */
|
|
ix = 0;
|
|
while (ix < pos) {
|
|
if (!unicode_combin_table[arr[ix]]) {
|
|
ix++;
|
|
continue;
|
|
}
|
|
if (ix >= pos)
|
|
break;
|
|
grpstart = ix;
|
|
while (ix < pos && unicode_combin_table[arr[ix]])
|
|
ix++;
|
|
grpend = ix;
|
|
if (grpend - grpstart >= 2) {
|
|
/* Sort this group. */
|
|
for (jx = grpend-1; jx > grpstart; jx--) {
|
|
for (kx = grpstart; kx < jx; kx++) {
|
|
if (unicode_combin_table[arr[kx]] > unicode_combin_table[arr[kx+1]]) {
|
|
tmp = arr[kx];
|
|
arr[kx] = arr[kx+1];
|
|
arr[kx+1] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
function gli_buffer_canon_compose_uni(arr, numchars) {
|
|
/* The algorithm for canonically composing characters in a string:
|
|
for each base character, compare it to all the following
|
|
combining characters (up to the next base character). If they're
|
|
composable, compose them. Repeat until no more pairs are found. */
|
|
|
|
var ix, jx, curch, newch, curclass, newclass, map, pos;
|
|
|
|
if (numchars == 0)
|
|
return 0;
|
|
|
|
pos = 0;
|
|
curch = arr[0];
|
|
curclass = unicode_combin_table[curch];
|
|
if (curclass)
|
|
curclass = 999; // just in case the first character is a combiner
|
|
ix = 1;
|
|
jx = ix;
|
|
while (true) {
|
|
if (jx >= numchars) {
|
|
arr[pos] = curch;
|
|
pos = ix;
|
|
break;
|
|
}
|
|
newch = arr[jx];
|
|
newclass = unicode_combin_table[newch];
|
|
map = unicode_compo_table[curch];
|
|
if (map !== undefined && map[newch] !== undefined
|
|
&& (!curclass || (newclass && curclass < newclass))) {
|
|
curch = map[newch];
|
|
arr[pos] = curch;
|
|
}
|
|
else {
|
|
if (!newclass) {
|
|
pos = ix;
|
|
curch = newch;
|
|
}
|
|
curclass = newclass;
|
|
arr[ix] = newch;
|
|
ix++;
|
|
}
|
|
jx++;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
function glk_buffer_canon_decompose_uni(arr, numchars) {
|
|
var arrlen = arr.length;
|
|
var len;
|
|
|
|
len = gli_buffer_canon_decompose_uni(arr, numchars);
|
|
|
|
/* in case we stretched the array */
|
|
arr.length = arrlen;
|
|
|
|
return len;
|
|
}
|
|
|
|
function glk_buffer_canon_normalize_uni(arr, numchars) {
|
|
var arrlen = arr.length;
|
|
var len;
|
|
|
|
len = gli_buffer_canon_decompose_uni(arr, numchars);
|
|
len = gli_buffer_canon_compose_uni(arr, len);
|
|
|
|
/* in case we stretched the array */
|
|
arr.length = arrlen;
|
|
|
|
return len;
|
|
}
|
|
|
|
function glk_put_char_uni(ch) {
|
|
gli_put_char(gli_currentstr, ch);
|
|
}
|
|
|
|
function glk_put_string_uni(val) {
|
|
glk_put_jstring_stream(gli_currentstr, val, false);
|
|
}
|
|
|
|
function glk_put_buffer_uni(arr) {
|
|
gli_put_array(gli_currentstr, arr, false);
|
|
}
|
|
|
|
function glk_put_char_stream_uni(str, ch) {
|
|
gli_put_char(str, ch);
|
|
}
|
|
|
|
function glk_put_string_stream_uni(str, val) {
|
|
glk_put_jstring_stream(str, val, false);
|
|
}
|
|
|
|
function glk_put_buffer_stream_uni(str, arr) {
|
|
gli_put_array(str, arr, false);
|
|
}
|
|
|
|
function glk_get_char_stream_uni(str) {
|
|
if (!str)
|
|
throw('glk_get_char_stream_uni: invalid stream');
|
|
return gli_get_char(str, true);
|
|
}
|
|
|
|
function glk_get_buffer_stream_uni(str, buf) {
|
|
if (!str)
|
|
throw('glk_get_buffer_stream_uni: invalid stream');
|
|
return gli_get_buffer(str, buf, true);
|
|
}
|
|
|
|
function glk_get_line_stream_uni(str, buf) {
|
|
if (!str)
|
|
throw('glk_get_line_stream_uni: invalid stream');
|
|
return gli_get_line(str, buf, true);
|
|
}
|
|
|
|
function glk_stream_open_file_uni(fref, fmode, rock) {
|
|
if (!fref)
|
|
throw('glk_stream_open_file_uni: invalid fileref');
|
|
|
|
var str;
|
|
var fstream;
|
|
|
|
if (fmode != Const.filemode_Read
|
|
&& fmode != Const.filemode_Write
|
|
&& fmode != Const.filemode_ReadWrite
|
|
&& fmode != Const.filemode_WriteAppend)
|
|
throw('glk_stream_open_file_uni: illegal filemode');
|
|
|
|
if (fmode == Const.filemode_Read && !Dialog.file_ref_exists(fref.ref))
|
|
return null;
|
|
|
|
if (!Dialog.streaming) {
|
|
var content = null;
|
|
if (fmode != Const.filemode_Write) {
|
|
content = Dialog.file_read(fref.ref);
|
|
}
|
|
if (content == null) {
|
|
content = [];
|
|
if (fmode != Const.filemode_Read) {
|
|
/* We just created this file. (Or perhaps we're in Write mode
|
|
and we're truncating.) Write immediately, to create it and
|
|
get the creation date right. */
|
|
Dialog.file_write(fref.ref, '', true);
|
|
}
|
|
}
|
|
if (content.length == null)
|
|
throw('glk_stream_open_file_uni: data read had no length');
|
|
}
|
|
else {
|
|
fstream = Dialog.file_fopen(fmode, fref.ref);
|
|
if (!fstream)
|
|
return null;
|
|
}
|
|
|
|
str = gli_new_stream(strtype_File,
|
|
(fmode != Const.filemode_Write),
|
|
(fmode != Const.filemode_Read),
|
|
rock);
|
|
str.unicode = true;
|
|
str.isbinary = !fref.textmode;
|
|
str.ref = fref.ref;
|
|
str.origfmode = fmode;
|
|
|
|
if (!Dialog.streaming) {
|
|
str.streaming = false;
|
|
str.buf = content;
|
|
str.buflen = 0xFFFFFFFF; /* enormous */
|
|
if (fmode == Const.filemode_Write)
|
|
str.bufeof = 0;
|
|
else
|
|
str.bufeof = content.length;
|
|
if (fmode == Const.filemode_WriteAppend)
|
|
str.bufpos = str.bufeof;
|
|
else
|
|
str.bufpos = 0;
|
|
}
|
|
else {
|
|
str.streaming = true;
|
|
str.fstream = fstream;
|
|
/* We'll want a Buffer object around for short and writes. */
|
|
str.buffer4 = fstream.BufferClass.alloc(4);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_stream_open_memory_uni(buf, fmode, rock) {
|
|
var str;
|
|
|
|
if (fmode != Const.filemode_Read
|
|
&& fmode != Const.filemode_Write
|
|
&& fmode != Const.filemode_ReadWrite)
|
|
throw('glk_stream_open_memory: illegal filemode');
|
|
|
|
str = gli_new_stream(strtype_Memory,
|
|
(fmode != Const.filemode_Write),
|
|
(fmode != Const.filemode_Read),
|
|
rock);
|
|
str.unicode = true;
|
|
|
|
if (buf) {
|
|
str.buf = buf;
|
|
str.buflen = buf.length;
|
|
str.bufpos = 0;
|
|
if (fmode == Const.filemode_Write)
|
|
str.bufeof = 0;
|
|
else
|
|
str.bufeof = str.buflen;
|
|
if (GiDispa)
|
|
GiDispa.retain_array(buf);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
function glk_request_char_event_uni(win) {
|
|
if (!win)
|
|
throw('glk_request_char_event: invalid window');
|
|
if (win.char_request || win.line_request)
|
|
throw('glk_request_char_event: window already has keyboard request');
|
|
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
win.char_request = true;
|
|
win.char_request_uni = true;
|
|
win.input_generation = event_generation;
|
|
}
|
|
else {
|
|
/* ### wintype_Graphics could accept char input if we set up the focus to allow it. See gestalt_GraphicsCharInput. */
|
|
throw('glk_request_char_event: window does not support keyboard input');
|
|
}
|
|
}
|
|
|
|
function glk_request_line_event_uni(win, buf, initlen) {
|
|
if (!win)
|
|
throw('glk_request_line_event: invalid window');
|
|
if (win.char_request || win.line_request)
|
|
throw('glk_request_line_event: window already has keyboard request');
|
|
|
|
if (win.type == Const.wintype_TextBuffer
|
|
|| win.type == Const.wintype_TextGrid) {
|
|
if (initlen) {
|
|
/* This will be copied into the next update. */
|
|
var ls = buf.slice(0, initlen);
|
|
if (!current_partial_outputs)
|
|
current_partial_outputs = {};
|
|
current_partial_outputs[win.disprock] = UniArrayToString(ls);
|
|
}
|
|
win.line_request = true;
|
|
win.line_request_uni = true;
|
|
if (win.type == Const.wintype_TextBuffer)
|
|
win.request_echo_line_input = win.echo_line_input;
|
|
else
|
|
win.request_echo_line_input = true;
|
|
win.input_generation = event_generation;
|
|
win.linebuf = buf;
|
|
if (GiDispa)
|
|
GiDispa.retain_array(buf);
|
|
}
|
|
else {
|
|
throw('glk_request_line_event: window does not support keyboard input');
|
|
}
|
|
}
|
|
|
|
function glk_current_time(timevalref) {
|
|
var now = new Date().getTime();
|
|
var usec;
|
|
|
|
timevalref.set_field(0, Math.floor(now / 4294967296000));
|
|
timevalref.set_field(1, Math.floor(now / 1000) >>>0);
|
|
usec = Math.floor((now % 1000) * 1000);
|
|
if (usec < 0)
|
|
usec = 1000000 + usec;
|
|
timevalref.set_field(2, usec);
|
|
}
|
|
|
|
function glk_current_simple_time(factor) {
|
|
var now = new Date().getTime();
|
|
return Math.floor(now / (factor * 1000));
|
|
}
|
|
|
|
function glk_time_to_date_utc(timevalref, dateref) {
|
|
var now = timevalref.get_field(0) * 4294967296000 + timevalref.get_field(1) * 1000 + timevalref.get_field(2) / 1000;
|
|
var obj = new Date(now);
|
|
|
|
dateref.set_field(0, obj.getUTCFullYear())
|
|
dateref.set_field(1, 1+obj.getUTCMonth())
|
|
dateref.set_field(2, obj.getUTCDate())
|
|
dateref.set_field(3, obj.getUTCDay())
|
|
dateref.set_field(4, obj.getUTCHours())
|
|
dateref.set_field(5, obj.getUTCMinutes())
|
|
dateref.set_field(6, obj.getUTCSeconds())
|
|
dateref.set_field(7, 1000*obj.getUTCMilliseconds())
|
|
}
|
|
|
|
function glk_time_to_date_local(timevalref, dateref) {
|
|
var now = timevalref.get_field(0) * 4294967296000 + timevalref.get_field(1) * 1000 + timevalref.get_field(2) / 1000;
|
|
var obj = new Date(now);
|
|
|
|
dateref.set_field(0, obj.getFullYear())
|
|
dateref.set_field(1, 1+obj.getMonth())
|
|
dateref.set_field(2, obj.getDate())
|
|
dateref.set_field(3, obj.getDay())
|
|
dateref.set_field(4, obj.getHours())
|
|
dateref.set_field(5, obj.getMinutes())
|
|
dateref.set_field(6, obj.getSeconds())
|
|
dateref.set_field(7, 1000*obj.getMilliseconds())
|
|
}
|
|
|
|
function glk_simple_time_to_date_utc(time, factor, dateref) {
|
|
var now = time*(1000*factor);
|
|
var obj = new Date(now);
|
|
|
|
dateref.set_field(0, obj.getUTCFullYear())
|
|
dateref.set_field(1, 1+obj.getUTCMonth())
|
|
dateref.set_field(2, obj.getUTCDate())
|
|
dateref.set_field(3, obj.getUTCDay())
|
|
dateref.set_field(4, obj.getUTCHours())
|
|
dateref.set_field(5, obj.getUTCMinutes())
|
|
dateref.set_field(6, obj.getUTCSeconds())
|
|
dateref.set_field(7, 1000*obj.getUTCMilliseconds())
|
|
}
|
|
|
|
function glk_simple_time_to_date_local(time, factor, dateref) {
|
|
var now = time*(1000*factor);
|
|
var obj = new Date(now);
|
|
|
|
dateref.set_field(0, obj.getFullYear())
|
|
dateref.set_field(1, 1+obj.getMonth())
|
|
dateref.set_field(2, obj.getDate())
|
|
dateref.set_field(3, obj.getDay())
|
|
dateref.set_field(4, obj.getHours())
|
|
dateref.set_field(5, obj.getMinutes())
|
|
dateref.set_field(6, obj.getSeconds())
|
|
dateref.set_field(7, 1000*obj.getMilliseconds())
|
|
}
|
|
|
|
function glk_date_to_time_utc(dateref, timevalref) {
|
|
var obj = new Date(0);
|
|
|
|
obj.setUTCFullYear(dateref.get_field(0));
|
|
obj.setUTCMonth(dateref.get_field(1)-1);
|
|
obj.setUTCDate(dateref.get_field(2));
|
|
obj.setUTCHours(dateref.get_field(4));
|
|
obj.setUTCMinutes(dateref.get_field(5));
|
|
obj.setUTCSeconds(dateref.get_field(6));
|
|
obj.setUTCMilliseconds(dateref.get_field(7)/1000);
|
|
|
|
var now = obj.getTime();
|
|
var usec;
|
|
|
|
timevalref.set_field(0, Math.floor(now / 4294967296000));
|
|
timevalref.set_field(1, Math.floor(now / 1000) >>>0);
|
|
usec = Math.floor((now % 1000) * 1000);
|
|
if (usec < 0)
|
|
usec = 1000000 + usec;
|
|
timevalref.set_field(2, usec);
|
|
}
|
|
|
|
function glk_date_to_time_local(dateref, timevalref) {
|
|
var obj = new Date(
|
|
dateref.get_field(0), dateref.get_field(1)-1, dateref.get_field(2),
|
|
dateref.get_field(4), dateref.get_field(5), dateref.get_field(6),
|
|
dateref.get_field(7)/1000);
|
|
|
|
var now = obj.getTime();
|
|
var usec;
|
|
|
|
timevalref.set_field(0, Math.floor(now / 4294967296000));
|
|
timevalref.set_field(1, Math.floor(now / 1000) >>>0);
|
|
usec = Math.floor((now % 1000) * 1000);
|
|
if (usec < 0)
|
|
usec = 1000000 + usec;
|
|
timevalref.set_field(2, usec);
|
|
}
|
|
|
|
function glk_date_to_simple_time_utc(dateref, factor) {
|
|
var obj = new Date(0);
|
|
|
|
obj.setUTCFullYear(dateref.get_field(0));
|
|
obj.setUTCMonth(dateref.get_field(1)-1);
|
|
obj.setUTCDate(dateref.get_field(2));
|
|
obj.setUTCHours(dateref.get_field(4));
|
|
obj.setUTCMinutes(dateref.get_field(5));
|
|
obj.setUTCSeconds(dateref.get_field(6));
|
|
obj.setUTCMilliseconds(dateref.get_field(7)/1000);
|
|
|
|
var now = obj.getTime();
|
|
return Math.floor(now / (factor * 1000));
|
|
}
|
|
|
|
function glk_date_to_simple_time_local(dateref, factor) {
|
|
var obj = new Date(
|
|
dateref.get_field(0), dateref.get_field(1)-1, dateref.get_field(2),
|
|
dateref.get_field(4), dateref.get_field(5), dateref.get_field(6),
|
|
dateref.get_field(7)/1000);
|
|
|
|
var now = obj.getTime();
|
|
return Math.floor(now / (factor * 1000));
|
|
}
|
|
|
|
/* End of Glk namespace function. Return the object which will
|
|
become the Glk global. */
|
|
var api = {
|
|
version: '2.2.3', /* GlkOte/GlkApi version */
|
|
set_references: set_references,
|
|
init : init,
|
|
update : update,
|
|
save_allstate : save_allstate,
|
|
restore_allstate : restore_allstate,
|
|
fatal_error : fatal_error,
|
|
|
|
byte_array_to_string : ByteArrayToString,
|
|
uni_array_to_string : UniArrayToString,
|
|
Const : Const,
|
|
RefBox : RefBox,
|
|
RefStruct : RefStruct,
|
|
DidNotReturn : DidNotReturn,
|
|
call_may_not_return : call_may_not_return,
|
|
|
|
glk_put_jstring : glk_put_jstring,
|
|
glk_put_jstring_stream : glk_put_jstring_stream,
|
|
|
|
glk_exit : glk_exit,
|
|
glk_tick : glk_tick,
|
|
glk_gestalt : glk_gestalt,
|
|
glk_gestalt_ext : glk_gestalt_ext,
|
|
glk_window_iterate : glk_window_iterate,
|
|
glk_window_get_rock : glk_window_get_rock,
|
|
glk_window_get_root : glk_window_get_root,
|
|
glk_window_open : glk_window_open,
|
|
glk_window_close : glk_window_close,
|
|
glk_window_get_size : glk_window_get_size,
|
|
glk_window_set_arrangement : glk_window_set_arrangement,
|
|
glk_window_get_arrangement : glk_window_get_arrangement,
|
|
glk_window_get_type : glk_window_get_type,
|
|
glk_window_get_parent : glk_window_get_parent,
|
|
glk_window_clear : glk_window_clear,
|
|
glk_window_move_cursor : glk_window_move_cursor,
|
|
glk_window_get_stream : glk_window_get_stream,
|
|
glk_window_set_echo_stream : glk_window_set_echo_stream,
|
|
glk_window_get_echo_stream : glk_window_get_echo_stream,
|
|
glk_set_window : glk_set_window,
|
|
glk_window_get_sibling : glk_window_get_sibling,
|
|
glk_stream_iterate : glk_stream_iterate,
|
|
glk_stream_get_rock : glk_stream_get_rock,
|
|
glk_stream_open_file : glk_stream_open_file,
|
|
glk_stream_open_memory : glk_stream_open_memory,
|
|
glk_stream_close : glk_stream_close,
|
|
glk_stream_set_position : glk_stream_set_position,
|
|
glk_stream_get_position : glk_stream_get_position,
|
|
glk_stream_set_current : glk_stream_set_current,
|
|
glk_stream_get_current : glk_stream_get_current,
|
|
glk_fileref_create_temp : glk_fileref_create_temp,
|
|
glk_fileref_create_by_name : glk_fileref_create_by_name,
|
|
glk_fileref_create_by_prompt : glk_fileref_create_by_prompt,
|
|
glk_fileref_destroy : glk_fileref_destroy,
|
|
glk_fileref_iterate : glk_fileref_iterate,
|
|
glk_fileref_get_rock : glk_fileref_get_rock,
|
|
glk_fileref_delete_file : glk_fileref_delete_file,
|
|
glk_fileref_does_file_exist : glk_fileref_does_file_exist,
|
|
glk_fileref_create_from_fileref : glk_fileref_create_from_fileref,
|
|
glk_put_char : glk_put_char,
|
|
glk_put_char_stream : glk_put_char_stream,
|
|
glk_put_string : glk_put_string,
|
|
glk_put_string_stream : glk_put_string_stream,
|
|
glk_put_buffer : glk_put_buffer,
|
|
glk_put_buffer_stream : glk_put_buffer_stream,
|
|
glk_set_style : glk_set_style,
|
|
glk_set_style_stream : glk_set_style_stream,
|
|
glk_get_char_stream : glk_get_char_stream,
|
|
glk_get_line_stream : glk_get_line_stream,
|
|
glk_get_buffer_stream : glk_get_buffer_stream,
|
|
glk_char_to_lower : glk_char_to_lower,
|
|
glk_char_to_upper : glk_char_to_upper,
|
|
glk_stylehint_set : glk_stylehint_set,
|
|
glk_stylehint_clear : glk_stylehint_clear,
|
|
glk_style_distinguish : glk_style_distinguish,
|
|
glk_style_measure : glk_style_measure,
|
|
glk_select : glk_select,
|
|
glk_select_poll : glk_select_poll,
|
|
glk_request_line_event : glk_request_line_event,
|
|
glk_cancel_line_event : glk_cancel_line_event,
|
|
glk_request_char_event : glk_request_char_event,
|
|
glk_cancel_char_event : glk_cancel_char_event,
|
|
glk_request_mouse_event : glk_request_mouse_event,
|
|
glk_cancel_mouse_event : glk_cancel_mouse_event,
|
|
glk_request_timer_events : glk_request_timer_events,
|
|
glk_image_get_info : glk_image_get_info,
|
|
glk_image_draw : glk_image_draw,
|
|
glk_image_draw_scaled : glk_image_draw_scaled,
|
|
glk_window_flow_break : glk_window_flow_break,
|
|
glk_window_erase_rect : glk_window_erase_rect,
|
|
glk_window_fill_rect : glk_window_fill_rect,
|
|
glk_window_set_background_color : glk_window_set_background_color,
|
|
glk_schannel_iterate : glk_schannel_iterate,
|
|
glk_schannel_get_rock : glk_schannel_get_rock,
|
|
glk_schannel_create : glk_schannel_create,
|
|
glk_schannel_destroy : glk_schannel_destroy,
|
|
glk_schannel_play : glk_schannel_play,
|
|
glk_schannel_play_ext : glk_schannel_play_ext,
|
|
glk_schannel_stop : glk_schannel_stop,
|
|
glk_schannel_set_volume : glk_schannel_set_volume,
|
|
glk_schannel_create_ext : glk_schannel_create_ext,
|
|
glk_schannel_play_multi : glk_schannel_play_multi,
|
|
glk_schannel_pause : glk_schannel_pause,
|
|
glk_schannel_unpause : glk_schannel_unpause,
|
|
glk_schannel_set_volume_ext : glk_schannel_set_volume_ext,
|
|
glk_sound_load_hint : glk_sound_load_hint,
|
|
glk_set_hyperlink : glk_set_hyperlink,
|
|
glk_set_hyperlink_stream : glk_set_hyperlink_stream,
|
|
glk_request_hyperlink_event : glk_request_hyperlink_event,
|
|
glk_cancel_hyperlink_event : glk_cancel_hyperlink_event,
|
|
glk_buffer_to_lower_case_uni : glk_buffer_to_lower_case_uni,
|
|
glk_buffer_to_upper_case_uni : glk_buffer_to_upper_case_uni,
|
|
glk_buffer_to_title_case_uni : glk_buffer_to_title_case_uni,
|
|
glk_buffer_canon_decompose_uni : glk_buffer_canon_decompose_uni,
|
|
glk_buffer_canon_normalize_uni : glk_buffer_canon_normalize_uni,
|
|
glk_put_char_uni : glk_put_char_uni,
|
|
glk_put_string_uni : glk_put_string_uni,
|
|
glk_put_buffer_uni : glk_put_buffer_uni,
|
|
glk_put_char_stream_uni : glk_put_char_stream_uni,
|
|
glk_put_string_stream_uni : glk_put_string_stream_uni,
|
|
glk_put_buffer_stream_uni : glk_put_buffer_stream_uni,
|
|
glk_get_char_stream_uni : glk_get_char_stream_uni,
|
|
glk_get_buffer_stream_uni : glk_get_buffer_stream_uni,
|
|
glk_get_line_stream_uni : glk_get_line_stream_uni,
|
|
glk_stream_open_file_uni : glk_stream_open_file_uni,
|
|
glk_stream_open_memory_uni : glk_stream_open_memory_uni,
|
|
glk_request_char_event_uni : glk_request_char_event_uni,
|
|
glk_request_line_event_uni : glk_request_line_event_uni,
|
|
glk_set_echo_line_event : glk_set_echo_line_event,
|
|
glk_set_terminators_line_event : glk_set_terminators_line_event,
|
|
glk_current_time : glk_current_time,
|
|
glk_current_simple_time : glk_current_simple_time,
|
|
glk_time_to_date_utc : glk_time_to_date_utc,
|
|
glk_time_to_date_local : glk_time_to_date_local,
|
|
glk_simple_time_to_date_utc : glk_simple_time_to_date_utc,
|
|
glk_simple_time_to_date_local : glk_simple_time_to_date_local,
|
|
glk_date_to_time_utc : glk_date_to_time_utc,
|
|
glk_date_to_time_local : glk_date_to_time_local,
|
|
glk_date_to_simple_time_utc : glk_date_to_simple_time_utc,
|
|
glk_date_to_simple_time_local : glk_date_to_simple_time_local,
|
|
glk_stream_open_resource : glk_stream_open_resource,
|
|
glk_stream_open_resource_uni : glk_stream_open_resource_uni
|
|
};
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = api;
|
|
}
|
|
|
|
return api;
|
|
|
|
}();
|
|
|
|
/* End of Glk library. */ |