Functions the Library Must Provide

Functions the Library Must Provide — Platform-dependent dispatch layer functions

Functions

Types and Values

Includes

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

Description

Ideally, the three layers — program, dispatch layer, Glk library — would be completely modular; each would refer only to the layers beneath it. Sadly, there are a few places where the library must notify the program that something has happened. Worse, these situations are only relevant to programs which use the dispatch layer, and then only some of those.

Since C is uncomfortable with the concept of calling functions which may not exist, Glk handles this with call-back function pointers. The program can pass callbacks in to the library; if it does, the library will call them, and if not, the library doesn't try.

These callbacks are optional, in the sense that the program may or may not set them. However, any library which wants to interoperate with the dispatch layer must allow the program to set them; it is the program's choice. The library does this by implementing set_registry functions — the functions to which the program passes its callbacks.

Even though these callbacks and the functions to set them are declared in gi_dispa.h, they are not defined in gi_dispa.c. The dispatch layer merely coordinates them. The program defines the callback functions; the library calls them.

Functions

gidispatch_set_object_registry ()

void
gidispatch_set_object_registry (gidispatch_rock_t (*regi) (void *obj, glui32 objclass),
                                void (*unregi) (void *obj, glui32 objclass, gidispatch_rock_t objrock));

The Glk API refers to opaque objects by pointer; but a VM probably cannot store pointers to native memory. Therefore, a VM program will want to keep a VM-accessible collection of opaque objects.

For example, it might keep a hash table for each opaque object class, mapping integer identifiers to object pointers.

To make this possible, a Glk library must implement gidispatch_set_object_registry().

Your program calls gidispatch_set_object_registry() early (before it begins actually executing VM code.) You pass in two function pointers, matching the following prototypes:

1
2
gidispatch_rock_t my_vm_reg_object(void *obj, glui32 objclass);
void my_vm_unreg_object(void *obj, glui32 objclass, gidispatch_rock_t objrock);

Whenever the Glk library creates an object, it will call my_vm_reg_object<!---->(). It will pass the object pointer and the class number (from 0 to N - 1, where N is the value returned by gidispatch_count_classes().)

You can return any value in the gidispatch_rock_t object; the library will stash this away inside the object.

Note that this is entirely separate from the regular Glk rock, which is always a glui32 and can be set independently.

Whenever the Glk library destroys an object, it will call my_vm_unreg_object<!---->(). It passes you the object pointer, class number, and the object rock.

One significant detail: It is possible that some Glk objects will already exist when your glk_main() function is called.

For example, MacGlk can open a stream when the user double-clicks a file; this occurs before glk_main().

So when you call gidispatch_set_object_registry(), it may immediately call your my_vm_reg_object<!---->() callback, notifying you of the existing objects. You must be prepared for this possibility.

If you are keeping hash tables, for example, create them before you call gidispatch_set_object_registry().

Parameters

regi

Function to call whenever an opaque object is created.

 

unregi

Function to call whenever an opaque object is destroyed.

 

gidispatch_get_objrock ()

gidispatch_rock_t
gidispatch_get_objrock (void *obj,
                        glui32 objclass);

You can, at any time, get the object rock of an object. The library implements this function.

With this and your two callbacks, you can maintain (say) a hash table for each object class, and easily convert back and forth between hash table keys and Glk object pointers. A more sophisticated run-time system (such as Java) could create a typed VM object for every Glk object, thus allowing VM code to manipulate Glk objects intelligently.

Parameters

obj

An opaque object.

 

objclass

One of gidisp_Class_Window, gidisp_Class_Stream, gidisp_Class_Fileref, or gidisp_Class_Schannel.

 

gidispatch_set_retained_registry ()

void
gidispatch_set_retained_registry (gidispatch_rock_t (*regi) (void *array, glui32 len, char *typecode),
                                  void (*unregi) (void *array, glui32 len, char *typecode, gidispatch_rock_t objrock));

A few Glk functions take an array and hold onto it. The memory is “owned” by the library until some future Glk call releases it. While the library retains the array, your program should not read, write, move, or deallocate it. When the library releases it, the contents are in their final form, and you can copy them out (if appropriate) and dispose of the memory as you wish.

To allow this, the library implements gidispatch_set_retained_registry().

Again, you pass in two function pointers:

1
2
gidispatch_rock_t my_vm_reg_array(void *array, glui32 len, char *typecode);
void my_vm_unreg_array(void *array, glui32 len, char *typecode, gidispatch_rock_t objrock);

Whenever a Glk function retains an array, it will call my_vm_reg_array<!---->(). This occurs only if you pass an array to an argument with the "#!" prefix.

But not in every such case. Wait for the my_vm_reg_array() call to confirm it.

The library passes the array and its length, exactly as you put them in the gluniversal_t array. It also passes the string which describes the argument.

Currently, the only calls that retain arrays are glk_request_line_event(), glk_stream_open_memory(), glk_request_line_event_uni(), and glk_stream_open_memory_uni(). The first two of these use arrays of characters, so the string is "&+#!Cn". The latter two use arrays of glui32, so the string is "&+#!Iu".

You can return any value in the gidispatch_rock_t object; the library will stash this away with the array.

When a Glk function releases a retained array, it will call my_vm_unreg_array<!---->(). It passes back the same array , len , and typecode parameters, as well as the gidispatch_rock_t you returned from my_vm_reg_array<!---->().

With these callbacks, you can maintain a collection of retained arrays. You can use this to copy data from C arrays to your own data structures, or keep relocatable memory locked, or prevent a garbage-collection system from deallocating an array while Glk is writing to it.

Parameters

regi

Function to call whenever the Glk library assumes ownership of an array.

 

unregi

Function to call whenever the Glk library releases ownership of an array.

 

Types and Values

gidispatch_rock_t

You can store any value you want in this object; return it from your object registry and retained array registry callbacks, and the library will stash it away. You can retrieve it with gidispatch_get_objrock().

Members

glui32 num;

Space for storing an integer.

 

void *ptr;

Space for storing a pointer.