/* * 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 /******** 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) { new_ = new hooks_chain(); memset(new_, 0, sizeof(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; delete c; } else { p->next = c->next; delete c; } } } /* 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, const char *ret, const 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, const char *ret, const 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, const 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; }