~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to terps/frotz/glkmisc.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 *                                                                            *
 
3
 * Copyright (C) 2006-2009 by Tor Andersson.                                  *
 
4
 *                                                                            *
 
5
 * This file is part of Gargoyle.                                             *
 
6
 *                                                                            *
 
7
 * Gargoyle is free software; you can redistribute it and/or modify           *
 
8
 * it under the terms of the GNU General Public License as published by       *
 
9
 * the Free Software Foundation; either version 2 of the License, or          *
 
10
 * (at your option) any later version.                                        *
 
11
 *                                                                            *
 
12
 * Gargoyle is distributed in the hope that it will be useful,                *
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 
15
 * GNU General Public License for more details.                               *
 
16
 *                                                                            *
 
17
 * You should have received a copy of the GNU General Public License          *
 
18
 * along with Gargoyle; if not, write to the Free Software                    *
 
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *
 
20
 *                                                                            *
 
21
 *****************************************************************************/
 
22
 
 
23
/* glkstuff.c -- non-screen related glk stuff */
 
24
 
 
25
#include "glkfrotz.h"
 
26
 
 
27
#define VERSION "2.43"
 
28
 
 
29
f_setup_t f_setup;
 
30
 
 
31
int curr_status_ht = 0;
 
32
int mach_status_ht = 0;
 
33
 
 
34
winid_t gos_upper = NULL;
 
35
winid_t gos_lower = NULL;
 
36
winid_t gos_curwin = NULL;
 
37
 
 
38
int gos_linepending = 0;
 
39
char *gos_linebuf = NULL;
 
40
winid_t gos_linewin = NULL;
 
41
 
 
42
schanid_t gos_channel = NULL;
 
43
 
 
44
#define INFORMATION ""\
 
45
"An interpreter for Infocom and other Z-Machine games.\n"\
 
46
"Complies with standard 1.0 of Graham Nelson's specification.\n"\
 
47
"Plays Z-code versions 1-5 and 8.\n"\
 
48
"\n"\
 
49
"Syntax: frotz [options] story-file\n"\
 
50
"    -a   watch attribute setting\n"\
 
51
"    -A   watch attribute testing\n"\
 
52
"    -i   ignore fatal errors\n"\
 
53
"    -I # interpreter number\n"\
 
54
"    -o   watch object movement\n"\
 
55
"    -O   watch object locating\n"\
 
56
"    -P   alter piracy opcode\n"\
 
57
"    -Q   use old-style save format\n"\
 
58
"    -s # random number seed value\n"\
 
59
"    -S # transscript width\n"\
 
60
"    -t   set Tandy bit\n"\
 
61
"    -u # slots for multiple undo\n"\
 
62
"    -x   expand abbreviations g/x/z\n"
 
63
 
 
64
/* A unix-like getopt, but with the names changed to avoid any problems.  */
 
65
static int zoptind = 1;
 
66
static int zoptopt = 0;
 
67
static char *zoptarg = NULL;
 
68
static int zgetopt (int argc, char *argv[], const char *options)
 
69
{
 
70
        static int pos = 1;
 
71
        const char *p;
 
72
        if (zoptind >= argc || argv[zoptind][0] != '-' || argv[zoptind][1] == 0)
 
73
                return EOF;
 
74
        zoptopt = argv[zoptind][pos++];
 
75
        zoptarg = NULL;
 
76
        if (argv[zoptind][pos] == 0)
 
77
        {
 
78
                pos = 1;
 
79
                zoptind++;
 
80
        }
 
81
        p = strchr (options, zoptopt);
 
82
        if (zoptopt == ':' || p == NULL)
 
83
        {
 
84
                fputs ("illegal option -- ", stderr);
 
85
                goto error;
 
86
        }
 
87
        else if (p[1] == ':')
 
88
        {
 
89
                if (zoptind >= argc) {
 
90
                        fputs ("option requires an argument -- ", stderr);
 
91
                        goto error;
 
92
                } else {
 
93
                        zoptarg = argv[zoptind];
 
94
                        if (pos != 1)
 
95
                                zoptarg += pos;
 
96
                        pos = 1; zoptind++;
 
97
                }
 
98
        }
 
99
        return zoptopt;
 
100
error:
 
101
        fputc (zoptopt, stderr);
 
102
        fputc ('\n', stderr);
 
103
        return '?';
 
104
}
 
