Hook example code

From Second Life Wiki
Jump to: navigation, search
#include "lldarray.h"
// data1 and data2 may be used for any arbitrary user data.
// from_plugin should be set to FALSE if the function is being called due to a user's action,
// and TRUE if it is being called from another plugin.  (The idea is to avoid event loops, but
// maybe there is a better way.
// If function pointer returns FALSE, and this is one of a series of callbacks for a hook, 
// the function should terminate without passing control to any further plugins or to the
// rest of the viewer function.  (This is to allow hook functions to "swallow" events by return FALSE.)
typedef bool (*func_ptr)(void *data1, void *data2);

class hook {
public:
        const char * name;
        LLDynamicArray<func_ptr> *hook_ptrs;
        hook() {}
        hook(const char *n) {name = n; hook_ptrs = new (LLDynamicArray<func_ptr>)();}
};

class viewer_func  {
public:
        const char * name;
        func_ptr ptr;
        viewer_func() {}
        viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}
};

class plugin_interface {
private:
        hook * get_hook_by_name(const char *name);
        viewer_func * get_viewer_func_by_name(const char *name);
public:
        LLDynamicArray<hook> hooks;
        LLDynamicArray<viewer_func> viewer_funcs;
        
        void add_hook(const char *name, const func_ptr ptr);  

       void add_viewer_func(const char *name, func_ptr ptr);
       char ** get_viewer_func_list();
       char ** get_hook_list();
       
       const char * get_interface_version();
       void * call_viewer_func(const char *name, void *data1, void *data2);
       bool call_hooks(const char *name, void *data1, void *data2);
       void init();
       //plugin_interface();   
       
};

#define PLUGIN_HOOK(name, data1, data2) fprintf(stderr, "PLUGIN_HOOK(%s)\n", name); if(!gPluginInterface.call_hooks(name, (void *)(data1), (void *)(data2))) return; 

extern plugin_interface gPluginInterface;


void plugin_interface::add_hook(const char *name, const func_ptr ptr) {
       /* This function adds a named hook definition with nothing to call to the list.
         It should be called once for each hooked function upon instantiation of 
         the plugin interface; the hook_ptrs lists will be filled in, if necessary,
         by plugin init functions.  We need a list of hook names (function names)
         so that plugins can ask the interface what hooks it will export. */
       fprintf(stderr, "add_hook(%s = %p)\n", name, ptr);
       if(ptr) {
               hook * myhook = get_hook_by_name(name);
               if (myhook == NULL) {
                       fprintf(stderr, "ERROR: tried to add function to unknown hook %s\n", name);
                       return;
               } 
               myhook->hook_ptrs->put(ptr);
       } else
               hooks.put(*(new hook(name)));
}
hook * plugin_interface::get_hook_by_name(const char *name) {
       // this should really be a hash table lookup
       for(int i=0; i < hooks.count() ; i++) 
               if (!strcasecmp(name, hooks[i].name)) 
                       return &hooks[i];
       return NULL;
}
bool plugin_interface::call_hooks(const char *name, void *data1, void *data2) {
       hook * func = get_hook_by_name(name);
       if (func) {
               for (int i=0; i < func->hook_ptrs->count(); i++) {
                       LLDynamicArray<func_ptr> *fptr_array=func->hook_ptrs;
                       func_ptr fptr=(*fptr_array)[i];
                       if (!(fptr)(data1, data2)) return FALSE;
               }
               return TRUE;
       } else return FALSE;
}