summaryrefslogtreecommitdiff
path: root/src/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hooks.c')
-rw-r--r--src/hooks.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/src/hooks.c b/src/hooks.c
new file mode 100644
index 00000000..2b70e90d
--- /dev/null
+++ b/src/hooks.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+#include "hooks.h"
+#include "angband.h"
+#include <assert.h>
+
+/******** Hooks stuff *********/
+FILE *hook_file;
+
+#define MAX_ARGS 50
+
+static hooks_chain *hooks_heads[MAX_HOOKS];
+
+/* Wipe hooks and init them with quest hooks */
+void wipe_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_HOOKS; i++)
+ {
+ hooks_heads[i] = NULL;
+ }
+}
+void init_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_Q_IDX; i++)
+ {
+ if (quest[i].init != NULL)
+ {
+ quest[i].init(i);
+ }
+ }
+}
+
+/* Add a hook */
+hooks_chain* add_hook(int h_idx, hook_type hook, cptr name)
+{
+ hooks_chain *new_, *c = hooks_heads[h_idx];
+
+ /* Find it */
+ while ((c != NULL) && (strcmp(c->name, name)))
+ {
+ c = c->next;
+ }
+
+ /* If not already in the list, add it */
+ if (c == NULL)
+ {
+ MAKE(new_, hooks_chain);
+ new_->hook = hook;
+ sprintf(new_->name, "%s", name);
+ new_->next = hooks_heads[h_idx];
+ hooks_heads[h_idx] = new_;
+ return (new_);
+ }
+ else return (c);
+}
+
+void add_hook_new(int h_idx, bool_ (*hook_f)(void *, void *, void *), cptr name, void *data)
+{
+ hooks_chain *c = add_hook(h_idx, NULL, name);
+ c->hook_f = hook_f;
+ c->hook_data = data;
+ c->type = HOOK_TYPE_NEW;
+}
+
+/* Remove a hook */
+void del_hook(int h_idx, hook_type hook)
+{
+ hooks_chain *c = hooks_heads[h_idx], *p = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (c->hook != hook))
+ {
+ p = c;
+ c = c->next;
+ }
+
+ /* Remove it */
+ if (c != NULL)
+ {
+ if (p == NULL)
+ {
+ hooks_heads[h_idx] = c->next;
+ FREE(c, hooks_chain);
+ }
+ else
+ {
+ p->next = c->next;
+ FREE(c, hooks_chain);
+ }
+ }
+}
+
+/* get the next argument */
+static hook_return param_pile[MAX_ARGS];
+static int get_next_arg_pos = 0;
+static int get_next_arg_pile_pos = 0;
+s32b get_next_arg(const char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 'd':
+ case 'l':
+ return (param_pile[get_next_arg_pile_pos++].num);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+char* get_next_arg_str(const char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 's':
+ return (char*)(param_pile[get_next_arg_pile_pos++].str);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+object_type* get_next_arg_obj() {
+ object_type *o_ptr = param_pile[get_next_arg_pile_pos++].o_ptr;
+ assert(o_ptr != NULL);
+ return o_ptr;
+}
+
+
+/* Actually process the hooks */
+int process_hooks_restart = FALSE;
+hook_return process_hooks_return[20];
+static bool_ vprocess_hooks_return (int h_idx, char *ret, char *fmt, va_list *ap)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+ va_list real_ap;
+
+ while (c != NULL)
+ {
+ if (c->type == HOOK_TYPE_C)
+ {
+ int i = 0, nb = 0;
+
+ /* Push all args in the pile */
+ i = 0;
+ COPY(&real_ap, ap, va_list);
+ while (fmt[i])
+ {
+ switch (fmt[i])
+ {
+ case 'O':
+ param_pile[nb++].o_ptr = va_arg(real_ap, object_type *);
+ break;
+ case 's':
+ param_pile[nb++].str = va_arg(real_ap, char *);
+ break;
+ case 'd':
+ case 'l':
+ param_pile[nb++].num = va_arg(real_ap, s32b);
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ i++;
+ }
+
+ get_next_arg_pos = 0;
+ get_next_arg_pile_pos = 0;
+ if (c->hook(fmt))
+ {
+ return TRUE;
+ }
+
+ /* Should we restart ? */
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ {
+ c = c->next;
+ }
+ }
+ else if (c->type == HOOK_TYPE_NEW)
+ {
+ /* Skip; handled in process_hooks_new */
+ c = c->next;
+ }
+ else
+ {
+ msg_format("Unkown hook type %d, name %s", c->type, c->name);
+ c = c->next;
+ }
+ }
+
+ return FALSE;
+}
+
+bool_ process_hooks_ret(int h_idx, char *ret, char *fmt, ...)
+{
+ va_list ap;
+ bool_ r;
+
+ va_start(ap, fmt);
+ r = vprocess_hooks_return (h_idx, ret, fmt, &ap);
+ va_end(ap);
+ return (r);
+}
+
+bool_ process_hooks(int h_idx, char *fmt, ...)
+{
+ va_list ap;
+ bool_ ret;
+
+ va_start(ap, fmt);
+ ret = vprocess_hooks_return (h_idx, "", fmt, &ap);
+ va_end(ap);
+ return (ret);
+}
+
+bool_ process_hooks_new(int h_idx, void *in, void *out)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+
+ while (c != NULL)
+ {
+ /* Only new-style hooks; skip the rest. */
+ if (c->type != HOOK_TYPE_NEW)
+ {
+ c = c->next;
+ continue;
+ }
+
+ /* Invoke hook function; stop processing if
+ the hook returns TRUE */
+ if (c->hook_f(c->hook_data, in, out))
+ {
+ return TRUE;
+ }
+
+ /* Should we restart processing at the beginning? */
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ {
+ c = c->next;
+ }
+ }
+
+ return FALSE;
+}