105
 
 
106
static int user_random_seed = -1;
 
107
static int user_tandy_bit = 0;
 
108
static char *graphics_filename = NULL;
 
109
 
 
110
void os_process_arguments(int argc, char *argv[]) 
 
111
{
 
112
        int c;
 
113
 
 
114
#ifdef GARGLK
 
115
        garglk_set_program_name("Frotz " VERSION);
 
116
        garglk_set_program_info(
 
117
                        "Glk Frotz " VERSION "\n"
 
118
                        "Original Frotz by Stefan Jokisch\n"
 
119
                        "Unix port by Jim Dunleavy and David Griffith\n"
 
120
                        "Glk port by Tor Andersson\n");
 
121
#endif
 
122
 
 
123
        /* Parse the options */
 
124
        do {
 
125
                c = zgetopt(argc, argv, "aAiI:oOPQs:S:tu:xZ:");
 
126
                switch (c)
 
127
                {
 
128
                        case 'a': f_setup.attribute_assignment = 1; break;
 
129
                        case 'A': f_setup.attribute_testing = 1; break;
 
130
                        case 'i': f_setup.ignore_errors = 1; break;
 
131
                        case 'I': f_setup.interpreter_number = atoi(zoptarg); break;
 
132
                        case 'o': f_setup.object_movement = 1; break;
 
133
                        case 'O': f_setup.object_locating = 1; break;
 
134
                        case 'P': f_setup.piracy = 1; break;
 
135
                        case 'Q': f_setup.save_quetzal = 0; break;
 
136
                        case 's': user_random_seed = atoi(zoptarg); break;
 
137
                        case 'S': f_setup.script_cols = atoi(zoptarg); break;
 
138
                        case 't': user_tandy_bit = 1; break;
 
139
                        case 'u': f_setup.undo_slots = atoi(zoptarg); break;
 
140
                        case 'x': f_setup.expand_abbreviations = 1; break;
 
141
                        case 'Z': f_setup.err_report_mode = atoi(zoptarg);
 
142
                                          if ((f_setup.err_report_mode < ERR_REPORT_NEVER) ||
 
143
                                                          (f_setup.err_report_mode > ERR_REPORT_FATAL))
 
144
                                                  f_setup.err_report_mode = ERR_DEFAULT_REPORT_MODE;
 
145
                                          break;
 
146
                }
 
147
        } while (c != EOF);
 
148
 
 
149
        if (((argc - zoptind) != 1) && ((argc - zoptind) != 2))
 
150
        {
 
151
                winid_t win;
 
152
                char buf[256];
 
153
                win = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
 
154
                glk_set_window(win);
 
155
                glk_put_string("FROTZ V" VERSION " -- Glk 0.6.1 interface.\n");
 
156
                glk_put_string(INFORMATION);
 
157
                sprintf(buf,
 
158
                                "    -Z # error checking mode (default = %d)\n"
 
159
                                "         %d = don't report errors.  "
 
160
                                "%d = report first error.\n"
 
161
                                "         %d = report all errors.  "
 
162
                                "%d = exit after any error.\n",
 
163
                                ERR_DEFAULT_REPORT_MODE, ERR_REPORT_NEVER,
 
164
                                ERR_REPORT_ONCE, ERR_REPORT_ALWAYS, ERR_REPORT_FATAL);
 
165
                glk_put_string(buf);
 
166
                glk_exit();
 
167
        }
 
168
        else
 
169
        {
 
170
                char *s;
 
171
 
 
172
                story_name = argv[zoptind++];
 
173
                if (zoptind < argc)
 
174
                        graphics_filename = argv[zoptind++];
 
175
 
 
176
                #ifdef GARGLK
 
177
                s = strrchr(story_name, '\\');
 
178
                if (!s) s = strrchr(story_name, '/');
 
179
                garglk_set_story_name(s ? s + 1 : story_name);
 
180
                #endif
 
181
        }
 
182
}
 
183
 
 
184
void os_init_screen(void)
 
