X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=interpreters%2Fglulxe%2Fmain.c;fp=interpreters%2Fglulxe%2Fmain.c;h=63aba89e1b5524673b50f4d344e876cd0251179c;hb=147a8cbf17f2b3379277bf7d37cda9866510f16c;hp=0000000000000000000000000000000000000000;hpb=7de488aa6a1709a4d5c59b5ff59862105c1748c5;p=rodin%2Fchimara.git diff --git a/interpreters/glulxe/main.c b/interpreters/glulxe/main.c new file mode 100644 index 0000000..63aba89 --- /dev/null +++ b/interpreters/glulxe/main.c @@ -0,0 +1,163 @@ +/* main.c: Glulxe top-level code. + Designed by Andrew Plotkin + http://eblong.com/zarf/glulx/index.html +*/ + +#include "glk.h" +#include "glulxe.h" + +strid_t gamefile = NULL; /* The stream containing the Glulx file. */ +glui32 gamefile_start = 0; /* The position within the stream. (This will not + be zero if the Glulx file is a chunk inside a Blorb archive.) */ +glui32 gamefile_len = 0; /* The length within the stream. */ +char *init_err = NULL; +char *init_err2 = NULL; + +static winid_t get_error_win(void); +static void stream_hexnum(glsi32 val); + +/* glk_main(): + The top-level routine. This does everything, and consequently is + very simple. +*/ +void glk_main() +{ + if (init_err) { + fatal_error_2(init_err, init_err2); + return; + } + + if (!is_gamefile_valid()) { + /* The fatal error has already been displayed. */ + return; + } + + glulx_setrandom(0); + if (!init_dispatch()) { + return; + } + if (!init_profile()) { + return; + } + + setup_vm(); + execute_loop(); + finalize_vm(); + + profile_quit(); + glk_exit(); +} + +/* get_error_win(): + Return a window in which to display errors. The first time this is called, + it creates a new window; after that it returns the window it first + created. +*/ +static winid_t get_error_win() +{ + static winid_t errorwin = NULL; + + if (!errorwin) { + winid_t rootwin = glk_window_get_root(); + if (!rootwin) { + errorwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1); + } + else { + errorwin = glk_window_open(rootwin, winmethod_Below | winmethod_Fixed, + 3, wintype_TextBuffer, 0); + } + if (!errorwin) + errorwin = rootwin; + } + + return errorwin; +} + +/* fatal_error_handler(): + Display an error in the error window, and then exit. +*/ +void fatal_error_handler(char *str, char *arg, int useval, glsi32 val) +{ + winid_t win = get_error_win(); + if (win) { + glk_set_window(win); + glk_put_string("Glulxe fatal error: "); + glk_put_string(str); + if (arg || useval) { + glk_put_string(" ("); + if (arg) + glk_put_string(arg); + if (arg && useval) + glk_put_string(" "); + if (useval) + stream_hexnum(val); + glk_put_string(")"); + } + glk_put_string("\n"); + } + glk_exit(); +} + +/* nonfatal_warning_handler(): + Display a warning in the error window, and then continue. +*/ +void nonfatal_warning_handler(char *str, char *arg, int useval, glsi32 val) +{ + winid_t win = get_error_win(); + if (win) { + strid_t oldstr = glk_stream_get_current(); + glk_set_window(win); + glk_put_string("Glulxe warning: "); + glk_put_string(str); + if (arg || useval) { + glk_put_string(" ("); + if (arg) + glk_put_string(arg); + if (arg && useval) + glk_put_string(" "); + if (useval) + stream_hexnum(val); + glk_put_string(")"); + } + glk_put_string("\n"); + glk_stream_set_current(oldstr); + } +} + +/* stream_hexnum(): + Write a signed integer to the current Glk output stream. +*/ +static void stream_hexnum(glsi32 val) +{ + char buf[16]; + glui32 ival; + int ix; + + if (val == 0) { + glk_put_char('0'); + return; + } + + if (val < 0) { + glk_put_char('-'); + ival = -val; + } + else { + ival = val; + } + + ix = 0; + while (ival != 0) { + buf[ix] = (ival % 16) + '0'; + if (buf[ix] > '9') + buf[ix] += ('A' - ('9' + 1)); + ix++; + ival /= 16; + } + + while (ix) { + ix--; + glk_put_char(buf[ix]); + } +} +