| 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 |