185
{
 
186
        glui32 width, height;
 
187
 
 
188
        /*
 
189
         * Init glk stuff
 
190
         */
 
191
 
 
192
        glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
 
193
 
 
194
 
 
195
        gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
 
196
        if (!gos_lower)
 
197
                gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
 
198
        glk_window_get_size(gos_lower, &width, &height);
 
199
        glk_window_close(gos_lower, NULL);
 
200
 
 
201
        gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
 
202
        gos_upper = glk_window_open(gos_lower,
 
203
                        winmethod_Above | winmethod_Fixed,
 
204
                        0,
 
205
                        wintype_TextGrid, 0);
 
206
 
 
207
        gos_channel = NULL;
 
208
 
 
209
        glk_set_window(gos_lower);
 
210
        gos_curwin = gos_lower;
 
211
 
 
212
        /*
 
213
         * Icky magic bit setting
 
214
         */
 
215
 
 
216
        if (h_version == V3 && user_tandy_bit)
 
217
                h_config |= CONFIG_TANDY;
 
218
 
 
219
        if (h_version == V3 && gos_upper)
 
220
                h_config |= CONFIG_SPLITSCREEN;
 
221
 
 
222
        if (h_version == V3 && !gos_upper)
 
223
                h_config |= CONFIG_NOSTATUSLINE;
 
224
 
 
225
        if (h_version >= V4)
 
226
                h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
 
227
                        CONFIG_FIXED | CONFIG_TIMEDINPUT;
 
228
 
 
229
        if (h_version >= V5)
 
230
                h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);
 
231
 
 
232
        if ((h_version >= 5) && (h_flags & SOUND_FLAG))
 
233
                h_flags |= SOUND_FLAG;
 
234
 
 
235
        if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
 
236
                h_flags |= OLD_SOUND_FLAG;
 
237
 
 
238
        if ((h_version == 6) && (f_setup.sound != 0)) 
 
239
                h_config |= CONFIG_SOUND;
 
240
 
 
241
        if (h_version >= V5 && (h_flags & UNDO_FLAG))
 
242
                if (f_setup.undo_slots == 0)
 
243
                        h_flags &= ~UNDO_FLAG;
 
244
 
 
245
        h_screen_cols = width;
 
246
        h_screen_rows = height;
 
247
 
 
248
        h_screen_height = h_screen_rows;
 
249
        h_screen_width = h_screen_cols;
 
250
 
 
251
        h_font_width = 1;
 
252
        h_font_height = 1;
 
253
 
 
254
        /* Must be after screen dimensions are computed.  */
 
255
        if (h_version == V6) {
 
256
                h_flags &= ~GRAPHICS_FLAG;
 
257
        }
 
258
 
 
259
        /* Use the ms-dos interpreter number for v6, because that's the
 
260
         * kind of graphics files we understand.  Otherwise, use DEC.  */
 
261
        h_interpreter_number = h_version == 6 ? INTERP_MSDOS : INTERP_DEC_20;
 
262
        if (f_setup.interpreter_number > 0)
 
263
                h_interpreter_number = f_setup.interpreter_number;
 
264
        h_interpreter_version = 'F';
 
265
        {
 
266
                /* Set these per spec 8.3.2. */
 
267
                h_default_foreground = WHITE_COLOUR;
 
268
                h_default_background = BLACK_COLOUR;
 
269
                if (h_flags & COLOUR_FLAG) h_flags &= ~COLOUR_FLAG;
 
270
        }
 
271
}
 
272
 
 
273
int os_random_seed (void)
 
274
{
 
275
    if (user_random_seed == -1)
 
276
        /* Use the epoch as seed value */
 
277
        return (time(0) & 0x7fff);
 
278
    return user_random_seed;
 
279
}
 
280
 
 
281
void os_restart_game (int stage) {}
 
282
 
 
283
void os_fatal (char *s)
 
284
{
 
285
        if (!gos_lower)
 
286
                gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
 
287
 
 
288
        glk_set_window(gos_lower);
 
289
        glk_set_style(style_Normal);
 
290
        glk_put_string("\n\nFatal error: ");
 
291
        glk_put_string(s);
 
292
        glk_put_string("\n");
 
293
        glk_exit();
 
294
}
 
