Top |
void gidispatch_call (glui32 funcnum
,glui32 numargs
,gluniversal_t *arglist
);
funcnum
is the function number to invoke; see Table of
Selectors.
arglist
is the list of arguments, and numargs
is the length of the list.
The arguments are all stored as gluniversal_t objects.
Numeric arguments are passed in the obvious way — one argument per
gluniversal_t, with the uint
or sint
field set to the numeric value.
Characters and strings are also passed in this way — chars in
the uch
, sch
, or ch
fields (depending on whether the char is signed) and
strings in the charstr
field. Opaque objects (windows, streams, etc) are
passed in the opaqueref
field (which is void*
, in order to handle all
opaque pointer types.)
However, pointers (other than C strings), arrays, and structures complicate life. So do return values.
A reference to a numeric type or object reference — that is,
glui32*
, winid_t*
, and so on — takes
one or two gluniversal_t objects. The first is a flag
indicating whether the reference argument is NULL
or not. The ptrflag
field
of this gluniversal_t should be FALSE
(0) if the reference is NULL
, and
TRUE
(1) otherwise. If FALSE
, that is the end of the argument; you should
not use a gluniversal_t to explicitly store the NULL
reference. If the flag
is TRUE
, you must then put a gluniversal_t storing the base type of the
reference.
For example, consider a hypothetical function, with selector 0xABCD
:
1 |
void glk_glomp(glui32 num, winid_t win, glui32 *numref, strid_t *strref); |
...and the calls:
1 2 3 4 |
glui32 value; winid_t mainwin; strid_t gamefile; glk_glomp(5, mainwin, &value, &gamefile); |
To perform this through gidispatch_call()
, you would do the following:
1 2 3 4 5 6 7 8 9 10 |
gluniversal_t arglist[6]; arglist[0].uint = 5; arglist[1].opaqueref = mainwin; arglist[2].ptrflag = TRUE; arglist[3].uint = value; arglist[4].ptrflag = TRUE; arglist[5].opaqueref = gamefile; gidispatch_call(0xABCD, 6, arglist); value = arglist[3].uint; gamefile = arglist[5].opaqueref; |
Note that you copy the value of the reference arguments into and out of
arglist
.
Of course, it may be that glk_glomp<!---->()
only uses these as pass-out
references or pass-in references; if so, you could skip copying in or out.
For further examples:
1 2 3 4 5 6 7 8 |
glk_glomp(7, mainwin, NULL, NULL); ...or... gluniversal_t arglist[4]; arglist[0].uint = 7; arglist[1].opaqueref = mainwin; arglist[2].ptrflag = FALSE; arglist[3].ptrflag = FALSE; gidispatch_call(0xABCD, 4, arglist); |
1 2 3 4 5 6 7 8 9 10 |
glk_glomp(13, NULL, NULL, &gamefile); ...or... gluniversal_t arglist[5]; arglist[0].uint = 13; arglist[1].opaqueref = NULL; arglist[2].ptrflag = FALSE; arglist[3].ptrflag = TRUE; arglist[4].opaqueref = gamefile; gidispatch_call(0xABCD, 5, arglist); gamefile = arglist[4].opaqueref; |
1 2 3 4 5 6 7 8 9 10 |
glk_glomp(17, NULL, &value, NULL); ...or... gluniversal_t arglist[5]; arglist[0].uint = 17; arglist[1].opaqueref = NULL; arglist[2].ptrflag = TRUE; arglist[3].uint = value; arglist[4].ptrflag = FALSE; gidispatch_call(0xABCD, 5, arglist); value = arglist[3].uint; |
As you see, the length of arglist
depends on how many of the reference
arguments are NULL
.
A structure pointer is represented by a single ptrflag
, possibly followed by
a sequence of gluniversal_t objects (one for each field of the structure.)
Again, if the structure pointer is non-NULL
, the ptrflag
should be TRUE
and be followed by values; if not, the ptrflag
should be NULL
and stands
alone.
For example, the function glk_select()
can be invoked as follows:
1 2 3 4 5 6 7 8 |
event_t ev; gluniversal_t arglist[5]; arglist[0].ptrflag = TRUE; gidispatch_call(0x00C0, 5, arglist); ev.type = arglist[1].uint; ev.win = arglist[2].opaqueref; ev.val1 = arglist[3].uint; ev.val2 = arglist[4].uint; |
Since the structure passed to glk_select()
is a pass-out reference (the entry
values are ignored), you don't need to fill in arglist[1..4]
before calling
gidispatch_call()
.
Theoretically, you would invoke glk_select(
by setting'
NULL
)arglist[0].ptrflag
to FALSE
, and using a one-element arglist
instead of five-element. But it's illegal to pass NULL
to glk_select()
. So
you cannot actually do this.
In the Glk API, an array argument is always followed by a numeric argument
giving the array's length. These two C arguments are a single logical
argument, which is represented by one or three
gluniversal_t objects. The first is a ptrflag
, indicating whether the
argument is NULL
or not. The second is a pointer, stored in the array
field. The third is the array length, stored in the uint
field. And again,
if the ptrflag
is NULL
, the following two are omitted.
For example, the function glk_put_buffer()
can be invoked as follows:
1 2 3 4 5 6 7 8 9 |
char buf[64]; glui32 len = 64; glk_put_buffer(buf, len); ...or... gluniversal_t arglist[3]; arglist[0].ptrflag = TRUE; arglist[1].array = buf; arglist[2].uint = len; gidispatch_call(0x0084, 3, arglist); |
Since you are passing a C char array to gidispatch_call()
, the contents will
be read directly from that. There is no need to copy data into arglist
, as
you would for a basic type.
If you are implementing a VM whose native representation of char arrays is more complex, you will have to do more work. You should allocate a C char array, copy your characters into it, make the call, and then free the array.
glk_put_buffer()
does not modify the array passed to it, so there is no
need to copy the characters out.
The return value of a function is not treated specially. It is simply
considered to be a pass-out reference argument which may not be NULL
. It
comes after all the other arguments of the function.
For example, the function glk_window_get_rock()
can be invoked as follows:
1 2 3 4 5 6 7 8 9 |
glui32 rock; winid_t win; rock = glk_window_get_rock(win); ...or... gluniversal_t arglist[3]; arglist[0].opaqueref = win; arglist[1].ptrflag = TRUE; gidispatch_call(0x0021, 3, arglist); rock = arglist[2].uint; |
This is a union, encompassing all the types that can be passed to Glk functions.
glui32 |
Stores a glui32. |
|
glsi32 |
Stores a glsi32. |
|
Stores an unsigned char. |
||
Stores a signed char. |
||
Stores a char with the default signedness. |
||
Stores a null-terminated string. |
||
glui32 * |
Stores a zero-terminated string of glui32 values representing Unicode characters. |
|
Stores a pointer to an array, and should be followed by another
gluniversal_t with the array length stored in the |
||
glui32 |
If |