/* Do not remove the headers from this file! see /USAGE for more info. */
#include <mudlib.h>
#include <hooks.h>
#include <driver/function.h>
//:MODULE
//
//The hook module is included as part of OBJECT, and allows a general method
//of allowing keeping track of and calling hooks, along with a method if
//specifying how multiple hooks should be resolved.
private nosave mapping hooks = ([]);
//:FUNCTION add_hook
//add_hook(string tag, function hook) sets up the function 'hook' to be
//called whenever call_hooks(tag, ...) is done. Note that if you want
//to remove the tag later, you have to do so with the _exact_ same function
//pointer.
//
//e.g.
//
//function my_hook = (: my_hook_func :);
//
// add_hook("foo", my_hook);
//
// remove_hook("foo", my_hook);
//
void add_hook(string tag, function hook) {
array tmp = ({ hook });
if (hooks[tag]) {
// Make sure we only have one
hooks[tag] -= tmp;
hooks[tag] += tmp;
} else
hooks[tag] = tmp;
}
//:FUNCTION remove_hook
//
//Remove a hook added with add_hook. The function pointer passed must be
//the same one that was passed to add_hook.
//
//see: add_hook
void remove_hook(string tag, function hook) {
if (hooks[tag])
hooks[tag] -= ({ hook });
if(!sizeof(hooks[tag]))
map_delete(hooks,tag);
}
//:FUNCTION hook_state
//
//hook_state(tag, hook, state) Either add or remove a hook based on the
//state 'state'
void hook_state(string tag, mixed hook, int state) {
if (state)
add_hook(tag, hook);
else
remove_hook(tag, hook);
}
//:FUNCTION call_hooks
//
//Call a set of hooks, with the specified method for resolving multiple
//hooks. A setting from /include/hooks.h can be used, or a function pointer
//which is appropriate for implode()ing with the return values.
//
//E.g.
//
// call_hooks("foo", (: $1 + $2 :), 2) will return 2 + the sum of the return
// values of the hooks
//
// but 2 + call_hooks("foo", HOOK_SUM) is faster.
//
//see: implode
//see: add_hook
varargs mixed call_hooks(string tag, mixed func, mixed start,
array args...) {
array hooks_to_call;
mixed tmp;
function hook;
if (hooks_to_call = hooks[tag]) {
hooks_to_call = filter(hooks_to_call,
(: !(functionp($1) & FP_OWNER_DESTED) :));
hooks[tag] = hooks_to_call;
if (!intp(func))
return implode(map(hooks_to_call, (: evaluate($1, $(args)...) :)),
func, start);
switch (func) {
case HOOK_IGNORE:
map(hooks_to_call, (: evaluate($1, $(args)...) :));
return 0;
case HOOK_SUM:
foreach (hook in hooks_to_call)
tmp += evaluate(hook, args...);
return tmp;
case HOOK_LAND:
foreach (hook in hooks_to_call)
if (!evaluate(hook, args...)) return 0;
return 1;
case HOOK_LOR:
foreach (hook in hooks_to_call)
if (tmp = evaluate(hook, args...))
return tmp;
return 0;
case HOOK_YES_NO_ERROR:
foreach (hook in hooks_to_call) {
tmp = evaluate(hook, args...);
if (!tmp || stringp(tmp)) return tmp;
}
return (start || 1);
default:
error("Unknown hook type in call_hooks.\n");
}
} else {
if (!intp(func))
return start;
switch (func) {
case HOOK_IGNORE:
case HOOK_SUM:
case HOOK_LOR:
return 0;
case HOOK_LAND:
return 1;
case HOOK_YES_NO_ERROR:
return (start || 1);
default:
error("Unknown hook type in call_hooks.\n");
}
}
}
mapping debug_hooks()
{
return copy(hooks);
}