Open main menu

SCI/FreeSCI/Kernel hacking/Selectors

Selectors

Selectors are very important for some of the kernel functions. BaseSetter(), Animate(), Display(), GetEvent() and others take data from or write directly to selectors of a specified object (passed as a parameter or retreived from a node list), or even call object methods from kernel space.[1]

To prepare the usage of selectors, a variable has do be declared (in src/include/vm.h, selector_map_t). This variable will carry the numeric selector ID during run time. Now, the selector has to be mapped- this is happens once during initialization, to save time. It is performed by script_map_selectors(), which is located at the end of src/core/script.c (just use the "FIND_SELECTOR" macro).

If everything went right, accessing selectors should be really easy now. Just use the GET_SELECTOR(obj, selector) and PUT_SELECTOR(obj, selector, value) macros, where obj is a heap_ptr pointing to the object you want to read from or write to, and selector is the name of the selector to use.

An example for PUT_SELECTOR and GET_SELECTOR:

<syntax type="C">

             void
             kSwapXY(state_t *s, int funct_nr, int argc, heap_ptr argp)
             {
               int posx, posy;
               heap_ptr obj = PARAM(0);
               posx = GET_SELECTOR(obj, x);
               posy = GET_SELECTOR(obj, y); /* x and y are defined in selector_map_t */
               PUT_SELECTOR(obj, y, posx);
               PUT_SELECTOR(obj, x, posy);
             }</syntax>

Also, it may be neccessary to invoke an actual method. To do this, a varargs macro has been provided: INVOKE_SELECTOR(obj, selector, argc...). In theory, this macro can be used to set and read selectors as well (it would even handle multiple sends correctly), but this is discouraged for the sake of clarity.

INVOKE_SELECTOR works very much like the other macros; it must be called directly from a kernel function (or from any function supplying valid argc, argp and s).

An example for INVOKE_SELECTOR:

<syntax type="C">

       INVOKE_SELECTOR(obj, doit, 0); /* Call doit() without any parameters */
       INVOKE_SELECTOR(s->game_obj, setCursor, 2, 999, 1);
                               /* Call game_obj::setCursor(999, 1) */</syntax>

Notes

  1. Yes, this is evil. Don't do this at home, kids!