Dispatching

Dispatching — Dispatching the call to the Glk library

Functions

void gidispatch_call ()

Types and Values

Includes

#include <libchimara/glk.h>
#include <libchimara/gi-dispa.h>

Description

The function gidispatch_call() invokes a function from the Glk library.

Functions

gidispatch_call ()

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.

Basic Dispatch Types

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.

References

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.

Structures

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(NULL) by setting' 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.

Arrays

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.

Return Values

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;

Parameters

funcnum

Selector of the function to call.

 

numargs

Length of arglist .

 

arglist

List of arguments to pass to the function.

 

Types and Values

gluniversal_t

This is a union, encompassing all the types that can be passed to Glk functions.

Members

glui32 uint;

Stores a glui32.

 

glsi32 sint;

Stores a glsi32.

 

void *opaqueref;

Stores a winid_t, strid_t, frefid_t, or schanid_t.

 

unsigned char uch;

Stores an unsigned char.

 

signed char sch;

Stores a signed char.

 

char ch;

Stores a char with the default signedness.

 

char *charstr;

Stores a null-terminated string.

 

glui32 *unicharstr;

Stores a zero-terminated string of glui32 values representing Unicode characters.

 

void *array;

Stores a pointer to an array, and should be followed by another gluniversal_t with the array length stored in the uint member.

 

glui32 ptrflag;

If FALSE, represents an opaque reference or array that is NULL, in which case it represents the entire argument. If TRUE, should be followed by another gluniversal_t with the pointer in its opaqueref or array field.