295
 
 
296
void os_init_setup(void)
 
297
{
 
298
        f_setup.attribute_assignment = 0;
 
299
        f_setup.attribute_testing = 0;
 
300
        f_setup.context_lines = 0;
 
301
        f_setup.object_locating = 0;
 
302
        f_setup.object_movement = 0;
 
303
        f_setup.left_margin = 0;
 
304
        f_setup.right_margin = 0;
 
305
        f_setup.ignore_errors = 0;
 
306
        f_setup.interpreter_number = 0;
 
307
        f_setup.piracy = 0;
 
308
        f_setup.undo_slots = MAX_UNDO_SLOTS;
 
309
        f_setup.expand_abbreviations = 0;
 
310
        f_setup.script_cols = 80;
 
311
        f_setup.save_quetzal = 1;
 
312
        f_setup.sound = 1;
 
313
        f_setup.err_report_mode = ERR_DEFAULT_REPORT_MODE;
 
314
}
 
315
 
 
316
void gos_cancel_pending_line(void)
 
317
{
 
318
        event_t ev;
 
319
        glk_cancel_line_event(gos_linewin, &ev);
 
320
        gos_linebuf[ev.val1] = '\0';
 
321
        gos_linepending = 0;
 
322
}
 
323
 
 
324
zchar os_read_key (int timeout, bool show_cursor)
 
325
{
 
326
        event_t ev;
 
327
        winid_t win = gos_curwin ? gos_curwin : gos_lower;
 
328
 
 
329
        if (gos_linepending)
 
330
                gos_cancel_pending_line();
 
331
 
 
332
        glk_request_char_event(win);
 
333
        if (timeout != 0)
 
334
                glk_request_timer_events(timeout * 100);
 
335
 
 
336
        while (1)
 
337
        {
 
338
                glk_select(&ev);
 
339
                if (ev.type == evtype_Arrange) {
 
340
                        gos_update_height();
 
341
                        gos_update_width();
 
342
                }
 
343
                else if (ev.type == evtype_Timer)
 
344
                {
 
345
                        glk_cancel_char_event(win);
 
346
                        glk_request_timer_events(0);
 
347
                        return ZC_TIME_OUT;
 
348
                }
 
349
                else if (ev.type == evtype_CharInput)
 
350
                        break;
 
351
        }
 
352
 
 
353
        glk_request_timer_events(0);
 
354
 
 
355
        if (gos_upper && mach_status_ht < curr_status_ht)
 
356
                reset_status_ht();
 
357
        curr_status_ht = 0;
 
358
 
 
359
        switch (ev.val1)
 
360
        {
 
361
                case keycode_Escape: return ZC_ESCAPE;
 
362
                case keycode_PageUp: return ZC_ARROW_MIN;
 
363
                case keycode_PageDown: return ZC_ARROW_MAX;
 
364
                case keycode_Left: return ZC_ARROW_LEFT;
 
365
                case keycode_Right: return ZC_ARROW_RIGHT;
 
366
                case keycode_Up: return ZC_ARROW_UP;
 
367
                case keycode_Down: return ZC_ARROW_DOWN;
 
368
                case keycode_Return: return ZC_RETURN;
 
369
                case keycode_Delete: return ZC_BACKSPACE;
 
370
                case keycode_Tab: return ZC_INDENT;
 
371
                default:
 
372
                        return ev.val1;
 
373
        }
 
374
}
 
375
 
 
376
zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued)
 
