#include #include #include "log.h" #include "lephisto.h" #include "hook.h" // The hook. typedef struct Hook_ { int id; // Unique id. unsigned int parent; // Mission it's connected to. char* func; // Function returned. char* stack; // Stack it's a part of. int delete; // Indicates it should be deleted when possible. } Hook; // The stack. static unsigned int hook_id = 0; // Unique hook id. static Hook* hook_stack = NULL; static int hook_mstack = 0; static int hook_nstack = 0; static int hook_runningstack = 0; // Check if stack is running. // Extern. extern int misn_run(Mission* misn, char* func); // Intern. static int hook_run(Hook* hook); static int hook_run(Hook* hook) { int i; Mission* misn; if(hook->delete) return 0; // Hook should be deleted not run. // Locate the mission. for(i = 0; i < MISSION_MAX; i++) if(player_missions[i].id == hook->parent) break; if(i >= MISSION_MAX) { WARN("Trying to run hook with parent not in player mission stack!"); return -1; } misn = &player_missions[i]; if(misn_run(misn, hook->func)) // Error has accured. WARN("Hook [%s] '%d' -> '%s' failed", hook->stack, hook->id, hook->func); return 0; } // Add/Remove hooks. int hook_add(unsigned int parent, char* func, char* stack) { Hook* new_hook; // If the memory must grow. if(hook_nstack+1 > hook_mstack) { hook_mstack += 5; hook_stack = realloc(hook_stack, hook_mstack*sizeof(Hook)); } // Create the new hook. new_hook = &hook_stack[hook_nstack]; new_hook->id = ++hook_id; new_hook->parent = parent; new_hook->func = func; new_hook->stack = stack; new_hook->delete = 0; hook_nstack++; return new_hook->id; } void hook_rm(int id) { int l, m, h; l = 0; h = hook_nstack-1; while(l <= h) { m = (l+h)/2; if(hook_stack[m].id > id) h = m-1; else if(hook_stack[m].id < id) l = m+1; else break; } if(hook_runningstack) { hook_stack[m].delete = 1; return; } // Last hook, just clip the stack. if(m == (hook_nstack-1)) { hook_nstack--; return; } // Move it! memmove(&hook_stack[m], &hook_stack[m], sizeof(Hook)*(hook_nstack-(m+1))); hook_nstack--; } void hook_rmParent(unsigned int parent) { int i; for(i = 0; i < hook_nstack; i++) if(parent == hook_stack[i].parent) { hook_rm(hook_stack[i].id); if(!hook_runningstack) i--; } } // Run all hooks off the stack. int hooks_run(char* stack) { int i; hook_runningstack = 1; // Running hooks. for(i = 0; i < hook_nstack; i++) if((strcmp(stack, hook_stack[i].stack)==0) && !hook_stack[i].delete) { hook_run(&hook_stack[i]); } hook_runningstack = 0; // Not running hooks anymore. for(i = 0; i < hook_nstack; i++) if((strcmp(stack, hook_stack[i].stack)==0) && hook_stack[i].delete) { hook_rm(hook_stack[i].id); i--; } return 0; } // Run a single hook by id. void hook_runID(int id) { int i; for(i = 0; i < hook_nstack; i++) if(hook_stack[i].id == id) { hook_run(&hook_stack[i]); return; } DEBUG("Attempting to run hook of id '%d' which is not in the stack", id); } // Clean upi after ourselves. void hook_cleanup(void) { free(hook_stack); hook_stack = NULL; // Sane defaults just in case. hook_nstack = 0; hook_mstack = 0; }