mirror of
https://github.com/ganelson/inform.git
synced 2024-07-18 06:54:26 +03:00
369 lines
13 KiB
OpenEdge ABL
369 lines
13 KiB
OpenEdge ABL
[CInputOutputModel::] C Input-Output Model.
|
|
|
|
How C programs print text out, really.
|
|
|
|
@h Setting up the model.
|
|
|
|
=
|
|
void CInputOutputModel::initialise(code_generator *gtr) {
|
|
}
|
|
|
|
void CInputOutputModel::initialise_data(code_generation *gen) {
|
|
}
|
|
|
|
void CInputOutputModel::begin(code_generation *gen) {
|
|
}
|
|
|
|
void CInputOutputModel::end(code_generation *gen) {
|
|
}
|
|
|
|
@ By input/output, we mean printing text, receiving textual commands, or reading
|
|
or writing files. Inter can do this in one of two ways: either
|
|
|
|
(a) With one of the following primitives, or
|
|
(b) With an assembly-language opcode, and in particular |@glk|.
|
|
|
|
=
|
|
int CInputOutputModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
|
|
text_stream *OUT = CodeGen::current(gen);
|
|
switch (bip) {
|
|
case SPACES_BIP:
|
|
WRITE("for (int j = "); VNODE_1C;
|
|
WRITE("; j > 0; j--) i7_print_char(proc, 32);"); break;
|
|
case FONT_BIP:
|
|
WRITE("i7_styling(proc, 1, "); VNODE_1C; WRITE(")"); break;
|
|
case STYLE_BIP:
|
|
WRITE("i7_styling(proc, 2, "); VNODE_1C; WRITE(")"); break;
|
|
case PRINT_BIP:
|
|
WRITE("i7_print_C_string(proc, ");
|
|
CodeGen::lt_mode(gen, PRINTING_LTM); VNODE_1C;
|
|
CodeGen::lt_mode(gen, REGULAR_LTM); WRITE(")"); break;
|
|
case PRINTCHAR_BIP:
|
|
WRITE("i7_print_char(proc, "); VNODE_1C; WRITE(")"); break;
|
|
case PRINTNL_BIP:
|
|
WRITE("i7_print_char(proc, '\\n')"); break;
|
|
case PRINTOBJ_BIP:
|
|
WRITE("i7_print_object(proc, "); VNODE_1C; WRITE(")"); break;
|
|
case PRINTNUMBER_BIP:
|
|
WRITE("i7_print_decimal(proc, "); VNODE_1C; WRITE(")"); break;
|
|
case PRINTSTRING_BIP:
|
|
WRITE("i7_print_C_string(proc, i7_text_to_C_string("); VNODE_1C;
|
|
WRITE("))"); break;
|
|
case PRINTDWORD_BIP:
|
|
WRITE("i7_print_dword(proc, "); VNODE_1C; WRITE(")"); break;
|
|
case BOX_BIP:
|
|
WRITE("i7_print_box(proc, "); CodeGen::lt_mode(gen, BOX_LTM); VNODE_1C;
|
|
CodeGen::lt_mode(gen, REGULAR_LTM); WRITE(")"); break;
|
|
case ENABLEPRINTING_BIP:
|
|
WRITE("{ i7word_t window_id = 0;\n");
|
|
WRITE("i7_opcode_setiosys(proc, 2, 0); // Set to use Glk\n");
|
|
WRITE("i7_push(proc, 201); // = GG_MAINWIN_ROCK;\n");
|
|
WRITE("i7_push(proc, 3); // = wintype_TextBuffer;\n");
|
|
WRITE("i7_push(proc, 0);\n");
|
|
WRITE("i7_push(proc, 0);\n");
|
|
WRITE("i7_push(proc, 0);\n");
|
|
WRITE("i7_opcode_glk(proc, 35, 5, &window_id); // glk_window_open, pushing a window ID\n");
|
|
WRITE("i7_push(proc, window_id);\n");
|
|
WRITE("i7_opcode_glk(proc, 47, 1, NULL); // glk_set_window to that window ID\n");
|
|
WRITE("}\n");
|
|
break;
|
|
default: return NOT_APPLICABLE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
@ See //C Literals// for the implementation of |i7_print_dword|: it funnels
|
|
through to |i7_print_char|, and so do all of these:
|
|
|
|
= (text to inform7_clib.h)
|
|
void i7_print_C_string(i7process_t *proc, char *c_string);
|
|
void i7_print_decimal(i7process_t *proc, i7word_t x);
|
|
void i7_print_object(i7process_t *proc, i7word_t x);
|
|
void i7_print_box(i7process_t *proc, i7word_t x);
|
|
=
|
|
|
|
= (text to inform7_clib.c)
|
|
void i7_print_C_string(i7process_t *proc, char *c_string) {
|
|
if (c_string)
|
|
for (int i=0; c_string[i]; i++)
|
|
i7_print_char(proc, (i7word_t) c_string[i]);
|
|
}
|
|
|
|
void i7_print_decimal(i7process_t *proc, i7word_t x) {
|
|
char room[32];
|
|
sprintf(room, "%d", (int) x);
|
|
i7_print_C_string(proc, room);
|
|
}
|
|
|
|
void i7_print_object(i7process_t *proc, i7word_t x) {
|
|
i7_print_decimal(proc, x);
|
|
}
|
|
|
|
void i7_print_box(i7process_t *proc, i7word_t x) {
|
|
printf("Unimplemented: i7_print_box.\n");
|
|
i7_fatal_exit(proc);
|
|
}
|
|
=
|
|
|
|
@ Which in turn uses the |@glk| opcode:
|
|
|
|
= (text to inform7_clib.h)
|
|
void i7_print_char(i7process_t *proc, i7word_t x);
|
|
=
|
|
|
|
= (text to inform7_clib.c)
|
|
void i7_print_char(i7process_t *proc, i7word_t x) {
|
|
if (x == 13) x = 10;
|
|
i7_push(proc, x);
|
|
i7word_t current = 0;
|
|
i7_opcode_glk(proc, i7_glk_stream_get_current, 0, ¤t);
|
|
i7_push(proc, current);
|
|
i7_opcode_glk(proc, i7_glk_put_char_stream, 2, NULL);
|
|
}
|
|
=
|
|
|
|
@ At this point, then, all of our I/O needs will be handled if we can just
|
|
define two functions: |i7_styling|, for setting the font style, and |i7_opcode_glk|.
|
|
So we're nearly done, right? Right?
|
|
|
|
But in fact we route both of these functions through hooks which the user can
|
|
provide, so that the user can change the entire I/O model (if she is willing to
|
|
code up an alternative):
|
|
|
|
= (text to inform7_clib.h)
|
|
void i7_styling(i7process_t *proc, i7word_t which, i7word_t what);
|
|
void i7_default_stylist(i7process_t *proc, i7word_t which, i7word_t what);
|
|
void i7_opcode_glk(i7process_t *proc, i7word_t glk_api_selector, i7word_t varargc,
|
|
i7word_t *z);
|
|
void i7_default_glk(i7process_t *proc, i7word_t glk_api_selector, i7word_t varargc,
|
|
i7word_t *z);
|
|
=
|
|
|
|
= (text to inform7_clib.c)
|
|
void i7_styling(i7process_t *proc, i7word_t which, i7word_t what) {
|
|
(proc->stylist)(proc, which, what);
|
|
}
|
|
void i7_opcode_glk(i7process_t *proc, i7word_t glk_api_selector, i7word_t varargc,
|
|
i7word_t *z) {
|
|
(proc->glk_implementation)(proc, glk_api_selector, varargc, z);
|
|
}
|
|
=
|
|
|
|
@ What makes this more burdensome is that |@glk| is not so much a single opcode
|
|
as an entire instruction set: it is an compendium of over 120 disparate operations.
|
|
Indeed, the |glk_api_selector| argument to |i7_opcode_glk| chooses which one is
|
|
being used. For convenience, we define a set of names for them all -- which does
|
|
not imply any commitment to implement them all.
|
|
|
|
= (text to inform7_clib.h)
|
|
#define i7_glk_exit 0x0001
|
|
#define i7_glk_set_interrupt_handler 0x0002
|
|
#define i7_glk_tick 0x0003
|
|
#define i7_glk_gestalt 0x0004
|
|
#define i7_glk_gestalt_ext 0x0005
|
|
#define i7_glk_window_iterate 0x0020
|
|
#define i7_glk_window_get_rock 0x0021
|
|
#define i7_glk_window_get_root 0x0022
|
|
#define i7_glk_window_open 0x0023
|
|
#define i7_glk_window_close 0x0024
|
|
#define i7_glk_window_get_size 0x0025
|
|
#define i7_glk_window_set_arrangement 0x0026
|
|
#define i7_glk_window_get_arrangement 0x0027
|
|
#define i7_glk_window_get_type 0x0028
|
|
#define i7_glk_window_get_parent 0x0029
|
|
#define i7_glk_window_clear 0x002A
|
|
#define i7_glk_window_move_cursor 0x002B
|
|
#define i7_glk_window_get_stream 0x002C
|
|
#define i7_glk_window_set_echo_stream 0x002D
|
|
#define i7_glk_window_get_echo_stream 0x002E
|
|
#define i7_glk_set_window 0x002F
|
|
#define i7_glk_window_get_sibling 0x0030
|
|
#define i7_glk_stream_iterate 0x0040
|
|
#define i7_glk_stream_get_rock 0x0041
|
|
#define i7_glk_stream_open_file 0x0042
|
|
#define i7_glk_stream_open_memory 0x0043
|
|
#define i7_glk_stream_close 0x0044
|
|
#define i7_glk_stream_set_position 0x0045
|
|
#define i7_glk_stream_get_position 0x0046
|
|
#define i7_glk_stream_set_current 0x0047
|
|
#define i7_glk_stream_get_current 0x0048
|
|
#define i7_glk_stream_open_resource 0x0049
|
|
#define i7_glk_fileref_create_temp 0x0060
|
|
#define i7_glk_fileref_create_by_name 0x0061
|
|
#define i7_glk_fileref_create_by_prompt 0x0062
|
|
#define i7_glk_fileref_destroy 0x0063
|
|
#define i7_glk_fileref_iterate 0x0064
|
|
#define i7_glk_fileref_get_rock 0x0065
|
|
#define i7_glk_fileref_delete_file 0x0066
|
|
#define i7_glk_fileref_does_file_exist 0x0067
|
|
#define i7_glk_fileref_create_from_fileref 0x0068
|
|
#define i7_glk_put_char 0x0080
|
|
#define i7_glk_put_char_stream 0x0081
|
|
#define i7_glk_put_string 0x0082
|
|
#define i7_glk_put_string_stream 0x0083
|
|
#define i7_glk_put_buffer 0x0084
|
|
#define i7_glk_put_buffer_stream 0x0085
|
|
#define i7_glk_set_style 0x0086
|
|
#define i7_glk_set_style_stream 0x0087
|
|
#define i7_glk_get_char_stream 0x0090
|
|
#define i7_glk_get_line_stream 0x0091
|
|
#define i7_glk_get_buffer_stream 0x0092
|
|
#define i7_glk_char_to_lower 0x00A0
|
|
#define i7_glk_char_to_upper 0x00A1
|
|
#define i7_glk_stylehint_set 0x00B0
|
|
#define i7_glk_stylehint_clear 0x00B1
|
|
#define i7_glk_style_distinguish 0x00B2
|
|
#define i7_glk_style_measure 0x00B3
|
|
#define i7_glk_select 0x00C0
|
|
#define i7_glk_select_poll 0x00C1
|
|
#define i7_glk_request_line_event 0x00D0
|
|
#define i7_glk_cancel_line_event 0x00D1
|
|
#define i7_glk_request_char_event 0x00D2
|
|
#define i7_glk_cancel_char_event 0x00D3
|
|
#define i7_glk_request_mouse_event 0x00D4
|
|
#define i7_glk_cancel_mouse_event 0x00D5
|
|
#define i7_glk_request_timer_events 0x00D6
|
|
#define i7_glk_image_get_info 0x00E0
|
|
#define i7_glk_image_draw 0x00E1
|
|
#define i7_glk_image_draw_scaled 0x00E2
|
|
#define i7_glk_window_flow_break 0x00E8
|
|
#define i7_glk_window_erase_rect 0x00E9
|
|
#define i7_glk_window_fill_rect 0x00EA
|
|
#define i7_glk_window_set_background_color 0x00EB
|
|
#define i7_glk_schannel_iterate 0x00F0
|
|
#define i7_glk_schannel_get_rock 0x00F1
|
|
#define i7_glk_schannel_create 0x00F2
|
|
#define i7_glk_schannel_destroy 0x00F3
|
|
#define i7_glk_schannel_create_ext 0x00F4
|
|
#define i7_glk_schannel_play_multi 0x00F7
|
|
#define i7_glk_schannel_play 0x00F8
|
|
#define i7_glk_schannel_play_ext 0x00F9
|
|
#define i7_glk_schannel_stop 0x00FA
|
|
#define i7_glk_schannel_set_volume 0x00FB
|
|
#define i7_glk_sound_load_hint 0x00FC
|
|
#define i7_glk_schannel_set_volume_ext 0x00FD
|
|
#define i7_glk_schannel_pause 0x00FE
|
|
#define i7_glk_schannel_unpause 0x00FF
|
|
#define i7_glk_set_hyperlink 0x0100
|
|
#define i7_glk_set_hyperlink_stream 0x0101
|
|
#define i7_glk_request_hyperlink_event 0x0102
|
|
#define i7_glk_cancel_hyperlink_event 0x0103
|
|
#define i7_glk_buffer_to_lower_case_uni 0x0120
|
|
#define i7_glk_buffer_to_upper_case_uni 0x0121
|
|
#define i7_glk_buffer_to_title_case_uni 0x0122
|
|
#define i7_glk_buffer_canon_decompose_uni 0x0123
|
|
#define i7_glk_buffer_canon_normalize_uni 0x0124
|
|
#define i7_glk_put_char_uni 0x0128
|
|
#define i7_glk_put_string_uni 0x0129
|
|
#define i7_glk_put_buffer_uni 0x012A
|
|
#define i7_glk_put_char_stream_uni 0x012B
|
|
#define i7_glk_put_string_stream_uni 0x012C
|
|
#define i7_glk_put_buffer_stream_uni 0x012D
|
|
#define i7_glk_get_char_stream_uni 0x0130
|
|
#define i7_glk_get_buffer_stream_uni 0x0131
|
|
#define i7_glk_get_line_stream_uni 0x0132
|
|
#define i7_glk_stream_open_file_uni 0x0138
|
|
#define i7_glk_stream_open_memory_uni 0x0139
|
|
#define i7_glk_stream_open_resource_uni 0x013A
|
|
#define i7_glk_request_char_event_uni 0x0140
|
|
#define i7_glk_request_line_event_uni 0x0141
|
|
#define i7_glk_set_echo_line_event 0x0150
|
|
#define i7_glk_set_terminators_line_event 0x0151
|
|
#define i7_glk_current_time 0x0160
|
|
#define i7_glk_current_simple_time 0x0161
|
|
#define i7_glk_time_to_date_utc 0x0168
|
|
#define i7_glk_time_to_date_local 0x0169
|
|
#define i7_glk_simple_time_to_date_utc 0x016A
|
|
#define i7_glk_simple_time_to_date_local 0x016B
|
|
#define i7_glk_date_to_time_utc 0x016C
|
|
#define i7_glk_date_to_time_local 0x016D
|
|
#define i7_glk_date_to_simple_time_utc 0x016E
|
|
#define i7_glk_date_to_simple_time_local 0x016F
|
|
=
|
|
|
|
A few other constants will also be useful. These are the window IDs for the
|
|
three Glk windows used by the standard Inform 7 kits: |I7_BODY_TEXT_ID| is
|
|
where text is regularly printed; |I7_STATUS_TEXT_ID| is for the "status line"
|
|
at the top of a traditional interactive fiction display, but can simply be
|
|
ignored for non-IF purposes; and |I7_BOX_TEXT_ID| is where box quotations
|
|
would be displayed over the top of text, though C projects probably should
|
|
not use this, and the default Glk implementation here ignores it.
|
|
|
|
= (text to inform7_clib.h)
|
|
#define I7_BODY_TEXT_ID 201
|
|
#define I7_STATUS_TEXT_ID 202
|
|
#define I7_BOX_TEXT_ID 203
|
|
=
|
|
|
|
These are needed for different forms of file I/O:
|
|
|
|
= (text to inform7_clib.h)
|
|
#define i7_fileusage_Data 0x00
|
|
#define i7_fileusage_SavedGame 0x01
|
|
#define i7_fileusage_Transcript 0x02
|
|
#define i7_fileusage_InputRecord 0x03
|
|
#define i7_fileusage_TypeMask 0x0f
|
|
#define i7_fileusage_TextMode 0x100
|
|
#define i7_fileusage_BinaryMode 0x000
|
|
|
|
#define i7_filemode_Write 0x01
|
|
#define i7_filemode_Read 0x02
|
|
#define i7_filemode_ReadWrite 0x03
|
|
#define i7_filemode_WriteAppend 0x05
|
|
=
|
|
|
|
And these are modes for seeking a position in a file:
|
|
|
|
= (text to inform7_clib.h)
|
|
#define i7_seekmode_Start (0)
|
|
#define i7_seekmode_Current (1)
|
|
#define i7_seekmode_End (2)
|
|
=
|
|
|
|
And these are "event types":
|
|
|
|
= (text to inform7_clib.h)
|
|
#define i7_evtype_None 0
|
|
#define i7_evtype_Timer 1
|
|
#define i7_evtype_CharInput 2
|
|
#define i7_evtype_LineInput 3
|
|
#define i7_evtype_MouseInput 4
|
|
#define i7_evtype_Arrange 5
|
|
#define i7_evtype_Redraw 6
|
|
#define i7_evtype_SoundNotify 7
|
|
#define i7_evtype_Hyperlink 8
|
|
#define i7_evtype_VolumeNotify 9
|
|
=
|
|
|
|
Finally, these are the gestalt values: that is, the selection of bells and
|
|
whistles which a Glk implementation can offer --
|
|
|
|
= (text to inform7_clib.h)
|
|
#define i7_gestalt_Version 0
|
|
#define i7_gestalt_CharInput 1
|
|
#define i7_gestalt_LineInput 2
|
|
#define i7_gestalt_CharOutput 3
|
|
#define i7_gestalt_CharOutput_ApproxPrint 1
|
|
#define i7_gestalt_CharOutput_CannotPrint 0
|
|
#define i7_gestalt_CharOutput_ExactPrint 2
|
|
#define i7_gestalt_MouseInput 4
|
|
#define i7_gestalt_Timer 5
|
|
#define i7_gestalt_Graphics 6
|
|
#define i7_gestalt_DrawImage 7
|
|
#define i7_gestalt_Sound 8
|
|
#define i7_gestalt_SoundVolume 9
|
|
#define i7_gestalt_SoundNotify 10
|
|
#define i7_gestalt_Hyperlinks 11
|
|
#define i7_gestalt_HyperlinkInput 12
|
|
#define i7_gestalt_SoundMusic 13
|
|
#define i7_gestalt_GraphicsTransparency 14
|
|
#define i7_gestalt_Unicode 15
|
|
#define i7_gestalt_UnicodeNorm 16
|
|
#define i7_gestalt_LineInputEcho 17
|
|
#define i7_gestalt_LineTerminators 18
|
|
#define i7_gestalt_LineTerminatorKey 19
|
|
#define i7_gestalt_DateTime 20
|
|
#define i7_gestalt_Sound2 21
|
|
#define i7_gestalt_ResourceStream 22
|
|
#define i7_gestalt_GraphicsCharInput 23
|