Merge branch 'sound'
[projects/chimara/chimara.git] / interpreters / glulxe / main.c
1 /* main.c: Glulxe top-level code.
2     Designed by Andrew Plotkin <erkyrath@eblong.com>
3     http://eblong.com/zarf/glulx/index.html
4 */
5
6 #include "glk.h"
7 #include "glulxe.h"
8
9 strid_t gamefile = NULL; /* The stream containing the Glulx file. */
10 glui32 gamefile_start = 0; /* The position within the stream. (This will not 
11     be zero if the Glulx file is a chunk inside a Blorb archive.) */
12 glui32 gamefile_len = 0; /* The length within the stream. */
13 char *init_err = NULL;
14 char *init_err2 = NULL;
15
16 static winid_t get_error_win(void);
17 static void stream_hexnum(glsi32 val);
18
19 /* glk_main():
20    The top-level routine. This does everything, and consequently is
21    very simple. 
22 */
23 void glk_main()
24 {
25   if (init_err) {
26     fatal_error_2(init_err, init_err2);
27     return;
28   }
29
30   if (!is_gamefile_valid()) {
31     /* The fatal error has already been displayed. */
32     return;
33   }
34
35   glulx_setrandom(0);
36 #ifdef FLOAT_SUPPORT
37   if (!init_float()) {
38     return;
39   }
40 #endif /* FLOAT_SUPPORT */
41   if (!init_dispatch()) {
42     return;
43   }
44   if (!init_profile()) {
45     return;
46   }
47
48   setup_vm();
49   execute_loop();
50   finalize_vm();
51
52   profile_quit();
53   glk_exit();
54 }
55
56 /* get_error_win():
57    Return a window in which to display errors. The first time this is called,
58    it creates a new window; after that it returns the window it first
59    created.
60 */
61 static winid_t get_error_win()
62 {
63   static winid_t errorwin = NULL;
64
65   if (!errorwin) {
66     winid_t rootwin = glk_window_get_root();
67     if (!rootwin) {
68       errorwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
69     }
70     else {
71       errorwin = glk_window_open(rootwin, winmethod_Below | winmethod_Fixed, 
72         3, wintype_TextBuffer, 0);
73     }
74     if (!errorwin)
75       errorwin = rootwin;
76   }
77
78   return errorwin;
79 }
80
81 /* fatal_error_handler():
82    Display an error in the error window, and then exit.
83 */
84 void fatal_error_handler(char *str, char *arg, int useval, glsi32 val)
85 {
86   winid_t win = get_error_win();
87   if (win) {
88     glk_set_window(win);
89     glk_put_string("Glulxe fatal error: ");
90     glk_put_string(str);
91     if (arg || useval) {
92       glk_put_string(" (");
93       if (arg)
94         glk_put_string(arg);
95       if (arg && useval)
96         glk_put_string(" ");
97       if (useval)
98         stream_hexnum(val);
99       glk_put_string(")");
100     }
101     glk_put_string("\n");
102   }
103   glk_exit();
104 }
105
106 /* nonfatal_warning_handler():
107    Display a warning in the error window, and then continue.
108 */
109 void nonfatal_warning_handler(char *str, char *arg, int useval, glsi32 val)
110 {
111   winid_t win = get_error_win();
112   if (win) {
113     strid_t oldstr = glk_stream_get_current();
114     glk_set_window(win);
115     glk_put_string("Glulxe warning: ");
116     glk_put_string(str);
117     if (arg || useval) {
118       glk_put_string(" (");
119       if (arg)
120         glk_put_string(arg);
121       if (arg && useval)
122         glk_put_string(" ");
123       if (useval)
124         stream_hexnum(val);
125       glk_put_string(")");
126     }
127     glk_put_string("\n");
128     glk_stream_set_current(oldstr);
129   }
130 }
131
132 /* stream_hexnum():
133    Write a signed integer to the current Glk output stream.
134 */
135 static void stream_hexnum(glsi32 val)
136 {
137   char buf[16];
138   glui32 ival;
139   int ix;
140
141   if (val == 0) {
142     glk_put_char('0');
143     return;
144   }
145
146   if (val < 0) {
147     glk_put_char('-');
148     ival = -val;
149   }
150   else {
151     ival = val;
152   }
153
154   ix = 0;
155   while (ival != 0) {
156     buf[ix] = (ival % 16) + '0';
157     if (buf[ix] > '9')
158       buf[ix] += ('A' - ('9' + 1));
159     ix++;
160     ival /= 16;
161   }
162
163   while (ix) {
164     ix--;
165     glk_put_char(buf[ix]);
166   }
167 }
168