377
{
 
378
        event_t ev;
 
379
        winid_t win = gos_curwin ? gos_curwin : gos_lower;
 
380
 
 
381
        if (!continued && gos_linepending)
 
382
                gos_cancel_pending_line(); 
 
383
 
 
384
        if (!continued || !gos_linepending)
 
385
        {
 
386
                glk_request_line_event(win, buf, max, strlen(buf));
 
387
                if (timeout != 0)
 
388
                        glk_request_timer_events(timeout * 100);
 
389
        }
 
390
 
 
391
        gos_linepending = 0;
 
392
 
 
393
        while (1)
 
394
        {
 
395
                glk_select(&ev);
 
396
                if (ev.type == evtype_Arrange) {
 
397
                        gos_update_height();
 
398
                        gos_update_width();
 
399
                }
 
400
                else if (ev.type == evtype_Timer)
 
401
                {
 
402
                        gos_linewin = win;
 
403
                        gos_linepending = 1;
 
404
                        gos_linebuf = buf;
 
405
                        return ZC_TIME_OUT;
 
406
                }
 
407
                else if (ev.type == evtype_LineInput)
 
408
                        break;
 
409
        }
 
410
 
 
411
        glk_request_timer_events(0);
 
412
        buf[ev.val1] = '\0';
 
413
 
 
414
        if (gos_upper && mach_status_ht < curr_status_ht)
 
415
                reset_status_ht();
 
416
        curr_status_ht = 0;
 
417
 
 
418
        return ZC_RETURN;
 
419
}
 
420
 
 
421
zword os_read_mouse(void)
 
422
{
 
423
        /* NOT IMPLEMENTED */
 
424
        return 0;
 
425
}
 
426
 
 
427
static glui32 flag2usage(int flag)
 
428
{
 
429
        switch (flag)
 
430
        {       
 
431
                case FILE_RESTORE:
 
432
                        return fileusage_SavedGame | fileusage_BinaryMode;
 
433
                case FILE_SAVE:
 
434
                        return fileusage_SavedGame | fileusage_BinaryMode;
 
435
                case FILE_SCRIPT:
 
436
                        return fileusage_Transcript | fileusage_TextMode;
 
437
                case FILE_PLAYBACK:
 
438
                        return fileusage_InputRecord | fileusage_TextMode;
 
439
                case FILE_RECORD:
 
440
                        return fileusage_InputRecord | fileusage_TextMode;
 
441
                case FILE_LOAD_AUX:
 
442
                        return fileusage_Data | fileusage_BinaryMode;
 
443
                case FILE_SAVE_AUX:
 
444
                        return fileusage_Data | fileusage_BinaryMode;
 
445
        }
 
446
        return 0;
 
447
}
 
448
 
 
449
static glui32 flag2mode(int flag)
 
450
{
 
451
        switch (flag)
 
452
        {       
 
453
        case FILE_RESTORE:
 
454
                return filemode_Read;
 
455
        case FILE_SAVE:
 
456
                return filemode_Write;
 
457
        case FILE_SCRIPT:
 
458
                return filemode_ReadWrite;      /* append really, but with erase option */
 
459
        case FILE_PLAYBACK:
 
460
                return filemode_Read;
 
461
        case FILE_RECORD:
 
462
                return filemode_Write;
 
463
        case FILE_LOAD_AUX:
 
464
                return filemode_Read;
 
465
        case FILE_SAVE_AUX:
 
466
                return filemode_Write;
 
467
        }
 
468
        return filemode_ReadWrite;
 
469
}
 
470
 
 
471
strid_t frotzopenprompt(int flag)
 
472
{
 
473
        frefid_t fref;
 
474
        strid_t stm;
 
475
        glui32 gusage = flag2usage(flag);
 
476
        glui32 gmode = flag2mode(flag);
 
477
 
 
478
        fref = glk_fileref_create_by_prompt(gusage, gmode, 0);
 
479
        if (fref == NULL)
 
480
                return NULL;
 
481
 
 
482
        stm = glk_stream_open_file(fref, gmode, 0);
 
483
 
 
484
        glk_fileref_destroy(fref);
 
485
 
 
486
        return stm;
 
487
}
 
488
 
 
489
strid_t frotzopen(char *filename, int flag)
 
490
{
 
491
        frefid_t fref;
 
492
        strid_t stm;
 
493
        glui32 gusage = flag2usage(flag);
 
494
        glui32 gmode = flag2mode(flag);
 
495
 
 
496
        fref = glk_fileref_create_by_name(gusage, filename, 0);
 
497
        if (!fref)
 
498
                return NULL;
 
499
 
 
500
        stm = glk_stream_open_file(fref, gmode, 0);
 
501
 
 
502
        glk_fileref_destroy(fref);
 
503
 
 
504
        return stm;
 
505
}
 
506