diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/HPM.c | 696 | ||||
-rw-r--r-- | src/common/HPM.h | 66 | ||||
-rw-r--r-- | src/common/HPMDataCheck.h | 1 | ||||
-rw-r--r-- | src/common/HPMi.h | 121 | ||||
-rw-r--r-- | src/common/cbasetypes.h | 2 | ||||
-rw-r--r-- | src/common/console.c | 286 | ||||
-rw-r--r-- | src/common/console.h | 18 | ||||
-rw-r--r-- | src/common/core.c | 35 | ||||
-rw-r--r-- | src/common/core.h | 4 | ||||
-rw-r--r-- | src/common/db.h | 1321 | ||||
-rw-r--r-- | src/common/mmo.h | 7 | ||||
-rw-r--r-- | src/common/socket.c | 133 | ||||
-rw-r--r-- | src/common/socket.h | 26 | ||||
-rw-r--r-- | src/common/timer.c | 34 |
14 files changed, 1558 insertions, 1192 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c index 0316f9494..578e90bbc 100644 --- a/src/common/HPM.c +++ b/src/common/HPM.c @@ -43,28 +43,52 @@ DBMap *datacheck_db; int datacheck_version; const struct s_HPMDataCheck *datacheck_data; -void hplugin_trigger_event(enum hp_event_types type) { - unsigned int i; - for( i = 0; i < HPM->plugin_count; i++ ) { - if( HPM->plugins[i]->hpi->event[type] != NULL ) - (HPM->plugins[i]->hpi->event[type])(); +/** + * Executes an event on all loaded plugins. + * + * @param type The event type to trigger. + */ +void hplugin_trigger_event(enum hp_event_types type) +{ + int i; + for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) { + struct hplugin *plugin = VECTOR_INDEX(HPM->plugins, i); + if (plugin->hpi->event[type] != NULL) + plugin->hpi->event[type](); } } -void hplugin_export_symbol(void *var, char *name) { - RECREATE(HPM->symbols, struct hpm_symbol *, ++HPM->symbol_count); - CREATE(HPM->symbols[HPM->symbol_count - 1] ,struct hpm_symbol, 1); - HPM->symbols[HPM->symbol_count - 1]->name = name; - HPM->symbols[HPM->symbol_count - 1]->ptr = var; +/** + * Exports a symbol to the shared symbols list. + * + * @param value The symbol value. + * @param name The symbol name. + */ +void hplugin_export_symbol(void *value, const char *name) +{ + struct hpm_symbol *symbol = NULL; + CREATE(symbol ,struct hpm_symbol, 1); + symbol->name = name; + symbol->ptr = value; + VECTOR_ENSURE(HPM->symbols, 1, 1); + VECTOR_PUSH(HPM->symbols, symbol); } -void *hplugin_import_symbol(char *name, unsigned int pID) { - unsigned int i; +/** + * Imports a shared symbol. + * + * @param name The symbol name. + * @param pID The requesting plugin ID. + * @return The symbol value. + * @retval NULL if the symbol wasn't found. + */ +void *hplugin_import_symbol(char *name, unsigned int pID) +{ + int i; + ARR_FIND(0, VECTOR_LENGTH(HPM->symbols), i, strcmp(VECTOR_INDEX(HPM->symbols, i)->name, name) == 0); - for( i = 0; i < HPM->symbol_count; i++ ) { - if( strcmp(HPM->symbols[i]->name,name) == 0 ) - return HPM->symbols[i]->ptr; - } + if (i != VECTOR_LENGTH(HPM->symbols)) + return VECTOR_INDEX(HPM->symbols, i)->ptr; ShowError("HPM:get_symbol:%s: '"CL_WHITE"%s"CL_RESET"' not found!\n",HPM->pid2name(pID),name); return NULL; @@ -81,40 +105,60 @@ bool hplugin_iscompatible(char* version) { return ( req_major == HPM->version[0] && req_minor <= HPM->version[1] ) ? true : false; } -bool hplugin_exists(const char *filename) { - unsigned int i; - for(i = 0; i < HPM->plugin_count; i++) { - if( strcmpi(HPM->plugins[i]->filename,filename) == 0 ) +/** + * Checks whether a plugin is currently loaded + * + * @param filename The plugin filename. + * @retval true if the plugin exists and is currently loaded. + * @retval false otherwise. + */ +bool hplugin_exists(const char *filename) +{ + int i; + for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) { + if (strcmpi(VECTOR_INDEX(HPM->plugins, i)->filename,filename) == 0) return true; } return false; } -struct hplugin *hplugin_create(void) { - RECREATE(HPM->plugins, struct hplugin *, ++HPM->plugin_count); - CREATE(HPM->plugins[HPM->plugin_count - 1], struct hplugin, 1); - HPM->plugins[HPM->plugin_count - 1]->idx = HPM->plugin_count - 1; - HPM->plugins[HPM->plugin_count - 1]->filename = NULL; - return HPM->plugins[HPM->plugin_count - 1]; + +/** + * Initializes the data structure for a new plugin and registers it. + * + * @return A (retained) pointer to the initialized data. + */ +struct hplugin *hplugin_create(void) +{ + struct hplugin *plugin = NULL; + CREATE(plugin, struct hplugin, 1); + plugin->idx = (int)VECTOR_LENGTH(HPM->plugins); + plugin->filename = NULL; + VECTOR_ENSURE(HPM->plugins, 1, 1); + VECTOR_PUSH(HPM->plugins, plugin); + return plugin; } -bool hplugins_addpacket(unsigned short cmd, unsigned short length, void (*receive) (int fd), unsigned int point,unsigned int pluginID) { +bool hplugins_addpacket(unsigned short cmd, unsigned short length, void (*receive) (int fd), unsigned int point, unsigned int pluginID) +{ struct HPluginPacket *packet; - unsigned int i; + int i; - if( point >= hpPHP_MAX ) { + if (point >= hpPHP_MAX) { ShowError("HPM->addPacket:%s: unknown point '%u' specified for packet 0x%04x (len %d)\n",HPM->pid2name(pluginID),point,cmd,length); return false; } - for(i = 0; i < HPM->packetsc[point]; i++) { - if( HPM->packets[point][i].cmd == cmd ) { - ShowError("HPM->addPacket:%s: can't add packet 0x%04x, already in use by '%s'!",HPM->pid2name(pluginID),cmd,HPM->pid2name(HPM->packets[point][i].pluginID)); + for (i = 0; i < VECTOR_LENGTH(HPM->packets[point]); i++) { + if (VECTOR_INDEX(HPM->packets[point], i).cmd == cmd ) { + ShowError("HPM->addPacket:%s: can't add packet 0x%04x, already in use by '%s'!", + HPM->pid2name(pluginID), cmd, HPM->pid2name(VECTOR_INDEX(HPM->packets[point], i).pluginID)); return false; } } - RECREATE(HPM->packets[point], struct HPluginPacket, ++HPM->packetsc[point]); - packet = &HPM->packets[point][HPM->packetsc[point] - 1]; + VECTOR_ENSURE(HPM->packets[point], 1, 1); + VECTOR_PUSHZEROED(HPM->packets[point]); + packet = &VECTOR_LAST(HPM->packets[point]); packet->pluginID = pluginID; packet->cmd = cmd; @@ -124,136 +168,158 @@ bool hplugins_addpacket(unsigned short cmd, unsigned short length, void (*receiv return true; } -void hplugins_grabHPData(struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr) +/** + * Validates and if necessary initializes a plugin data store. + * + * @param type[in] The data store type. + * @param storeptr[in,out] A pointer to the store. + * @param initialize Whether the store should be initialized in case it isn't. + * @retval false if the store is an invalid or mismatching type. + * @retval true if the store is a valid type. + * + * @remark + * If \c storeptr is a pointer to a NULL pointer (\c storeptr itself can't + * be NULL), two things may happen, depending on the \c initialize value: + * if false, then \c storeptr isn't changed; if true, then \c storeptr is + * initialized through \c HPM->data_store_create() and ownership is passed + * to the caller. + */ +bool hplugin_data_store_validate(enum HPluginDataTypes type, struct hplugin_data_store **storeptr, bool initialize) { - /* record address */ + struct hplugin_data_store *store; + nullpo_retr(false, storeptr); + store = *storeptr; + if (!initialize && store == NULL) + return true; + switch (type) { /* core-handled */ case HPDT_SESSION: - ret->HPDataSRCPtr = (void**)(&((struct socket_data *)ptr)->hdata); - ret->hdatac = &((struct socket_data *)ptr)->hdatac; break; - /* goes to sub */ default: - if (HPM->grabHPDataSub) { - if (HPM->grabHPDataSub(ret,type,ptr)) - return; - ShowError("HPM:HPM:grabHPData failed, unknown type %d!\n",type); - } else { - ShowError("HPM:grabHPData failed, type %d needs sub-handler!\n",type); + if (HPM->data_store_validate_sub == NULL) { + ShowError("HPM:validateHPData failed, type %d needs sub-handler!\n",type); + return false; + } + if (!HPM->data_store_validate_sub(type, storeptr, initialize)) { + ShowError("HPM:HPM:validateHPData failed, unknown type %d!\n",type); + return false; } - ret->HPDataSRCPtr = NULL; - ret->hdatac = NULL; - return; + break; + } + if (initialize && (!store || store->type == HPDT_UNKNOWN)) { + HPM->data_store_create(storeptr, type); + store = *storeptr; } + if (store->type != type) { + ShowError("HPM:HPM:validateHPData failed, store type mismatch %d != %d.\n",store->type, type); + return false; + } + return true; } -void hplugins_addToHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, void *data, unsigned int index, bool autofree) +/** + * Adds an entry to a plugin data store. + * + * @param type[in] The store type. + * @param pluginID[in] The plugin identifier. + * @param storeptr[in,out] A pointer to the store. The store will be initialized if necessary. + * @param data[in] The data entry to add. + * @param classid[in] The entry class identifier. + * @param autofree[in] Whether the entry should be automatically freed when removed. + */ +void hplugins_addToHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store **storeptr, void *data, uint32 classid, bool autofree) { - struct HPluginData *HPData, **HPDataSRC; - struct HPDataOperationStorage action; - unsigned int i, max; - - HPM->grabHPData(&action,type,ptr); + struct hplugin_data_store *store; + struct hplugin_data_entry *entry; + int i; + nullpo_retv(storeptr); - if (action.hdatac == NULL) { /* woo it failed! */ - ShowError("HPM:addToHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index); + if (!HPM->data_store_validate(type, storeptr, true)) { + /* woo it failed! */ + ShowError("HPM:addToHPData:%s: failed, type %d (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid); return; } - - /* flag */ - HPDataSRC = *(action.HPDataSRCPtr); - max = *(action.hdatac); + store = *storeptr; /* duplicate check */ - for (i = 0; i < max; i++) { - if (HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index) { - ShowError("HPM:addToHPData:%s: error! attempting to insert duplicate struct of id %u and index %u\n",HPM->pid2name(pluginID),pluginID,index); - return; - } + ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid); + if (i != VECTOR_LENGTH(store->entries)) { + ShowError("HPM:addToHPData:%s: error! attempting to insert duplicate struct of id %u and classid %u\n", HPM->pid2name(pluginID), pluginID, classid); + return; } - /* HPluginData is always same size, probably better to use the ERS (with reasonable chunk size e.g. 10/25/50) */ - CREATE(HPData, struct HPluginData, 1); + /* hplugin_data_entry is always same size, probably better to use the ERS (with reasonable chunk size e.g. 10/25/50) */ + CREATE(entry, struct hplugin_data_entry, 1); /* input */ - HPData->pluginID = pluginID; - HPData->type = index; - HPData->flag.free = autofree ? 1 : 0; - HPData->data = data; - - /* resize */ - *(action.hdatac) += 1; - RECREATE(*(action.HPDataSRCPtr),struct HPluginData *,*(action.hdatac)); + entry->pluginID = pluginID; + entry->classid = classid; + entry->flag.free = autofree ? 1 : 0; + entry->data = data; - /* RECREATE modified the address */ - HPDataSRC = *(action.HPDataSRCPtr); - HPDataSRC[*(action.hdatac) - 1] = HPData; + VECTOR_ENSURE(store->entries, 1, 1); + VECTOR_PUSH(store->entries, entry); } -void *hplugins_getFromHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index) +/** + * Retrieves an entry from a plugin data store. + * + * @param type[in] The store type. + * @param pluginID[in] The plugin identifier. + * @param store[in] The store. + * @param classid[in] The entry class identifier. + * + * @return The retrieved entry, or NULL. + */ +void *hplugins_getFromHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid) { - struct HPDataOperationStorage action; - struct HPluginData **HPDataSRC; - unsigned int i, max; - - HPM->grabHPData(&action,type,ptr); + int i; - if (action.hdatac == NULL) { /* woo it failed! */ - ShowError("HPM:getFromHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index); + if (!HPM->data_store_validate(type, &store, false)) { + /* woo it failed! */ + ShowError("HPM:getFromHPData:%s: failed, type %d (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid); return NULL; } + if (!store) + return NULL; - /* flag */ - HPDataSRC = *(action.HPDataSRCPtr); - max = *(action.hdatac); - - for (i = 0; i < max; i++) { - if (HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index) - return HPDataSRC[i]->data; - } + ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid); + if (i != VECTOR_LENGTH(store->entries)) + return VECTOR_INDEX(store->entries, i)->data; return NULL; } -void hplugins_removeFromHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index) +/** + * Removes an entry from a plugin data store. + * + * @param type[in] The store type. + * @param pluginID[in] The plugin identifier. + * @param store[in] The store. + * @param classid[in] The entry class identifier. + */ +void hplugins_removeFromHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid) { - struct HPDataOperationStorage action; - struct HPluginData **HPDataSRC; - unsigned int i, max; - - HPM->grabHPData(&action,type,ptr); + struct hplugin_data_entry *entry; + int i; - if (action.hdatac == NULL) { /* woo it failed! */ - ShowError("HPM:removeFromHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index); + if (!HPM->data_store_validate(type, &store, false)) { + /* woo it failed! */ + ShowError("HPM:removeFromHPData:%s: failed, type %d (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid); return; } + if (!store) + return; - /* flag */ - HPDataSRC = *(action.HPDataSRCPtr); - max = *(action.hdatac); - - for (i = 0; i < max; i++) { - if (HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index) - break; - } - - if (i != max) { - unsigned int cursor; - - aFree(HPDataSRC[i]->data);/* when its removed we delete it regardless of autofree */ - aFree(HPDataSRC[i]); - HPDataSRC[i] = NULL; + ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid); + if (i == VECTOR_LENGTH(store->entries)) + return; - for (i = 0, cursor = 0; i < max; i++) { - if (HPDataSRC[i] == NULL) - continue; - if (i != cursor) - HPDataSRC[cursor] = HPDataSRC[i]; - cursor++; - } - *(action.hdatac) = cursor; - } + entry = VECTOR_INDEX(store->entries, i); + VECTOR_ERASE(store->entries, i); // Erase and compact + aFree(entry->data); // when it's removed we delete it regardless of autofree + aFree(entry); } /* TODO: add ability for tracking using pID for the upcoming runtime load/unload support. */ @@ -303,9 +369,9 @@ bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecF return false; } - ARR_FIND(0, cmdline->args_data_count, i, strcmp(cmdline->args_data[i].name, name) == 0); + ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), i, strcmp(VECTOR_INDEX(cmdline->args_data, i).name, name) == 0); - if (i < cmdline->args_data_count) { + if (i != VECTOR_LENGTH(cmdline->args_data)) { ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID)); return false; } @@ -313,25 +379,36 @@ bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecF return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL); } +/** + * Adds a configuration listener for a plugin. + * + * @param pluginID The plugin identifier. + * @param type The configuration type to listen for. + * @param name The configuration entry name. + * @param func The callback function. + * @retval true if the listener was added successfully. + * @retval false in case of error. + */ bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *name, void (*func) (const char *val)) { struct HPConfListenStorage *conf; - unsigned int i; + int i; if (type >= HPCT_MAX) { ShowError("HPM->addConf:%s: unknown point '%u' specified for config '%s'\n",HPM->pid2name(pluginID),type,name); return false; } - for (i = 0; i < HPM->confsc[type]; i++) { - if (!strcmpi(name,HPM->confs[type][i].key)) { - ShowError("HPM->addConf:%s: duplicate '%s', already in use by '%s'!",HPM->pid2name(pluginID),name,HPM->pid2name(HPM->confs[type][i].pluginID)); - return false; - } + ARR_FIND(0, VECTOR_LENGTH(HPM->config_listeners[type]), i, strcmpi(name, VECTOR_INDEX(HPM->config_listeners[type], i).key) == 0); + if (i != VECTOR_LENGTH(HPM->config_listeners[type])) { + ShowError("HPM->addConf:%s: duplicate '%s', already in use by '%s'!", + HPM->pid2name(pluginID), name, HPM->pid2name(VECTOR_INDEX(HPM->config_listeners[type], i).pluginID)); + return false; } - RECREATE(HPM->confs[type], struct HPConfListenStorage, ++HPM->confsc[type]); - conf = &HPM->confs[type][HPM->confsc[type] - 1]; + VECTOR_ENSURE(HPM->config_listeners[type], 1, 1); + VECTOR_PUSHZEROED(HPM->config_listeners[type]); + conf = &VECTOR_LAST(HPM->config_listeners[type]); conf->pluginID = pluginID; safestrncpy(conf->key, name, HPM_ADDCONF_LENGTH); @@ -477,30 +554,23 @@ struct hplugin *hplugin_load(const char* filename) { return plugin; } +/** + * Unloads and unregisters a plugin. + * + * @param plugin The plugin data. + */ void hplugin_unload(struct hplugin* plugin) { + int i; if (plugin->filename) aFree(plugin->filename); if (plugin->dll) plugin_close(plugin->dll); /* TODO: for manual packet unload */ /* - Go through known packets and unlink any belonging to the plugin being removed */ - if (!HPM->off) { - unsigned int i, cursor; - for (cursor = 0; cursor < HPM->plugin_count; cursor++) { - if (HPM->plugins[cursor]->idx != plugin->idx) - continue; - HPM->plugins[cursor] = NULL; - break; - } - for(i = cursor + 1; i < HPM->plugin_count; i++) { - HPM->plugins[cursor] = HPM->plugins[i]; - cursor++; - } - if (!(HPM->plugin_count = cursor)) { - aFree(HPM->plugins); - HPM->plugins = NULL; - } + ARR_FIND(0, VECTOR_LENGTH(HPM->plugins), i, VECTOR_INDEX(HPM->plugins, i)->idx == plugin->idx); + if (i != VECTOR_LENGTH(HPM->plugins)) { + VECTOR_ERASE(HPM->plugins, i); } aFree(plugin); } @@ -510,8 +580,8 @@ void hplugin_unload(struct hplugin* plugin) */ CMDLINEARG(loadplugin) { - RECREATE(HPM->cmdline_plugins, char *, ++HPM->cmdline_plugins_count); - HPM->cmdline_plugins[HPM->cmdline_plugins_count-1] = aStrdup(params); + VECTOR_ENSURE(HPM->cmdline_load_plugins, 1, 1); + VECTOR_PUSH(HPM->cmdline_load_plugins, aStrdup(params)); return true; } @@ -535,9 +605,9 @@ void hplugins_config_read(void) { return; plist = libconfig->lookup(&plugins_conf, "plugins_list"); - for (i = 0; i < HPM->cmdline_plugins_count; i++) { + for (i = 0; i < VECTOR_LENGTH(HPM->cmdline_load_plugins); i++) { config_setting_t *entry = libconfig->setting_add(plist, NULL, CONFIG_TYPE_STRING); - config_setting_set_string(entry, HPM->cmdline_plugins[i]); + config_setting_set_string(entry, VECTOR_INDEX(HPM->cmdline_load_plugins, i)); } if (plist != NULL) { @@ -584,83 +654,117 @@ void hplugins_config_read(void) { } libconfig->destroy(&plugins_conf); - if( HPM->plugin_count ) - ShowStatus("HPM: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded, type '"CL_WHITE"plugins"CL_RESET"' to list them\n", HPM->plugin_count); + if (VECTOR_LENGTH(HPM->plugins)) + ShowStatus("HPM: There are '"CL_WHITE"%"PRIuS""CL_RESET"' plugins loaded, type '"CL_WHITE"plugins"CL_RESET"' to list them\n", VECTOR_LENGTH(HPM->plugins)); } -CPCMD(plugins) { - if( HPM->plugin_count == 0 ) { + +/** + * Console command: plugins + * + * Shows a list of loaded plugins. + * + * @see CPCMD() + */ +CPCMD(plugins) +{ + int i; + + if (VECTOR_LENGTH(HPM->plugins) == 0) { ShowInfo("HPC: there are no plugins loaded\n"); - } else { - unsigned int i; + return; + } - ShowInfo("HPC: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded\n",HPM->plugin_count); + ShowInfo("HPC: There are '"CL_WHITE"%"PRIuS""CL_RESET"' plugins loaded\n", VECTOR_LENGTH(HPM->plugins)); - for(i = 0; i < HPM->plugin_count; i++) { - ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n",HPM->plugins[i]->info->name,HPM->plugins[i]->filename); - } + for(i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) { + struct hplugin *plugin = VECTOR_INDEX(HPM->plugins, i); + ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n", plugin->info->name, plugin->filename); } } -/* - 0 = unknown - 1 = OK - 2 = incomplete +/** + * Parses a packet through the registered plugin. + * + * @param fd The connection fd. + * @param point The packet hooking point. + * @retval 0 unknown packet + * @retval 1 OK + * @retval 2 incomplete packet */ -unsigned char hplugins_parse_packets(int fd, enum HPluginPacketHookingPoints point) { - unsigned int i; +unsigned char hplugins_parse_packets(int fd, enum HPluginPacketHookingPoints point) +{ + struct HPluginPacket *packet = NULL; + int i; + int16 length; - for(i = 0; i < HPM->packetsc[point]; i++) { - if( HPM->packets[point][i].cmd == RFIFOW(fd,0) ) - break; - } + ARR_FIND(0, VECTOR_LENGTH(HPM->packets[point]), i, VECTOR_INDEX(HPM->packets[point], i).cmd == RFIFOW(fd,0)); - if( i != HPM->packetsc[point] ) { - struct HPluginPacket *packet = &HPM->packets[point][i]; - short length; + if (i == VECTOR_LENGTH(HPM->packets[point])) + return 0; - if( (length = packet->len) == -1 ) { - if( (length = RFIFOW(fd, 2)) > (int)RFIFOREST(fd) ) - return 2; - } + packet = &VECTOR_INDEX(HPM->packets[point], i); + length = packet->len; + if (length == -1) + length = RFIFOW(fd, 2); - packet->receive(fd); - RFIFOSKIP(fd, length); - return 1; - } + if (length > (int)RFIFOREST(fd)) + return 2; - return 0; + packet->receive(fd); + RFIFOSKIP(fd, length); + return 1; } -char *hplugins_id2name (unsigned int pid) { - unsigned int i; +/** + * Retrieves a plugin name by ID. + * + * @param pid The plugin identifier. + * @return The plugin name. + * @retval "core" if the plugin ID belongs to the Hercules core. + * @retval "UnknownPlugin" if the plugin wasn't found. + */ +char *hplugins_id2name(unsigned int pid) +{ + int i; if (pid == HPM_PID_CORE) return "core"; - for( i = 0; i < HPM->plugin_count; i++ ) { - if( HPM->plugins[i]->idx == pid ) - return HPM->plugins[i]->info->name; + for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) { + struct hplugin *plugin = VECTOR_INDEX(HPM->plugins, i); + if (plugin->idx == pid) + return plugin->info->name; } return "UnknownPlugin"; } -char* HPM_file2ptr(const char *file) { - unsigned int i; - for(i = 0; i < HPM->fnamec; i++) { - if( HPM->fnames[i].addr == file ) - return HPM->fnames[i].name; - } +/** + * Returns a retained permanent pointer to a source filename, for memory-manager reporting use. + * + * The returned pointer is safe to be used as filename in the memory manager + * functions, and it will be available during and after the memory manager + * shutdown (for memory leak reporting purposes). + * + * @param file The string/filename to retain + * @return A retained copy of the source string. + */ +const char *HPM_file2ptr(const char *file) +{ + int i; - i = HPM->fnamec; + ARR_FIND(0, HPM->filenames.count, i, HPM->filenames.data[i].addr == file); + if (i != HPM->filenames.count) { + return HPM->filenames.data[i].name; + } /* we handle this memory outside of the server's memory manager because we need it to exist after the memory manager goes down */ - HPM->fnames = realloc(HPM->fnames,(++HPM->fnamec)*sizeof(struct HPMFileNameCache)); + HPM->filenames.data = realloc(HPM->filenames.data, (++HPM->filenames.count)*sizeof(struct HPMFileNameCache)); - HPM->fnames[i].addr = file; - HPM->fnames[i].name = strdup(file); + HPM->filenames.data[i].addr = file; + HPM->filenames.data[i].name = strdup(file); - return HPM->fnames[i].name; + return HPM->filenames.data[i].name; } void* HPM_mmalloc(size_t size, const char *file, int line, const char *func) { return iMalloc->malloc(size,HPM_file2ptr(file),line,func); @@ -678,22 +782,74 @@ char* HPM_astrdup(const char *p, const char *file, int line, const char *func) { return iMalloc->astrdup(p,HPM_file2ptr(file),line,func); } -bool hplugins_parse_conf(const char *w1, const char *w2, enum HPluginConfType point) { - unsigned int i; +/** + * Parses a configuration entry through the registered plugins. + * + * @param w1 The configuration entry name. + * @param w2 The configuration entry value. + * @param point The type of configuration file. + * @retval true if a registered plugin was found to handle the entry. + * @retval false if no registered plugins could be found. + */ +bool hplugins_parse_conf(const char *w1, const char *w2, enum HPluginConfType point) +{ + int i; + ARR_FIND(0, VECTOR_LENGTH(HPM->config_listeners[point]), i, strcmpi(w1, VECTOR_INDEX(HPM->config_listeners[point], i).key) == 0); + if (i == VECTOR_LENGTH(HPM->config_listeners[point])) + return false; - /* exists? */ - for(i = 0; i < HPM->confsc[point]; i++) { - if( !strcmpi(w1,HPM->confs[point][i].key) ) - break; + VECTOR_INDEX(HPM->config_listeners[point], i).func(w2); + return true; +} + +/** + * Helper to destroy an interface's hplugin_data store and release any owned memory. + * + * The pointer will be cleared. + * + * @param storeptr[in,out] A pointer to the plugin data store. + */ +void hplugin_data_store_destroy(struct hplugin_data_store **storeptr) +{ + struct hplugin_data_store *store; + nullpo_retv(storeptr); + store = *storeptr; + if (store == NULL) + return; + + while (VECTOR_LENGTH(store->entries) > 0) { + struct hplugin_data_entry *entry = VECTOR_POP(store->entries); + if (entry->flag.free) { + aFree(entry->data); + } + aFree(entry); } + VECTOR_CLEAR(store->entries); + aFree(store); + *storeptr = NULL; +} - /* trigger and we're set! */ - if( i != HPM->confsc[point] ) { - HPM->confs[point][i].func(w2); - return true; +/** + * Helper to create and initialize an interface's hplugin_data store. + * + * The store is owned by the caller, and it should be eventually destroyed by + * \c hdata_destroy. + * + * @param storeptr[in,out] A pointer to the data store to initialize. + * @param type[in] The store type. + */ +void hplugin_data_store_create(struct hplugin_data_store **storeptr, enum HPluginDataTypes type) +{ + struct hplugin_data_store *store; + nullpo_retv(storeptr); + + if (*storeptr == NULL) { + CREATE(*storeptr, struct hplugin_data_store, 1); } + store = *storeptr; - return false; + store->type = type; + VECTOR_INIT(store->entries); } /** @@ -747,14 +903,14 @@ void HPM_datacheck_final(void) { } void hpm_init(void) { - unsigned int i; + int i; datacheck_db = NULL; datacheck_data = NULL; datacheck_version = 0; - HPM->symbols = NULL; - HPM->plugins = NULL; - HPM->plugin_count = HPM->symbol_count = 0; + VECTOR_INIT(HPM->plugins); + VECTOR_INIT(HPM->symbols); + HPM->off = false; memcpy(&iMalloc_HPM, iMalloc, sizeof(struct malloc_interface)); @@ -772,9 +928,12 @@ void hpm_init(void) { return; } - for(i = 0; i < hpPHP_MAX; i++) { - HPM->packets[i] = NULL; - HPM->packetsc[i] = 0; + for (i = 0; i < hpPHP_MAX; i++) { + VECTOR_INIT(HPM->packets[i]); + } + + for (i = 0; i < HPCT_MAX; i++) { + VECTOR_INIT(HPM->config_listeners[i]); } #ifdef CONSOLE_INPUT @@ -782,84 +941,68 @@ void hpm_init(void) { #endif return; } + +/** + * Releases the retained filenames cache. + */ void hpm_memdown(void) { - /* this memory is handled outside of the server's memory manager and thus cleared after memory manager goes down */ - - if (HPM->fnames) { - unsigned int i; - for (i = 0; i < HPM->fnamec; i++) { - free(HPM->fnames[i].name); + /* this memory is handled outside of the server's memory manager and + * thus cleared after memory manager goes down */ + if (HPM->filenames.count) { + int i; + for (i = 0; i < HPM->filenames.count; i++) { + free(HPM->filenames.data[i].name); } - free(HPM->fnames); + free(HPM->filenames.data); + HPM->filenames.data = NULL; + HPM->filenames.count = 0; } } -void hpm_final(void) { - unsigned int i; + +void hpm_final(void) +{ + int i; HPM->off = true; - if( HPM->plugins ) - { - for( i = 0; i < HPM->plugin_count; i++ ) { - HPM->unload(HPM->plugins[i]); - } - aFree(HPM->plugins); + while (VECTOR_LENGTH(HPM->plugins)) { + HPM->unload(VECTOR_LAST(HPM->plugins)); } + VECTOR_CLEAR(HPM->plugins); - if( HPM->symbols ) - { - for( i = 0; i < HPM->symbol_count; i++ ) { - aFree(HPM->symbols[i]); - } - aFree(HPM->symbols); + while (VECTOR_LENGTH(HPM->symbols)) { + aFree(VECTOR_POP(HPM->symbols)); } + VECTOR_CLEAR(HPM->symbols); - for( i = 0; i < hpPHP_MAX; i++ ) { - if( HPM->packets[i] ) - aFree(HPM->packets[i]); + for (i = 0; i < hpPHP_MAX; i++) { + VECTOR_CLEAR(HPM->packets[i]); } - for( i = 0; i < HPCT_MAX; i++ ) { - if( HPM->confsc[i] ) - aFree(HPM->confs[i]); + for (i = 0; i < HPCT_MAX; i++) { + VECTOR_CLEAR(HPM->config_listeners[i]); } - if (HPM->cmdline_plugins) { - int j; - for (j = 0; j < HPM->cmdline_plugins_count; j++) - aFree(HPM->cmdline_plugins[j]); - aFree(HPM->cmdline_plugins); - HPM->cmdline_plugins = NULL; - HPM->cmdline_plugins_count = 0; + + while (VECTOR_LENGTH(HPM->cmdline_load_plugins)) { + aFree(VECTOR_POP(HPM->cmdline_load_plugins)); } + VECTOR_CLEAR(HPM->cmdline_load_plugins); /* HPM->fnames is cleared after the memory manager goes down */ iMalloc->post_shutdown = hpm_memdown; return; } -void hpm_defaults(void) { - unsigned int i; +void hpm_defaults(void) +{ HPM = &HPM_s; - HPM->fnames = NULL; - HPM->fnamec = 0; + memset(&HPM->filenames, 0, sizeof(HPM->filenames)); + VECTOR_INIT(HPM->cmdline_load_plugins); HPM->force_return = false; HPM->hooking = false; /* */ - HPM->fnames = NULL; - HPM->fnamec = 0; - for(i = 0; i < hpPHP_MAX; i++) { - HPM->packets[i] = NULL; - HPM->packetsc[i] = 0; - } - for(i = 0; i < HPCT_MAX; i++) { - HPM->confs[i] = NULL; - HPM->confsc[i] = 0; - } - HPM->cmdline_plugins = NULL; - HPM->cmdline_plugins_count = 0; - /* */ HPM->init = hpm_init; HPM->final = hpm_final; @@ -876,10 +1019,13 @@ void hpm_defaults(void) { HPM->parse_packets = hplugins_parse_packets; HPM->load_sub = NULL; HPM->addhook_sub = NULL; - HPM->grabHPData = hplugins_grabHPData; - HPM->grabHPDataSub = NULL; HPM->parseConf = hplugins_parse_conf; HPM->DataCheck = HPM_DataCheck; HPM->datacheck_init = HPM_datacheck_init; HPM->datacheck_final = HPM_datacheck_final; + + HPM->data_store_destroy = hplugin_data_store_destroy; + HPM->data_store_create = hplugin_data_store_create; + HPM->data_store_validate = hplugin_data_store_validate; + HPM->data_store_validate_sub = NULL; } diff --git a/src/common/HPM.h b/src/common/HPM.h index c13132cfc..5420e5300 100644 --- a/src/common/HPM.h +++ b/src/common/HPM.h @@ -9,6 +9,7 @@ #endif #include "common/hercules.h" +#include "common/db.h" #include "common/HPMi.h" #ifdef WIN32 @@ -56,18 +57,32 @@ struct hplugin { struct HPMi_interface *hpi; }; +/** + * Symbols shared between core and plugins. + */ struct hpm_symbol { - char *name; - void *ptr; + const char *name; ///< The symbol name + void *ptr; ///< The symbol value }; -struct HPluginData { - unsigned int pluginID; - unsigned int type; +/** + * A plugin custom data, to be injected in various interfaces and objects. + */ +struct hplugin_data_entry { + uint32 pluginID; ///< The owner plugin identifier. + uint32 classid; ///< The entry's object type, managed by the plugin (for plugins that need more than one entry). struct { - unsigned int free : 1; + unsigned int free : 1; ///< Whether the entry data should be automatically cleared by the HPM. } flag; - void *data; + void *data; ///< The entry data. +}; + +/** + * A store for plugin custom data entries. + */ +struct hplugin_data_store { + enum HPluginDataTypes type; ///< The store type. + VECTOR_DECL(struct hplugin_data_entry *) entries; ///< The store entries. }; struct HPluginPacket { @@ -82,10 +97,6 @@ struct HPMFileNameCache { char *name; }; -struct HPDataOperationStorage { - void **HPDataSRCPtr; - unsigned int *hdatac; -}; /* */ struct HPConfListenStorage { unsigned int pluginID; @@ -102,22 +113,20 @@ struct HPM_interface { /* hooking */ bool force_return; /* data */ - struct hplugin **plugins; - unsigned int plugin_count; - struct hpm_symbol **symbols; - unsigned int symbol_count; + VECTOR_DECL(struct hplugin *) plugins; + VECTOR_DECL(struct hpm_symbol *) symbols; /* packet hooking points */ - struct HPluginPacket *packets[hpPHP_MAX]; - unsigned int packetsc[hpPHP_MAX]; + VECTOR_DECL(struct HPluginPacket) packets[hpPHP_MAX]; /* plugin file ptr caching */ - struct HPMFileNameCache *fnames; - unsigned int fnamec; + struct { + // This doesn't use a VECTOR because it needs to exist after the memory manager goes down. + int count; + struct HPMFileNameCache *data; + } filenames; /* config listen */ - struct HPConfListenStorage *confs[HPCT_MAX]; - unsigned int confsc[HPCT_MAX]; + VECTOR_DECL(struct HPConfListenStorage) config_listeners[HPCT_MAX]; /** Plugins requested through the command line */ - char **cmdline_plugins; - int cmdline_plugins_count; + VECTOR_DECL(char *) cmdline_load_plugins; /* funcs */ void (*init) (void); void (*final) (void); @@ -128,21 +137,24 @@ struct HPM_interface { bool (*iscompatible) (char* version); void (*event) (enum hp_event_types type); void *(*import_symbol) (char *name, unsigned int pID); - void (*share) (void *, char *); + void (*share) (void *value, const char *name); void (*config_read) (void); char *(*pid2name) (unsigned int pid); unsigned char (*parse_packets) (int fd, enum HPluginPacketHookingPoints point); void (*load_sub) (struct hplugin *plugin); bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID); - void (*grabHPData) (struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr); - /* for server-specific HPData e.g. map_session_data */ - bool (*grabHPDataSub) (struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr); /* for custom config parsing */ bool (*parseConf) (const char *w1, const char *w2, enum HPluginConfType point); /* validates plugin data */ bool (*DataCheck) (struct s_HPMDataCheck *src, unsigned int size, int version, char *name); void (*datacheck_init) (const struct s_HPMDataCheck *src, unsigned int length, int version); void (*datacheck_final) (void); + + void (*data_store_create) (struct hplugin_data_store **storeptr, enum HPluginDataTypes type); + void (*data_store_destroy) (struct hplugin_data_store **storeptr); + bool (*data_store_validate) (enum HPluginDataTypes type, struct hplugin_data_store **storeptr, bool initialize); + /* for server-specific HPData e.g. map_session_data */ + bool (*data_store_validate_sub) (enum HPluginDataTypes type, struct hplugin_data_store **storeptr, bool initialize); }; CMDLINEARG(loadplugin); diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h index 4fd16114b..510ea9d4e 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -201,6 +201,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { #ifdef COMMON_SOCKET_H { "hSockOpt", sizeof(struct hSockOpt), SERVER_TYPE_ALL }, { "s_subnet", sizeof(struct s_subnet), SERVER_TYPE_ALL }, + { "s_subnet_vector", sizeof(struct s_subnet_vector), SERVER_TYPE_ALL }, { "socket_data", sizeof(struct socket_data), SERVER_TYPE_ALL }, { "socket_interface", sizeof(struct socket_interface), SERVER_TYPE_ALL }, #else diff --git a/src/common/HPMi.h b/src/common/HPMi.h index e03f52e3b..9a61dd256 100644 --- a/src/common/HPMi.h +++ b/src/common/HPMi.h @@ -14,6 +14,7 @@ struct script_state; struct AtCommandInfo; struct socket_data; struct map_session_data; +struct hplugin_data_store; #define HPM_VERSION "1.1" #define HPM_ADDCONF_LENGTH 40 @@ -59,30 +60,34 @@ enum HPluginHookType { HOOK_TYPE_POST, }; +/** + * Data types for plugin custom data. + */ enum HPluginDataTypes { - HPDT_SESSION, - HPDT_MSD, - HPDT_NPCD, - HPDT_MAP, - HPDT_INSTANCE, - HPDT_GUILD, - HPDT_PARTY, - HPDT_MOBDB, - HPDT_MOBDATA, - HPDT_ITEMDATA, - HPDT_BGDATA, - HPDT_AUTOTRADE_VEND, + HPDT_UNKNOWN, ///< Unknown type (such as an uninitialized store). + HPDT_SESSION, ///< For struct socket_data. + HPDT_MSD, ///< For struct map_session_data. + HPDT_NPCD, ///< For struct npc_data. + HPDT_MAP, ///< For struct map_data. + HPDT_INSTANCE, ///< For struct instance_data. + HPDT_GUILD, ///< For struct guild. + HPDT_PARTY, ///< For struct party_data. + HPDT_MOBDB, ///< For struct mob_db. + HPDT_MOBDATA, ///< For struct mob_data. + HPDT_ITEMDATA, ///< For struct item_data. + HPDT_BGDATA, ///< For struct battleground_data. + HPDT_AUTOTRADE_VEND, ///< For struct autotrade_vending. }; /* used in macros and conf storage */ enum HPluginConfType { - HPCT_BATTLE, /* battle-conf (map-server) */ - HPCT_LOGIN, /* login-server.conf (login-server) */ - HPCT_CHAR, /* char-server.conf (char-server) */ - HPCT_CHAR_INTER, /* inter-server.conf (char-server) */ - HPCT_MAP_INTER, /* inter-server.conf (map-server) */ - HPCT_LOG, /* logs.conf (map-server) */ - HPCT_SCRIPT, /* script.conf (map-server) */ + HPCT_BATTLE, ///< battle-conf (map-server) + HPCT_LOGIN, ///< login-server.conf (login-server) + HPCT_CHAR, ///< char-server.conf (char-server) + HPCT_CHAR_INTER, ///< inter-server.conf (char-server) + HPCT_MAP_INTER, ///< inter-server.conf (map-server) + HPCT_LOG, ///< logs.conf (map-server) + HPCT_SCRIPT, ///< script.conf (map-server) HPCT_MAX, }; @@ -96,53 +101,53 @@ enum HPluginConfType { #define addArg(name, param,func,help) (HPMi->addArg(HPMi->pid,(name),(param),(cmdline_arg_ ## func),(help))) /* HPData handy redirects */ /* session[] */ -#define addToSession(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_SESSION,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromSession(ptr,index) (HPMi->getFromHPData(HPDT_SESSION,HPMi->pid,(ptr),(index))) -#define removeFromSession(ptr,index) (HPMi->removeFromHPData(HPDT_SESSION,HPMi->pid,(ptr),(index))) +#define addToSession(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_SESSION,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromSession(ptr,classid) (HPMi->getFromHPData(HPDT_SESSION,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromSession(ptr,classid) (HPMi->removeFromHPData(HPDT_SESSION,HPMi->pid,(ptr)->hdata,(classid))) /* map_session_data */ -#define addToMSD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MSD,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromMSD(ptr,index) (HPMi->getFromHPData(HPDT_MSD,HPMi->pid,(ptr),(index))) -#define removeFromMSD(ptr,index) (HPMi->removeFromHPData(HPDT_MSD,HPMi->pid,(ptr),(index))) +#define addToMSD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_MSD,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromMSD(ptr,classid) (HPMi->getFromHPData(HPDT_MSD,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromMSD(ptr,classid) (HPMi->removeFromHPData(HPDT_MSD,HPMi->pid,(ptr)->hdata,(classid))) /* npc_data */ -#define addToNPCD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_NPCD,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromNPCD(ptr,index) (HPMi->getFromHPData(HPDT_NPCD,HPMi->pid,(ptr),(index))) -#define removeFromNPCD(ptr,index) (HPMi->removeFromHPData(HPDT_NPCD,HPMi->pid,(ptr),(index))) +#define addToNPCD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_NPCD,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromNPCD(ptr,classid) (HPMi->getFromHPData(HPDT_NPCD,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromNPCD(ptr,classid) (HPMi->removeFromHPData(HPDT_NPCD,HPMi->pid,(ptr)->hdata,(classid))) /* map_data */ -#define addToMAPD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MAP,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromMAPD(ptr,index) (HPMi->getFromHPData(HPDT_MAP,HPMi->pid,(ptr),(index))) -#define removeFromMAPD(ptr,index) (HPMi->removeFromHPData(HPDT_MAP,HPMi->pid,(ptr),(index))) +#define addToMAPD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_MAP,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromMAPD(ptr,classid) (HPMi->getFromHPData(HPDT_MAP,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromMAPD(ptr,classid) (HPMi->removeFromHPData(HPDT_MAP,HPMi->pid,(ptr)->hdata,(classid))) /* party_data */ -#define addToPAD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_PARTY,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromPAD(ptr,index) (HPMi->getFromHPData(HPDT_PARTY,HPMi->pid,(ptr),(index))) -#define removeFromPAD(ptr,index) (HPMi->removeFromHPData(HPDT_PARTY,HPMi->pid,(ptr),(index))) +#define addToPAD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_PARTY,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromPAD(ptr,classid) (HPMi->getFromHPData(HPDT_PARTY,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromPAD(ptr,classid) (HPMi->removeFromHPData(HPDT_PARTY,HPMi->pid,(ptr)->hdata,(classid))) /* guild */ -#define addToGLD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_GUILD,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromGLD(ptr,index) (HPMi->getFromHPData(HPDT_GUILD,HPMi->pid,(ptr),(index))) -#define removeFromGLD(ptr,index) (HPMi->removeFromHPData(HPDT_GUILD,HPMi->pid,(ptr),(index))) +#define addToGLD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_GUILD,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromGLD(ptr,classid) (HPMi->getFromHPData(HPDT_GUILD,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromGLD(ptr,classid) (HPMi->removeFromHPData(HPDT_GUILD,HPMi->pid,(ptr)->hdata,(classid))) /* instance_data */ -#define addToINSTD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromINSTD(ptr,index) (HPMi->getFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(index))) -#define removeFromINSTD(ptr,index) (HPMi->removeFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(index))) +#define addToINSTD(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_INSTANCE,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromINSTD(ptr,classid) (HPMi->getFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromINSTD(ptr,classid) (HPMi->removeFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr)->hdata,(classid))) /* mob_db */ -#define addToMOBDB(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MOBDB,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromMOBDB(ptr,index) (HPMi->getFromHPData(HPDT_MOBDB,HPMi->pid,(ptr),(index))) -#define removeFromMOBDB(ptr,index) (HPMi->removeFromHPData(HPDT_MOBDB,HPMi->pid,(ptr),(index))) +#define addToMOBDB(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_MOBDB,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromMOBDB(ptr,classid) (HPMi->getFromHPData(HPDT_MOBDB,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromMOBDB(ptr,classid) (HPMi->removeFromHPData(HPDT_MOBDB,HPMi->pid,(ptr)->hdata,(classid))) /* mob_data */ -#define addToMOBDATA(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MOBDATA,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromMOBDATA(ptr,index) (HPMi->getFromHPData(HPDT_MOBDATA,HPMi->pid,(ptr),(index))) -#define removeFromMOBDATA(ptr,index) (HPMi->removeFromHPData(HPDT_MOBDATA,HPMi->pid,(ptr),(index))) +#define addToMOBDATA(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_MOBDATA,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromMOBDATA(ptr,classid) (HPMi->getFromHPData(HPDT_MOBDATA,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromMOBDATA(ptr,classid) (HPMi->removeFromHPData(HPDT_MOBDATA,HPMi->pid,(ptr)->hdata,(classid))) /* item_data */ -#define addToITEMDATA(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_ITEMDATA,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromITEMDATA(ptr,index) (HPMi->getFromHPData(HPDT_ITEMDATA,HPMi->pid,(ptr),(index))) -#define removeFromITEMDATA(ptr,index) (HPMi->removeFromHPData(HPDT_ITEMDATA,HPMi->pid,(ptr),(index))) +#define addToITEMDATA(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_ITEMDATA,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromITEMDATA(ptr,classid) (HPMi->getFromHPData(HPDT_ITEMDATA,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromITEMDATA(ptr,classid) (HPMi->removeFromHPData(HPDT_ITEMDATA,HPMi->pid,(ptr)->hdata,(classid))) /* battleground_data */ -#define addToBGDATA(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_BGDATA,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromBGDATA(ptr,index) (HPMi->getFromHPData(HPDT_BGDATA,HPMi->pid,(ptr),(index))) -#define removeFromBGDATA(ptr,index) (HPMi->removeFromHPData(HPDT_BGDATA,HPMi->pid,(ptr),(index))) +#define addToBGDATA(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_BGDATA,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromBGDATA(ptr,classid) (HPMi->getFromHPData(HPDT_BGDATA,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromBGDATA(ptr,classid) (HPMi->removeFromHPData(HPDT_BGDATA,HPMi->pid,(ptr)->hdata,(classid))) /* autotrade_vending */ -#define addToATVEND(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,(ptr),(data),(index),(autofree))) -#define getFromATVEND(ptr,index) (HPMi->getFromHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,(ptr),(index))) -#define removeFromATVEND(ptr,index) (HPMi->removeFromHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,(ptr),(index))) +#define addToATVEND(ptr,data,classid,autofree) (HPMi->addToHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,&(ptr)->hdata,(data),(classid),(autofree))) +#define getFromATVEND(ptr,classid) (HPMi->getFromHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,(ptr)->hdata,(classid))) +#define removeFromATVEND(ptr,classid) (HPMi->removeFromHPData(HPDT_AUTOTRADE_VEND,HPMi->pid,(ptr)->hdata,(classid))) /// HPMi->addCommand #define addAtcommand(cname,funcname) do { \ @@ -205,9 +210,9 @@ struct HPMi_interface { bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated); void (*addCPCommand) (char *name, CParseFunc func); /* HPM Custom Data */ - void (*addToHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, void *data, unsigned int index, bool autofree); - void *(*getFromHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index); - void (*removeFromHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index); + void (*addToHPData) (enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store **storeptr, void *data, uint32 classid, bool autofree); + void *(*getFromHPData) (enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid); + void (*removeFromHPData) (enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid); /* packet */ bool (*addPacket) (unsigned short cmd, unsigned short length, void (*receive)(int fd), unsigned int point, unsigned int pluginID); /* Hooking */ diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 575428f96..64f21f7e0 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -391,7 +391,7 @@ typedef char bool; ////////////////////////////////////////////////////////////////////////// // length of a static array -#define ARRAYLENGTH(A) ( sizeof(A)/sizeof((A)[0]) ) +#define ARRAYLENGTH(A) ( (int)(sizeof(A)/sizeof((A)[0])) ) ////////////////////////////////////////////////////////////////////////// // Make sure va_copy exists diff --git a/src/common/console.c b/src/common/console.c index eb55d7462..c8ca4ae87 100644 --- a/src/common/console.c +++ b/src/common/console.c @@ -9,6 +9,7 @@ #include "common/cbasetypes.h" #include "common/core.h" +#include "common/nullpo.h" #include "common/showmsg.h" #include "common/sysinfo.h" @@ -124,14 +125,16 @@ CPCMD_C(mem_report,server) { /** * Displays command list **/ -CPCMD(help) { - unsigned int i = 0; - for ( i = 0; i < console->input->cmd_list_count; i++ ) { - if( console->input->cmd_list[i]->next_count ) { - ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",console->input->cmd_list[i]->cmd); - console->input->parse_list_subs(console->input->cmd_list[i],2); +CPCMD(help) +{ + int i; + for (i = 0; i < VECTOR_LENGTH(console->input->command_list); i++) { + struct CParseEntry *entry = VECTOR_INDEX(console->input->command_list, i); + if (entry->type == CPET_CATEGORY) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n", entry->cmd); + console->input->parse_list_subs(entry, 2); } else { - ShowInfo("- '"CL_WHITE"%s"CL_RESET"'\n",console->input->cmd_list[i]->cmd); + ShowInfo("- '"CL_WHITE"%s"CL_RESET"'\n", entry->cmd); } } } @@ -171,7 +174,7 @@ void console_load_defaults(void) * 'sql' is the main category * CP_DEF_C(category) **/ -#define CP_DEF_C(x) { #x , NULL , NULL, NULL } +#define CP_DEF_C(x) { #x , CPET_CATEGORY, NULL , NULL, NULL } /** * Defines a sub-category. * @@ -181,20 +184,21 @@ void console_load_defaults(void) * 'update' is a sub-category * CP_DEF_C2(command, category) **/ -#define CP_DEF_C2(x,y) { #x , NULL , #y, NULL } +#define CP_DEF_C2(x,y) { #x , CPET_CATEGORY, NULL , #y, NULL } /** * Defines a command that is inside a category or sub-category * CP_DEF_S(command, category/sub-category) **/ -#define CP_DEF_S(x,y) { #x, CPCMD_C_A(x,y), #y, NULL } +#define CP_DEF_S(x,y) { #x, CPET_FUNCTION, CPCMD_C_A(x,y), #y, NULL } /** * Defines a command that is _not_ inside any category * CP_DEF_S(command) **/ -#define CP_DEF(x) { #x , CPCMD_A(x), NULL, NULL } +#define CP_DEF(x) { #x , CPET_FUNCTION, CPCMD_A(x), NULL, NULL } struct { char *name; + int type; CParseFunc func; char *connect; struct CParseEntry *self; @@ -215,43 +219,49 @@ void console_load_defaults(void) CP_DEF_C2(update,sql), CP_DEF_S(skip,update), }; - unsigned int i, len = ARRAYLENGTH(default_list); + int len = ARRAYLENGTH(default_list); struct CParseEntry *cmd; + int i; - RECREATE(console->input->cmds,struct CParseEntry *, len); + VECTOR_ENSURE(console->input->commands, len, 1); for(i = 0; i < len; i++) { CREATE(cmd, struct CParseEntry, 1); safestrncpy(cmd->cmd, default_list[i].name, CP_CMD_LENGTH); - if( default_list[i].func ) - cmd->u.func = default_list[i].func; - else - cmd->u.next = NULL; + cmd->type = default_list[i].type; - cmd->next_count = 0; + switch (cmd->type) { + case CPET_FUNCTION: + cmd->u.func = default_list[i].func; + break; + case CPET_CATEGORY: + VECTOR_INIT(cmd->u.children); + break; + case CPET_UNKNOWN: + break; + } - console->input->cmd_count++; - console->input->cmds[i] = cmd; + VECTOR_PUSH(console->input->commands, cmd); default_list[i].self = cmd; - if( !default_list[i].connect ) { - RECREATE(console->input->cmd_list,struct CParseEntry *, ++console->input->cmd_list_count); - console->input->cmd_list[console->input->cmd_list_count - 1] = cmd; + if (!default_list[i].connect) { + VECTOR_ENSURE(console->input->command_list, 1, 1); + VECTOR_PUSH(console->input->command_list, cmd); } } - for(i = 0; i < len; i++) { - unsigned int k; - if( !default_list[i].connect ) + for (i = 0; i < len; i++) { + int k; + if (!default_list[i].connect) continue; - for(k = 0; k < console->input->cmd_count; k++) { - if( strcmpi(default_list[i].connect,console->input->cmds[k]->cmd) == 0 ) { - cmd = default_list[i].self; - RECREATE(console->input->cmds[k]->u.next, struct CParseEntry *, ++console->input->cmds[k]->next_count); - console->input->cmds[k]->u.next[console->input->cmds[k]->next_count - 1] = cmd; - break; - } + ARR_FIND(0, VECTOR_LENGTH(console->input->commands), k, strcmpi(default_list[i].connect, VECTOR_INDEX(console->input->commands, k)->cmd) == 0); + if (k != VECTOR_LENGTH(console->input->commands)) { + struct CParseEntry *parent = VECTOR_INDEX(console->input->commands, k); + Assert_retb(parent->type == CPET_CATEGORY); + cmd = default_list[i].self; + VECTOR_ENSURE(parent->u.children, 1, 1); + VECTOR_PUSH(parent->u.children, cmd); } } #undef CP_DEF_C @@ -260,8 +270,15 @@ void console_load_defaults(void) #undef CP_DEF } -void console_parse_create(char *name, CParseFunc func) { - unsigned int i; +/** + * Creates a new console command entry. + * + * @param name The command name. + * @param func The command callback. + */ +void console_parse_create(char *name, CParseFunc func) +{ + int i; char *tok; char sublist[CP_CMD_LENGTH * 5]; struct CParseEntry *cmd; @@ -269,123 +286,142 @@ void console_parse_create(char *name, CParseFunc func) { safestrncpy(sublist, name, CP_CMD_LENGTH * 5); tok = strtok(sublist,":"); - for ( i = 0; i < console->input->cmd_list_count; i++ ) { - if( strcmpi(tok,console->input->cmd_list[i]->cmd) == 0 ) - break; - } + ARR_FIND(0, VECTOR_LENGTH(console->input->command_list), i, strcmpi(tok, VECTOR_INDEX(console->input->command_list, i)->cmd) == 0); - if( i == console->input->cmd_list_count ) { - RECREATE(console->input->cmds,struct CParseEntry *, ++console->input->cmd_count); + if (i == VECTOR_LENGTH(console->input->command_list)) { CREATE(cmd, struct CParseEntry, 1); safestrncpy(cmd->cmd, tok, CP_CMD_LENGTH); - cmd->next_count = 0; - console->input->cmds[console->input->cmd_count - 1] = cmd; - RECREATE(console->input->cmd_list,struct CParseEntry *, ++console->input->cmd_list_count); - console->input->cmd_list[console->input->cmd_list_count - 1] = cmd; - i = console->input->cmd_list_count - 1; + cmd->type = CPET_UNKNOWN; + VECTOR_ENSURE(console->input->commands, 1, 1); + VECTOR_PUSH(console->input->commands, cmd); + VECTOR_ENSURE(console->input->command_list, 1, 1); + VECTOR_PUSH(console->input->command_list, cmd); } - cmd = console->input->cmd_list[i]; - while( ( tok = strtok(NULL, ":") ) != NULL ) { - for(i = 0; i < cmd->next_count; i++) { - if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) - break; + cmd = VECTOR_INDEX(console->input->command_list, i); + while ((tok = strtok(NULL, ":")) != NULL) { + if (cmd->type == CPET_UNKNOWN) { + cmd->type = CPET_CATEGORY; + VECTOR_INIT(cmd->u.children); } - - if ( i == cmd->next_count ) { - RECREATE(console->input->cmds,struct CParseEntry *, ++console->input->cmd_count); - CREATE(console->input->cmds[console->input->cmd_count-1], struct CParseEntry, 1); - safestrncpy(console->input->cmds[console->input->cmd_count-1]->cmd, tok, CP_CMD_LENGTH); - console->input->cmds[console->input->cmd_count-1]->next_count = 0; - RECREATE(cmd->u.next, struct CParseEntry *, ++cmd->next_count); - cmd->u.next[cmd->next_count - 1] = console->input->cmds[console->input->cmd_count-1]; - cmd = console->input->cmds[console->input->cmd_count-1]; + Assert_retv(cmd->type == CPET_CATEGORY); + + ARR_FIND(0, VECTOR_LENGTH(cmd->u.children), i, strcmpi(VECTOR_INDEX(cmd->u.children, i)->cmd,tok) == 0); + if (i == VECTOR_LENGTH(cmd->u.children)) { + struct CParseEntry *entry; + CREATE(entry, struct CParseEntry, 1); + safestrncpy(entry->cmd, tok, CP_CMD_LENGTH); + entry->type = CPET_UNKNOWN; + VECTOR_ENSURE(console->input->commands, 1, 1); + VECTOR_PUSH(console->input->commands, entry); + VECTOR_ENSURE(cmd->u.children, 1, 1); + VECTOR_PUSH(cmd->u.children, entry); + cmd = entry; continue; } + cmd = VECTOR_INDEX(cmd->u.children, i); } + Assert_retv(cmd->type != CPET_CATEGORY); + cmd->type = CPET_FUNCTION; cmd->u.func = func; } -void console_parse_list_subs(struct CParseEntry *cmd, unsigned char depth) { - unsigned int i; + +/** + * Shows the help message for a console command category. + * + * @param cmd The command entry. + * @param depth The current tree depth (for display purposes). + */ +void console_parse_list_subs(struct CParseEntry *cmd, unsigned char depth) +{ + int i; char msg[CP_CMD_LENGTH * 2]; - for( i = 0; i < cmd->next_count; i++ ) { - if( cmd->u.next[i]->next_count ) { - memset(msg, '-', depth); - snprintf(msg + depth,( CP_CMD_LENGTH * 2 ) - depth, " '"CL_WHITE"%s"CL_RESET"'",cmd->u.next[i]->cmd); - ShowInfo("%s subs\n",msg); - console->input->parse_list_subs(cmd->u.next[i],depth + 1); - } else { - memset(msg, '-', depth); - snprintf(msg + depth,(CP_CMD_LENGTH * 2) - depth, " %s",cmd->u.next[i]->cmd); + Assert_retv(cmd->type == CPET_CATEGORY); + for (i = 0; i < VECTOR_LENGTH(cmd->u.children); i++) { + struct CParseEntry *child = VECTOR_INDEX(cmd->u.children, i); + memset(msg, '-', depth); + snprintf(msg + depth, (CP_CMD_LENGTH * 2) - depth, " '"CL_WHITE"%s"CL_RESET"'", child->cmd); + if (child->type == CPET_FUNCTION) { ShowInfo("%s\n",msg); + } else { + ShowInfo("%s subs\n",msg); + console->input->parse_list_subs(child,depth + 1); } } } -void console_parse_sub(char *line) { + +/** + * Parses a console command. + * + * @param line The input line. + */ +void console_parse_sub(char *line) +{ struct CParseEntry *cmd; char bline[200]; char *tok; char sublist[CP_CMD_LENGTH * 5]; - unsigned int i, len = 0; + int i; + unsigned int len = 0; memcpy(bline, line, 200); tok = strtok(line, " "); - for ( i = 0; i < console->input->cmd_list_count; i++ ) { - if( strcmpi(tok,console->input->cmd_list[i]->cmd) == 0 ) - break; - } - - if( i == console->input->cmd_list_count ) { + ARR_FIND(0, VECTOR_LENGTH(console->input->command_list), i, strcmpi(tok, VECTOR_INDEX(console->input->command_list, i)->cmd) == 0); + if (i == VECTOR_LENGTH(console->input->command_list)) { ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known command, type '"CL_WHITE"help"CL_RESET"' to list all commands\n",line); return; } - cmd = console->input->cmd_list[i]; + cmd = VECTOR_INDEX(console->input->command_list, i); - len += snprintf(sublist,CP_CMD_LENGTH * 5,"%s", cmd->cmd) + 1; + len += snprintf(sublist,CP_CMD_LENGTH * 5,"%s", cmd->cmd); - if( cmd->next_count == 0 && console->input->cmd_list[i]->u.func ) { + if (cmd->type == CPET_FUNCTION) { char *r = NULL; if( (tok = strtok(NULL, " ")) ) { r = bline; r += len + 1; } cmd->u.func(r); - } else { - while( ( tok = strtok(NULL, " ") ) != NULL ) { - for( i = 0; i < cmd->next_count; i++ ) { - if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) - break; - } - if( i == cmd->next_count ) { - if( strcmpi("help",tok) == 0 ) { - if( cmd->next_count ) { - ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",sublist); - console->input->parse_list_subs(cmd,2); - } else { - ShowError("'"CL_WHITE"%s"CL_RESET"' doesn't possess any subcommands\n",sublist); - } - return; + return; + } + + while (( tok = strtok(NULL, " ") ) != NULL) { + struct CParseEntry *entry = NULL; + + Assert_retv(cmd->type == CPET_CATEGORY); + + ARR_FIND(0, VECTOR_LENGTH(cmd->u.children), i, strcmpi(VECTOR_INDEX(cmd->u.children, i)->cmd, tok) == 0); + if (i == VECTOR_LENGTH(cmd->u.children)) { + if (strcmpi("help", tok) == 0) { + if (VECTOR_LENGTH(cmd->u.children)) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",sublist); + console->input->parse_list_subs(cmd,2); + } else { + ShowError("'"CL_WHITE"%s"CL_RESET"' doesn't possess any subcommands\n",sublist); } - ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known subcommand of '"CL_WHITE"%s"CL_RESET"'\n",tok,cmd->cmd); - ShowError("type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); return; } - if( cmd->u.next[i]->next_count == 0 && cmd->u.next[i]->u.func ) { - char *r = NULL; - if( (tok = strtok(NULL, " ")) ) { - r = bline; - r += len + strlen(cmd->u.next[i]->cmd) + 1; - } - cmd->u.next[i]->u.func(r); - return; - } else - cmd = cmd->u.next[i]; - len += snprintf(sublist + len,(CP_CMD_LENGTH * 5) - len,":%s", cmd->cmd); + ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known subcommand of '"CL_WHITE"%s"CL_RESET"'\n",tok,cmd->cmd); + ShowError("type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + return; + } + entry = VECTOR_INDEX(cmd->u.children, i); + if (entry->type == CPET_FUNCTION) { + char *r = NULL; + if ((tok = strtok(NULL, " "))) { + r = bline; + r += len + strlen(entry->cmd) + 1; + } + entry->u.func(r); + return; } - ShowError("Is only a category, type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + + cmd = entry; + len += snprintf(sublist + len,(CP_CMD_LENGTH * 5) - len," %s", cmd->cmd); } + ShowError("Is only a category, type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); } void console_parse(char* line) { int c, i = 0, len = MAX_CONSOLE_INPUT - 1;/* we leave room for the \0 :P */ @@ -472,27 +508,33 @@ void console_setSQL(Sql *SQL_handle) { } #endif /* CONSOLE_INPUT */ -void console_init (void) { +void console_init(void) +{ #ifdef CONSOLE_INPUT - console->input->cmd_count = console->input->cmd_list_count = 0; + VECTOR_INIT(console->input->command_list); + VECTOR_INIT(console->input->commands); console->input->load_defaults(); console->input->parse_init(); #endif } -void console_final(void) { + +void console_final(void) +{ #ifdef CONSOLE_INPUT - unsigned int i; console->input->parse_final(); - for( i = 0; i < console->input->cmd_count; i++ ) { - if( console->input->cmds[i]->next_count ) - aFree(console->input->cmds[i]->u.next); - aFree(console->input->cmds[i]); + while (VECTOR_LENGTH(console->input->commands)) { + struct CParseEntry *entry = VECTOR_POP(console->input->commands); + if (entry->type == CPET_CATEGORY) + VECTOR_CLEAR(entry->u.children); + aFree(entry); } - aFree(console->input->cmds); - aFree(console->input->cmd_list); + VECTOR_CLEAR(console->input->commands); + VECTOR_CLEAR(console->input->command_list); #endif } -void console_defaults(void) { + +void console_defaults(void) +{ console = &console_s; console->init = console_init; console->final = console_final; diff --git a/src/common/console.h b/src/common/console.h index ffb4a165b..ef6db0cb4 100644 --- a/src/common/console.h +++ b/src/common/console.h @@ -5,6 +5,7 @@ #define COMMON_CONSOLE_H #include "common/hercules.h" +#include "common/db.h" #include "common/mutex.h" #include "common/spinlock.h" #include "common/sql.h" @@ -33,13 +34,20 @@ typedef void (*CParseFunc)(char *line); #define CPCMD_C_A(x,y) console_parse_ ##y ##x #define CP_CMD_LENGTH 20 + +enum CONSOLE_PARSE_ENTRY_TYPE { + CPET_UNKNOWN, + CPET_FUNCTION, + CPET_CATEGORY, +}; + struct CParseEntry { char cmd[CP_CMD_LENGTH]; + int type; ///< Entry type (@see enum CONSOLE_PARSE_ENTRY_TYPE) union { CParseFunc func; - struct CParseEntry **next; + VECTOR_DECL(struct CParseEntry *) children; } u; - unsigned short next_count; }; #ifdef CONSOLE_INPUT @@ -51,10 +59,8 @@ struct console_input_interface { ramutex *ptmutex;/* parse thread mutex */ racond *ptcond;/* parse thread cond */ /* */ - struct CParseEntry **cmd_list; - struct CParseEntry **cmds; - unsigned int cmd_count; - unsigned int cmd_list_count; + VECTOR_DECL(struct CParseEntry *) command_list; + VECTOR_DECL(struct CParseEntry *) commands; /* */ Sql *SQL; /* */ diff --git a/src/common/core.c b/src/common/core.c index dcc96fa41..8564b8acc 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -207,8 +207,9 @@ const char *cmdline_arg_source(struct CmdlineArgData *arg) { bool cmdline_arg_add(unsigned int pluginID, const char *name, char shortname, CmdlineExecFunc func, const char *help, unsigned int options) { struct CmdlineArgData *data = NULL; - RECREATE(cmdline->args_data, struct CmdlineArgData, ++cmdline->args_data_count); - data = &cmdline->args_data[cmdline->args_data_count-1]; + VECTOR_ENSURE(cmdline->args_data, 1, 1); + VECTOR_PUSHZEROED(cmdline->args_data); + data = &VECTOR_LAST(cmdline->args_data); data->pluginID = pluginID; data->name = aStrdup(name); data->shortname = shortname; @@ -228,8 +229,8 @@ static CMDLINEARG(help) ShowInfo("\n"); ShowInfo("Options:\n"); - for (i = 0; i < cmdline->args_data_count; i++) { - struct CmdlineArgData *data = &cmdline->args_data[i]; + for (i = 0; i < VECTOR_LENGTH(cmdline->args_data); i++) { + struct CmdlineArgData *data = &VECTOR_INDEX(cmdline->args_data, i); char altname[16], paramnames[256]; if (data->shortname) { snprintf(altname, sizeof(altname), " [-%c]", data->shortname); @@ -288,8 +289,9 @@ bool cmdline_arg_next_value(const char *name, int current_arg, int argc) */ int cmdline_exec(int argc, char **argv, unsigned int options) { - int count = 0, i, j; + int count = 0, i; for (i = 1; i < argc; i++) { + int j; struct CmdlineArgData *data = NULL; const char *arg = argv[i]; if (arg[0] != '-') { // All arguments must begin with '-' @@ -297,17 +299,17 @@ int cmdline_exec(int argc, char **argv, unsigned int options) exit(EXIT_FAILURE); } if (arg[1] != '-' && strlen(arg) == 2) { - ARR_FIND(0, cmdline->args_data_count, j, cmdline->args_data[j].shortname == arg[1]); + ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), j, VECTOR_INDEX(cmdline->args_data, j).shortname == arg[1]); } else { - ARR_FIND(0, cmdline->args_data_count, j, strcmpi(cmdline->args_data[j].name, arg) == 0); + ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), j, strcmpi(VECTOR_INDEX(cmdline->args_data, j).name, arg) == 0); } - if (j == cmdline->args_data_count) { + if (j == VECTOR_LENGTH(cmdline->args_data)) { if (options&(CMDLINE_OPT_SILENT|CMDLINE_OPT_PREINIT)) continue; ShowError("Unknown option '%s'.\n", arg); exit(EXIT_FAILURE); } - data = &cmdline->args_data[j]; + data = &VECTOR_INDEX(cmdline->args_data, j); if (data->options&CMDLINE_OPT_PARAM) { if (!cmdline->arg_next_value(arg, i, argc)) exit(EXIT_FAILURE); @@ -346,15 +348,15 @@ void cmdline_init(void) #endif // !MINICORE cmdline_args_init_local(); } + void cmdline_final(void) { - int i; - for (i = 0; i < cmdline->args_data_count; i++) { - aFree(cmdline->args_data[i].name); - aFree(cmdline->args_data[i].help); + while (VECTOR_LENGTH(cmdline->args_data) > 0) { + struct CmdlineArgData *data = &VECTOR_POP(cmdline->args_data); + aFree(data->name); + aFree(data->help); } - if (cmdline->args_data) - aFree(cmdline->args_data); + VECTOR_CLEAR(cmdline->args_data); } struct cmdline_interface cmdline_s; @@ -364,8 +366,7 @@ void cmdline_defaults(void) { cmdline = &cmdline_s; - cmdline->args_data = NULL; - cmdline->args_data_count = 0; + VECTOR_INIT(cmdline->args_data); cmdline->init = cmdline_init; cmdline->final = cmdline_final; diff --git a/src/common/core.h b/src/common/core.h index c92bf4fa6..f8e748db4 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -6,6 +6,7 @@ #define COMMON_CORE_H #include "common/hercules.h" +#include "common/db.h" /* so that developers with --enable-debug can raise signals from any section of the code they'd like */ #ifdef DEBUG @@ -46,8 +47,7 @@ struct CmdlineArgData { }; struct cmdline_interface { - struct CmdlineArgData *args_data; - int args_data_count; + VECTOR_DECL(struct CmdlineArgData) args_data; void (*init) (void); void (*final) (void); diff --git a/src/common/db.h b/src/common/db.h index 73d44a755..afec62d86 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -935,608 +935,785 @@ void db_defaults(void); HPShared struct db_interface *DB; -/// Finds an entry in an array. -/// ex: ARR_FIND(0, size, i, list[i] == target); -/// -/// @param __start Starting index (ex: 0) -/// @param __end End index (ex: size of the array) -/// @param __var Index variable -/// @param __cmp Expression that returns true when the target entry is found -#define ARR_FIND(__start, __end, __var, __cmp) \ - do{ \ - for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ - if( __cmp ) \ +/** + * Array Helper macros + */ + +/** + * Finds an entry in an array. + * + * @code + * ARR_FIND(0, size, i, list[i] == target); + * @endcode + * + * To differentiate between the found and not found cases, the caller code can + * compare _end and _var after this macro returns. + * + * @param _start Starting index (ex: 0). + * @param _end End index (ex: size of the array). + * @param _var Index variable. + * @param _cmp Search expression (should return true when the target entry is found). + */ +#define ARR_FIND(_start, _end, _var, _cmp) \ + do { \ + for ((_var) = (_start); (_var) < (_end); ++(_var)) \ + if (_cmp) \ break; \ - }while(0) - -/// Moves an entry of the array. -/// Use ARR_MOVERIGHT/ARR_MOVELEFT if __from and __to are direct numbers. -/// ex: ARR_MOVE(i, 0, list, int);// move index i to index 0 -/// -/// -/// @param __from Initial index of the entry -/// @param __to Target index of the entry -/// @param __arr Array -/// @param __type Type of entry -#define ARR_MOVE(__from, __to, __arr, __type) \ - do{ \ - if( (__from) != (__to) ) \ - { \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - if( (__from) < (__to) ) \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - else if( (__from) > (__to) ) \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + } while(false) + +/** + * Moves an entry of the array. + * + * @code + * ARR_MOVE(i, 0, list, int); // move index i to index 0 + * @endcode + * + * @remark + * Use ARR_MOVERIGHT/ARR_MOVELEFT if _from and _to are direct numbers. + * + * @param _from Initial index of the entry. + * @param _to Target index of the entry. + * @param _arr Array. + * @param _type Type of entry. + */ +#define ARR_MOVE(_from, _to, _arr, _type) \ + do { \ + if ((_from) != (_to)) { \ + _type _backup_; \ + memmove(&_backup_, (_arr)+(_from), sizeof(_type)); \ + if ((_from) < (_to)) \ + memmove((_arr)+(_from), (_arr)+(_from)+1, ((_to)-(_from))*sizeof(_type)); \ + else if ((_from) > (_to)) \ + memmove((_arr)+(_to)+1, (_arr)+(_to), ((_from)-(_to))*sizeof(_type)); \ + memmove((_arr)+(_to), &_backup_, sizeof(_type)); \ } \ - }while(0) - -/// Moves an entry of the array to the right. -/// ex: ARR_MOVERIGHT(1, 4, list, int);// move index 1 to index 4 -/// -/// @param __from Initial index of the entry -/// @param __to Target index of the entry -/// @param __arr Array -/// @param __type Type of entry -#define ARR_MOVERIGHT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) - -/// Moves an entry of the array to the left. -/// ex: ARR_MOVELEFT(3, 0, list, int);// move index 3 to index 0 -/// -/// @param __from Initial index of the entry -/// @param __end Target index of the entry -/// @param __arr Array -/// @param __type Type of entry -#define ARR_MOVELEFT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) - -///////////////////////////////////////////////////////////////////// -// Vector library based on defines. (dynamic array) -// uses aMalloc, aRealloc, aFree - -/// Declares an anonymous vector struct. -/// -/// @param __type Type of data -#define VECTOR_DECL(__type) \ + } while(false) + +/** + * Moves an entry of the array to the right. + * + * @code + * ARR_MOVERIGHT(1, 4, list, int); // move index 1 to index 4 + * @endcode + * + * @param _from Initial index of the entry. + * @param _to Target index of the entry. + * @param _arr Array. + * @param _type Type of entry. + */ +#define ARR_MOVERIGHT(_from, _to, _arr, _type) \ + do { \ + _type _backup_; \ + memmove(&_backup_, (_arr)+(_from), sizeof(_type)); \ + memmove((_arr)+(_from), (_arr)+(_from)+1, ((_to)-(_from))*sizeof(_type)); \ + memmove((_arr)+(_to), &_backup_, sizeof(_type)); \ + } while(false) + +/** + * Moves an entry of the array to the left. + * + * @code + * ARR_MOVELEFT(3, 0, list, int); // move index 3 to index 0 + * @endcode + * + * @param _from Initial index of the entry. + * @param _end Target index of the entry. + * @param _arr Array. + * @param _type Type of entry. + */ +#define ARR_MOVELEFT(_from, _to, _arr, _type) \ + do { \ + _type _backup_; \ + memmove(&_backup_, (_arr)+(_from), sizeof(_type)); \ + memmove((_arr)+(_to)+1, (_arr)+(_to), ((_from)-(_to))*sizeof(_type)); \ + memmove((_arr)+(_to), &_backup_, sizeof(_type)); \ + } while(false) + +/** + * Vector library based on defines (dynamic array). + * + * @remark + * This library uses aMalloc, aRealloc, aFree. + */ + +/** + * Declares an anonymous vector struct. + * + * @param _type Type of data to be contained. + */ +#define VECTOR_DECL(_type) \ struct { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ + int _max_; \ + int _len_; \ + _type *_data_; \ } -/// Declares a named vector struct. -/// -/// @param __name Structure name -/// @param __type Type of data -#define VECTOR_STRUCT_DECL(__name,__type) \ - struct __name { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ +/** + * Declares a named vector struct. + * + * @param _name Structure name. + * @param _type Type of data to be contained. + */ +#define VECTOR_STRUCT_DECL(_name, _type) \ + struct _name { \ + int _max_; \ + int _len_; \ + _type *_data_; \ } -/// Declares and initializes an anonymous vector variable. -/// -/// @param __type Type of data -/// @param __var Variable name -#define VECTOR_VAR(__type,__var) \ - VECTOR_DECL(__type) __var = {0,0,NULL} - -/// Declares and initializes a named vector variable. -/// -/// @param __name Structure name -/// @param __var Variable name -#define VECTOR_STRUCT_VAR(__name,__var) \ - struct __name __var = {0,0,NULL} - -/// Initializes a vector. -/// -/// @param __vec Vector -#define VECTOR_INIT(__vec) \ - memset(&(__vec), 0, sizeof(__vec)) - -/// Returns the internal array of values. -/// -/// @param __vec Vector -/// @return Array of values -#define VECTOR_DATA(__vec) \ - ( (__vec)._data_ ) - -/// Returns the length of the vector. -/// -/// @param __vec Vector -/// @return Length -#define VECTOR_LENGTH(__vec) \ - ( (__vec)._len_ ) - -/// Returns the capacity of the vector. -/// -/// @param __vec Vector -/// @return Capacity -#define VECTOR_CAPACITY(__vec) \ - ( (__vec)._max_ ) - -/// Returns the value at the target index. -/// Assumes the index exists. -/// -/// @param __vec Vector -/// @param __idx Index -/// @return Value -#define VECTOR_INDEX(__vec,__idx) \ - ( VECTOR_DATA(__vec)[__idx] ) - -/// Returns the first value of the vector. -/// Assumes the array is not empty. -/// -/// @param __vec Vector -/// @return First value -#define VECTOR_FIRST(__vec) \ - ( VECTOR_INDEX(__vec,0) ) - -/// Returns the last value of the vector. -/// Assumes the array is not empty. -/// -/// @param __vec Vector -/// @return Last value -#define VECTOR_LAST(__vec) \ - ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) - -/// Resizes the vector. -/// Excess values are discarded, new positions are zeroed. -/// -/// @param __vec Vector -/// @param __n Size -#define VECTOR_RESIZE(__vec,__n) \ - do{ \ - if( (__n) > VECTOR_CAPACITY(__vec) ) \ - { /* increase size */ \ - if( VECTOR_CAPACITY(__vec) == 0 ) VECTOR_DATA(__vec) = aMalloc((__n)*sizeof(VECTOR_FIRST(__vec))); /* allocate new */ \ - else VECTOR_DATA(__vec) = aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec))); /* reallocate */ \ - memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - } \ - else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ - { /* clear vector */ \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - else if( (__n) < VECTOR_CAPACITY(__vec) ) \ - { /* reduce size */ \ - VECTOR_DATA(__vec) = aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec))); /* reallocate */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ +/** + * Declares and initializes an anonymous vector variable. + * + * @param _type Type of data to be contained. + * @param _var Variable name. + */ +#define VECTOR_VAR(_type, _var) \ + VECTOR_DECL(_type) _var = {0, 0, NULL} + +/** + * Declares and initializes a named vector variable. + * + * @param _name Structure name. + * @param _var Variable name. + */ +#define VECTOR_STRUCT_VAR(_name, _var) \ + struct _name _var = {0, 0, NULL} + +/** + * Initializes a vector. + * + * @param _vec Vector. + */ +#define VECTOR_INIT(_vec) \ + memset(&(_vec), 0, sizeof(_vec)) + +/** + * Returns the internal array of values. + * + * @param _vec Vector. + * @return Internal array of values. + */ +#define VECTOR_DATA(_vec) \ + ( (_vec)._data_ ) + +/** + * Returns the length of the vector (number of elements in use). + * + * @param _vec Vector + * @return Length + */ +#define VECTOR_LENGTH(_vec) \ + ( (_vec)._len_ ) + +/** + * Returns the capacity of the vector (number of elements allocated). + * + * @param _vec Vector. + * @return Capacity. + */ +#define VECTOR_CAPACITY(_vec) \ + ( (_vec)._max_ ) + +/** + * Returns the value at the target index. + * + * Assumes the index exists. + * + * @param _vec Vector. + * @param _idx Index. + * @return Value. + */ +#define VECTOR_INDEX(_vec, _idx) \ + ( VECTOR_DATA(_vec)[_idx] ) + +/** + * Returns the first value of the vector. + * + * Assumes the array is not empty. + * + * @param _vec Vector. + * @return First value. + */ +#define VECTOR_FIRST(_vec) \ + ( VECTOR_INDEX(_vec, 0) ) + +/** + * Returns the last value of the vector. + * + * Assumes the array is not empty. + * + * @param _vec Vector. + * @return Last value. + */ +#define VECTOR_LAST(_vec) \ + ( VECTOR_INDEX(_vec, VECTOR_LENGTH(_vec)-1) ) + +/** + * Resizes the vector. + * + * Excess values are discarded, new positions are zeroed. + * + * @param _vec Vector. + * @param _n New size. + */ +#define VECTOR_RESIZE(_vec, _n) \ + do { \ + if ((_n) > VECTOR_CAPACITY(_vec)) { \ + /* increase size */ \ + if (VECTOR_CAPACITY(_vec) == 0) \ + VECTOR_DATA(_vec) = aMalloc((_n)*sizeof(VECTOR_FIRST(_vec))); /* allocate new */ \ + else \ + VECTOR_DATA(_vec) = aRealloc(VECTOR_DATA(_vec), (_n)*sizeof(VECTOR_FIRST(_vec))); /* reallocate */ \ + memset(VECTOR_DATA(_vec)+VECTOR_LENGTH(_vec), 0, (VECTOR_CAPACITY(_vec)-VECTOR_LENGTH(_vec))*sizeof(VECTOR_FIRST(_vec))); /* clear new data */ \ + VECTOR_CAPACITY(_vec) = (_n); /* update capacity */ \ + } else if ((_n) == 0 && VECTOR_CAPACITY(_vec) > 0) { \ + /* clear vector */ \ + aFree(VECTOR_DATA(_vec)); VECTOR_DATA(_vec) = NULL; /* free data */ \ + VECTOR_CAPACITY(_vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(_vec) = 0; /* clear length */ \ + } else if ((_n) < VECTOR_CAPACITY(_vec)) { \ + /* reduce size */ \ + VECTOR_DATA(_vec) = aRealloc(VECTOR_DATA(_vec), (_n)*sizeof(VECTOR_FIRST(_vec))); /* reallocate */ \ + VECTOR_CAPACITY(_vec) = (_n); /* update capacity */ \ + if (VECTOR_LENGTH(_vec) > (_n)) \ + VECTOR_LENGTH(_vec) = (_n); /* update length */ \ } \ - }while(0) - -/// Ensures that the array has the target number of empty positions. -/// Increases the capacity in multiples of __step. -/// -/// @param __vec Vector -/// @param __n Empty positions -/// @param __step Increase -#define VECTOR_ENSURE(__vec,__n,__step) \ - do{ \ - size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ - if( (__n) > _empty_ ) { \ - while( (__n) > _empty_ ) _empty_ += (__step); \ - VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ + } while(false) + +/** + * Ensures that the array has the target number of empty positions. + * + * Increases the capacity in multiples of _step. + * + * @param _vec Vector. + * @param _n Desired empty positions. + * @param _step Increase. + */ +#define VECTOR_ENSURE(_vec, _n, _step) \ + do { \ + int _empty_ = VECTOR_CAPACITY(_vec)-VECTOR_LENGTH(_vec); \ + if ((_n) > _empty_) { \ + while ((_n) > _empty_) \ + _empty_ += (_step); \ + VECTOR_RESIZE(_vec, _empty_+VECTOR_LENGTH(_vec)); \ } \ - }while(0) - -/// Inserts a zeroed value in the target index. -/// Assumes the index is valid and there is enough capacity. -/// -/// @param __vec Vector -/// @param __idx Index -#define VECTOR_INSERTZEROED(__vec,__idx) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) - -/// Inserts a value in the target index. (using the '=' operator) -/// Assumes the index is valid and there is enough capacity. -/// -/// @param __vec Vector -/// @param __idx Index -/// @param __val Value -#define VECTOR_INSERT(__vec,__idx,__val) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) - -/// Inserts a value in the target index. (using memcpy) -/// Assumes the index is valid and there is enough capacity. -/// -/// @param __vec Vector -/// @param __idx Index -/// @param __val Value -#define VECTOR_INSERTCOPY(__vec,__idx,__val) \ - VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) - -/// Inserts the values of the array in the target index. (using memcpy) -/// Assumes the index is valid and there is enough capacity. -/// -/// @param __vec Vector -/// @param __idx Index -/// @param __pval Array of values -/// @param __n Number of values -#define VECTOR_INSERTARRAY(__vec,__idx,__pval,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) - -/// Inserts a zeroed value in the end of the vector. -/// Assumes there is enough capacity. -/// -/// @param __vec Vector -#define VECTOR_PUSHZEROED(__vec) \ - do{ \ - memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) - -/// Inserts a value in the end of the vector. (using the '=' operator) -/// Assumes there is enough capacity. -/// -/// @param __vec Vector -/// @param __val Value -#define VECTOR_PUSH(__vec,__val) \ - do{ \ - VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) - -/// Inserts a value in the end of the vector. (using memcpy) -/// Assumes there is enough capacity. -/// -/// @param __vec Vector -/// @param __val Value -#define VECTOR_PUSHCOPY(__vec,__val) \ - VECTOR_PUSHARRAY(__vec,&(__val),1) - -/// Inserts the values of the array in the end of the vector. (using memcpy) -/// Assumes there is enough capacity. -/// -/// @param __vec Vector -/// @param __pval Array of values -/// @param __n Number of values -#define VECTOR_PUSHARRAY(__vec,__pval,__n) \ - do{ \ - memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) - -/// Removes and returns the last value of the vector. -/// Assumes the array is not empty. -/// -/// @param __vec Vector -/// @return Removed value -#define VECTOR_POP(__vec) \ - ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) - -/// Removes the last N values of the vector and returns the value of the last pop. -/// Assumes there are enough values. -/// -/// @param __vec Vector -/// @param __n Number of pops -/// @return Last removed value -#define VECTOR_POPN(__vec,__n) \ - ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) - -/// Removes the target index from the vector. -/// Assumes the index is valid and there are enough values. -/// -/// @param __vec Vector -/// @param __idx Index -#define VECTOR_ERASE(__vec,__idx) \ - VECTOR_ERASEN(__vec,__idx,1) - -/// Removes N values from the target index of the vector. -/// Assumes the index is valid and there are enough values. -/// -/// @param __vec Vector -/// @param __idx Index -/// @param __n Number of values -#define VECTOR_ERASEN(__vec,__idx,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ - }while(0) - -/// Clears the vector, freeing allocated data. -/// -/// @param __vec Vector -#define VECTOR_CLEAR(__vec) \ - do{ \ - if( VECTOR_CAPACITY(__vec) ) \ - { \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } while(false) + +/** + * Inserts a zeroed value in the target index. + * + * Assumes the index is valid and there is enough capacity. + * + * @param _vec Vector. + * @param _idx Index. + */ +#define VECTOR_INSERTZEROED(_vec, _idx) \ + do { \ + if ((_idx) < VECTOR_LENGTH(_vec)) /* move data */ \ + memmove(&VECTOR_INDEX(_vec, (_idx)+1), &VECTOR_INDEX(_vec, _idx), (VECTOR_LENGTH(_vec)-(_idx))*sizeof(VECTOR_FIRST(_vec))); \ + memset(&VECTOR_INDEX(_vec, _idx), 0, sizeof(VECTOR_INDEX(_vec, _idx))); /* set zeroed value */ \ + ++VECTOR_LENGTH(_vec); /* increase length */ \ + } while(false) + +/** + * Inserts a value in the target index (using the '=' operator). + * + * Assumes the index is valid and there is enough capacity. + * + * @param _vec Vector. + * @param _idx Index. + * @param _val Value. + */ +#define VECTOR_INSERT(_vec, _idx, _val) \ + do { \ + if ((_idx) < VECTOR_LENGTH(_vec)) /* move data */ \ + memmove(&VECTOR_INDEX(_vec, (_idx)+1), &VECTOR_INDEX(_vec, _idx), (VECTOR_LENGTH(_vec)-(_idx))*sizeof(VECTOR_FIRST(_vec))); \ + VECTOR_INDEX(_vec, _idx) = (_val); /* set value */ \ + ++VECTOR_LENGTH(_vec); /* increase length */ \ + } while(false) + +/** + * Inserts a value in the target index (using memcpy). + * + * Assumes the index is valid and there is enough capacity. + * + * @param _vec Vector. + * @param _idx Index. + * @param _val Value. + */ +#define VECTOR_INSERTCOPY(_vec, _idx, _val) \ + VECTOR_INSERTARRAY(_vec, _idx, &(_val), 1) + +/** + * Inserts the values of the array in the target index (using memcpy). + * + * Assumes the index is valid and there is enough capacity. + * + * @param _vec Vector. + * @param _idx Index. + * @param _pval Array of values. + * @param _n Number of values. + */ +#define VECTOR_INSERTARRAY(_vec, _idx, _pval, _n) \ + do { \ + if ((_idx) < VECTOR_LENGTH(_vec)) /* move data */ \ + memmove(&VECTOR_INDEX(_vec, (_idx)+(_n)), &VECTOR_INDEX(_vec, _idx), (VECTOR_LENGTH(_vec)-(_idx))*sizeof(VECTOR_FIRST(_vec))); \ + memcpy(&VECTOR_INDEX(_vec, _idx), (_pval), (_n)*sizeof(VECTOR_FIRST(_vec))); /* set values */ \ + VECTOR_LENGTH(_vec) += (_n); /* increase length */ \ + } while(false) + +/** + * Inserts a zeroed value in the end of the vector. + * + * Assumes there is enough capacity. + * + * @param _vec Vector. + */ +#define VECTOR_PUSHZEROED(_vec) \ + do { \ + memset(&VECTOR_INDEX(_vec, VECTOR_LENGTH(_vec)), 0, sizeof(VECTOR_INDEX(_vec, VECTOR_LENGTH(_vec)))); /* set zeroed value */ \ + ++VECTOR_LENGTH(_vec); /* increase length */ \ + } while(false) + +/** + * Appends a value at the end of the vector (using the '=' operator). + * + * Assumes there is enough capacity. + * + * @param _vec Vector. + * @param _val Value. + */ +#define VECTOR_PUSH(_vec, _val) \ + do { \ + VECTOR_INDEX(_vec, VECTOR_LENGTH(_vec)) = (_val); /* set value */ \ + ++VECTOR_LENGTH(_vec); /* increase length */ \ + }while(false) + +/** + * Appends a value at the end of the vector (using memcpy). + * + * Assumes there is enough capacity. + * + * @param _vec Vector. + * @param _val Value. + */ +#define VECTOR_PUSHCOPY(_vec, _val) \ + VECTOR_PUSHARRAY(_vec, &(_val), 1) + +/** + * Appends the values of the array at the end of the vector (using memcpy). + * + * Assumes there is enough capacity. + * + * @param _vec Vector. + * @param _pval Array of values. + * @param _n Number of values. + */ +#define VECTOR_PUSHARRAY(_vec, _pval, _n) \ + do { \ + memcpy(&VECTOR_INDEX(_vec, VECTOR_LENGTH(_vec)), (_pval), (_n)*sizeof(VECTOR_FIRST(_vec))); /* set values */ \ + VECTOR_LENGTH(_vec) += (_n); /* increase length */ \ + } while(false) + +/** + * Removes and returns the last value of the vector. + * + * Assumes the array is not empty. + * + * @param _vec Vector. + * @return Removed value. + */ +#define VECTOR_POP(_vec) \ + ( VECTOR_INDEX(_vec, --VECTOR_LENGTH(_vec)) ) + +/** + * Removes the last N values of the vector and returns the value of the last pop. + * + * Assumes there are enough values. + * + * @param _vec Vector. + * @param _n Number of pops. + * @return Last removed value. + */ +#define VECTOR_POPN(_vec, _n) \ + ( VECTOR_INDEX(_vec, (VECTOR_LENGTH(_vec) -= (_n))) ) + +/** + * Removes the target index from the vector. + * + * Assumes the index is valid and there are enough values. + * + * @param _vec Vector. + * @param _idx Index. + */ +#define VECTOR_ERASE(_vec, _idx) \ + VECTOR_ERASEN(_vec, _idx, 1) + +/** + * Removes N values from the target index of the vector. + * + * Assumes the index is valid and there are enough values. + * + * @param _vec Vector. + * @param _idx Index. + * @param _n Number of values to remove. + */ +#define VECTOR_ERASEN(_vec, _idx, _n) \ + do { \ + if ((_idx) < VECTOR_LENGTH(_vec)-(_n) ) /* move data */ \ + memmove(&VECTOR_INDEX(_vec, _idx), &VECTOR_INDEX(_vec, (_idx)+(_n)), (VECTOR_LENGTH(_vec)-((_idx)+(_n)))*sizeof(VECTOR_FIRST(_vec))); \ + VECTOR_LENGTH(_vec) -= (_n); /* decrease length */ \ + } while(false) + +/** + * Clears the vector, freeing allocated data. + * + * @param _vec Vector. + */ +#define VECTOR_CLEAR(_vec) \ + do { \ + if (VECTOR_CAPACITY(_vec) > 0) { \ + aFree(VECTOR_DATA(_vec)); VECTOR_DATA(_vec) = NULL; /* clear allocated array */ \ + VECTOR_CAPACITY(_vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(_vec) = 0; /* clear length */ \ } \ - }while(0) - -///////////////////////////////////////////////////////////////////// -// Binary heap library based on defines. (uses the vector defines above) -// uses aMalloc, aRealloc, aFree -// WARNING: BHEAP implementation details affect behaviour of A* pathfinding - -/// Declares an anonymous binary heap struct. -/// -/// @param __type Type of data -#define BHEAP_DECL(__type) VECTOR_DECL(__type) - -/// Declares a named binary heap struct. -/// -/// @param __name Structure name -/// @param __type Type of data -#define BHEAP_STRUCT_DECL(__name,__type) VECTOR_STRUCT_DECL(__name,__type) - -/// Declares and initializes an anonymous binary heap variable. -/// -/// @param __type Type of data -/// @param __var Variable name -#define BHEAP_VAR(__type,__var) VECTOR_VAR(__type,__var) - -/// Declares and initializes a named binary heap variable. -/// -/// @param __name Structure name -/// @param __var Variable name -#define BHEAP_STRUCT_VAR(__name,__var) VECTOR_STRUCT_VAR(__name,__var) - -/// Initializes a heap. -/// -/// @param __heap Binary heap -#define BHEAP_INIT(__heap) VECTOR_INIT(__heap) - -/// Returns the internal array of values. -/// -/// @param __heap Binary heap -/// @return Array of values -#define BHEAP_DATA(__heap) VECTOR_DATA(__heap) - -/// Returns the length of the heap. -/// -/// @param __heap Binary heap -/// @return Length -#define BHEAP_LENGTH(__heap) VECTOR_LENGTH(__heap) - -/// Returns the capacity of the heap. -/// -/// @param __heap Binary heap -/// @return Capacity -#define BHEAP_CAPACITY(__heap) VECTOR_CAPACITY(__heap) - -/// Ensures that the heap has the target number of empty positions. -/// Increases the capacity in multiples of __step. -/// -/// @param __heap Binary heap -/// @param __n Empty positions -/// @param __step Increase -#define BHEAP_ENSURE(__heap,__n,__step) VECTOR_ENSURE(__heap,__n,__step) - -/// Returns the top value of the heap. -/// Assumes the heap is not empty. -/// -/// @param __heap Binary heap -/// @return Value at the top -#define BHEAP_PEEK(__heap) VECTOR_INDEX(__heap,0) - -/// Inserts a value in the heap. (using the '=' operator) -/// Assumes there is enough capacity. -/// -/// The comparator takes two values as arguments, returns: -/// - negative if the first value is on the top -/// - positive if the second value is on the top -/// - 0 if they are equal -/// -/// @param __heap Binary heap -/// @param __val Value -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_PUSH(__heap,__val,__topcmp,__swp) \ - do{ \ - size_t _i_ = VECTOR_LENGTH(__heap); \ - VECTOR_PUSH(__heap,__val); /* insert at end */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + } while(false) + +/** + * Binary heap library based on defines. + * + * Uses the VECTOR defines above. + * Uses aMalloc, aRealloc, aFree. + * + * @warning + * BHEAP implementation details affect behaviour of A* pathfinding. + */ + +/** + * Declares an anonymous binary heap struct. + * + * @param _type Type of data. + */ +#define BHEAP_DECL(_type) \ + VECTOR_DECL(_type) + +/** + * Declares a named binary heap struct. + * + * @param _name Structure name. + * @param _type Type of data. + */ +#define BHEAP_STRUCT_DECL(_name, _type) \ + VECTOR_STRUCT_DECL(_name, _type) + +/** + * Declares and initializes an anonymous binary heap variable. + * + * @param _type Type of data. + * @param _var Variable name. + */ +#define BHEAP_VAR(_type, _var) \ + VECTOR_VAR(_type, _var) + +/** + * Declares and initializes a named binary heap variable. + * + * @param _name Structure name. + * @param _var Variable name. + */ +#define BHEAP_STRUCT_VAR(_name, _var) \ + VECTOR_STRUCT_VAR(_name, _var) + +/** + * Initializes a heap. + * + * @param _heap Binary heap. + */ +#define BHEAP_INIT(_heap) \ + VECTOR_INIT(_heap) + +/** + * Returns the internal array of values. + * + * @param _heap Binary heap. + * @return Internal array of values. + */ +#define BHEAP_DATA(_heap) \ + VECTOR_DATA(_heap) + +/** + * Returns the length of the heap. + * + * @param _heap Binary heap. + * @return Length. + */ +#define BHEAP_LENGTH(_heap) \ + VECTOR_LENGTH(_heap) + +/** + * Returns the capacity of the heap. + * + * @param _heap Binary heap. + * @return Capacity. + */ +#define BHEAP_CAPACITY(_heap) \ + VECTOR_CAPACITY(_heap) + +/** + * Ensures that the heap has the target number of empty positions. + * + * Increases the capacity in multiples of _step. + * + * @param _heap Binary heap. + * @param _n Required empty positions. + * @param _step Increase. + */ +#define BHEAP_ENSURE(_heap, _n, _step) \ + VECTOR_ENSURE(_heap, _n, _step) + +/** + * Returns the top value of the heap. + * + * Assumes the heap is not empty. + * + * @param _heap Binary heap. + * @return Value at the top. + */ +#define BHEAP_PEEK(_heap) \ + VECTOR_INDEX(_heap, 0) + +/** + * Inserts a value in the heap (using the '=' operator). + * + * Assumes there is enough capacity. + * + * The comparator takes two values as arguments, returns: + * - negative if the first value is on the top + * - positive if the second value is on the top + * - 0 if they are equal + * + * @param _heap Binary heap. + * @param _val Value. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_PUSH(_heap, _val, _topcmp, _swp) \ + do { \ + int _i_ = VECTOR_LENGTH(_heap); \ + VECTOR_PUSH(_heap, _val); /* insert at end */ \ + while (_i_ > 0) { \ + /* restore heap property in parents */ \ + int _parent_ = (_i_-1)/2; \ + if (_topcmp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i_)) < 0) \ break; /* done */ \ - __swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _swp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i_)); \ _i_ = _parent_; \ } \ - }while(0) - -/// See BHEAP_PUSH. Version used by A* implementation, matching client bheap. -/// -/// @param __heap Binary heap -/// @param __val Value -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_PUSH2(__heap,__val,__topcmp,__swp) \ - do{ \ - size_t _i_ = VECTOR_LENGTH(__heap); \ - VECTOR_PUSH(__heap,__val); /* insert at end */ \ - BHEAP_SIFTDOWN(__heap,0,_i_,__topcmp,__swp); \ - }while(0) - -/// Removes the top value of the heap. (using the '=' operator) -/// Assumes the heap is not empty. -/// -/// The comparator takes two values as arguments, returns: -/// - negative if the first value is on the top -/// - positive if the second value is on the top -/// - 0 if they are equal -/// -/// @param __heap Binary heap -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_POP(__heap,__topcmp,__swp) BHEAP_POPINDEX(__heap,0,__topcmp,__swp) - -/// See BHEAP_POP. Version used by A* implementation, matching client bheap. -/// -/// @param __heap Binary heap -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_POP2(__heap,__topcmp,__swp) \ - do{ \ - VECTOR_INDEX(__heap,0) = VECTOR_POP(__heap); /* put last at index */ \ - if( !VECTOR_LENGTH(__heap) ) /* removed last, nothing to do */ \ + } while(false) + +/** + * Variant of BHEAP_PUSH used by A* implementation, matching client bheap. + * + * @see BHEAP_PUSH. + * + * @param _heap Binary heap. + * @param _val Value. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_PUSH2(_heap, _val, _topcmp, _swp) \ + do { \ + int _i_ = VECTOR_LENGTH(_heap); \ + VECTOR_PUSH(_heap, _val); /* insert at end */ \ + BHEAP_SIFTDOWN(_heap, 0, _i_, _topcmp, _swp); \ + } while(false) + +/** + * Removes the top value of the heap (using the '=' operator). + * + * Assumes the heap is not empty. + * + * The comparator takes two values as arguments, returns: + * - negative if the first value is on the top + * - positive if the second value is on the top + * - 0 if they are equal + * + * @param _heap Binary heap. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_POP(_heap, _topcmp, _swp) \ + BHEAP_POPINDEX(_heap, 0, _topcmp, _swp) + +/** + * Variant of BHEAP_POP used by A* implementation, matching client bheap. + * + * @see BHEAP_POP. + * + * @param _heap Binary heap. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_POP2(_heap, _topcmp, _swp) \ + do { \ + VECTOR_INDEX(_heap, 0) = VECTOR_POP(_heap); /* put last at index */ \ + if (VECTOR_LENGTH(_heap) == 0) /* removed last, nothing to do */ \ break; \ - BHEAP_SIFTUP(__heap,0,__topcmp,__swp); \ - }while(0) - -/// Removes the target value of the heap. (using the '=' operator) -/// Assumes the index exists. -/// -/// The comparator takes two values as arguments, returns: -/// - negative if the first value is on the top -/// - positive if the second value is on the top -/// - 0 if they are equal -/// -/// @param __heap Binary heap -/// @param __idx Index -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_POPINDEX(__heap,__idx,__topcmp,__swp) \ - do{ \ - size_t _i_ = __idx; \ - VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ - if( _i_ >= VECTOR_LENGTH(__heap)) /* removed last, nothing to do */ \ + BHEAP_SIFTUP(_heap, 0, _topcmp, _swp); \ + } while(false) + +/** + * Removes the target value of the heap (using the '=' operator). + * + * Assumes the index exists. + * + * The comparator takes two values as arguments, returns: + * - negative if the first value is on the top + * - positive if the second value is on the top + * - 0 if they are equal + * + * @param _heap Binary heap. + * @param _idx Index. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_POPINDEX(_heap, _idx, _topcmp, _swp) \ + do { \ + int _i_ = _idx; \ + VECTOR_INDEX(_heap, _idx) = VECTOR_POP(_heap); /* put last at index */ \ + if (_i_ >= VECTOR_LENGTH(_heap)) /* removed last, nothing to do */ \ break; \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + while (_i_ > 0) { \ + /* restore heap property in parents */ \ + int _parent_ = (_i_-1)/2; \ + if (_topcmp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i_)) < 0) \ break; /* done */ \ - __swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _swp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i_)); \ _i_ = _parent_; \ } \ - while( _i_ < VECTOR_LENGTH(__heap) ) \ - { /* restore heap property in childs */ \ - size_t _lchild_ = _i_*2 + 1; \ - size_t _rchild_ = _i_*2 + 2; \ - if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ - (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ + while (_i_ < VECTOR_LENGTH(_heap)) { \ + /* restore heap property in children */ \ + int _lchild_ = _i_*2 + 1; \ + int _rchild_ = _i_*2 + 2; \ + if ((_lchild_ >= VECTOR_LENGTH(_heap) || _topcmp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _lchild_)) <= 0) \ + && (_rchild_ >= VECTOR_LENGTH(_heap) || _topcmp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _rchild_)) <= 0)) { \ break; /* done */ \ - else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ - { /* left child */ \ - __swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ + } else if (_rchild_ >= VECTOR_LENGTH(_heap) || _topcmp(VECTOR_INDEX(_heap, _lchild_), VECTOR_INDEX(_heap, _rchild_)) <= 0) { \ + /* left child */ \ + _swp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _lchild_)); \ _i_ = _lchild_; \ - } \ - else \ - { /* right child */ \ - __swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ + } else { \ + /* right child */ \ + _swp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _rchild_)); \ _i_ = _rchild_; \ } \ } \ - }while(0) - -/// Follow path up towards (but not all the way to) the root, swapping nodes until finding -/// a place where the new item that was placed at __idx fits. -/// Only goes as high as __startidx (usually 0). -/// -/// @param __heap Binary heap -/// @param __startidx Index of an ancestor of __idx -/// @param __idx Index of an inserted element -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_SIFTDOWN(__heap,__startidx,__idx,__topcmp,__swp) \ - do{ \ - size_t _i2_ = __idx; \ - while( _i2_ > __startidx ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i2_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i2_)) <= 0 ) \ + } while(false) + +/** + * Follow path up towards (but not all the way to) the root, swapping nodes + * until finding a place where the new item that was placed at _idx fits. + * + * Only goes as high as _startidx (usually 0). + * + * @param _heap Binary heap. + * @param _startidx Index of an ancestor of _idx. + * @param _idx Index of an inserted element. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_SIFTDOWN(_heap, _startidx, _idx, _topcmp, _swp) \ + do { \ + int _i2_ = _idx; \ + while (_i2_ > _startidx) { \ + /* restore heap property in parents */ \ + int _parent_ = (_i2_-1)/2; \ + if (_topcmp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i2_)) <= 0) \ break; /* done */ \ - __swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i2_)); \ + _swp(VECTOR_INDEX(_heap, _parent_), VECTOR_INDEX(_heap, _i2_)); \ _i2_ = _parent_; \ } \ - }while(0) - -/// Repeatedly swap the smaller child with parent, after placing a new item at __idx. -/// -/// @param __heap Binary heap -/// @param __idx Index of an inserted element -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_SIFTUP(__heap,__idx,__topcmp,__swp) \ - do{ \ - size_t _i_ = __idx; \ - size_t _lchild_ = _i_*2 + 1; \ - while( _lchild_ < VECTOR_LENGTH(__heap) ) \ - { /* restore heap property in childs */ \ - size_t _rchild_ = _i_*2 + 2; \ - if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) < 0 ) \ - { /* left child */ \ - __swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ + } while(false) + +/** + * Repeatedly swap the smaller child with parent, after placing a new item at _idx. + * + * @param _heap Binary heap. + * @param _idx Index of an inserted element. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_SIFTUP(_heap, _idx, _topcmp, _swp) \ + do { \ + int _i_ = _idx; \ + int _lchild_ = _i_*2 + 1; \ + while (_lchild_ < VECTOR_LENGTH(_heap)) { \ + /* restore heap property in children */ \ + int _rchild_ = _i_*2 + 2; \ + if (_rchild_ >= VECTOR_LENGTH(_heap) || _topcmp(VECTOR_INDEX(_heap, _lchild_), VECTOR_INDEX(_heap, _rchild_)) < 0) { \ + /* left child */ \ + _swp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _lchild_)); \ _i_ = _lchild_; \ - } \ - else \ - { /* right child */ \ - __swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ + } else { \ + /* right child */ \ + _swp(VECTOR_INDEX(_heap, _i_), VECTOR_INDEX(_heap, _rchild_)); \ _i_ = _rchild_; \ } \ _lchild_ = _i_*2 + 1; \ } \ - BHEAP_SIFTDOWN(__heap,__idx,_i_,__topcmp,__swp); \ - }while(0) - -/// Call this after modifying the item at __idx__ to restore the heap -/// -/// @param __heap Binary heap -/// @param __idx Index -/// @param __topcmp Comparator -/// @param __swp Swapper -#define BHEAP_UPDATE(__heap,__idx,__topcmp,__swp) \ - do{ \ - BHEAP_SIFTDOWN(__heap,0,__idx,__topcmp,__swp); \ - BHEAP_SIFTUP(__heap,__idx,__topcmp,__swp); \ - }while(0) - -/// Clears the binary heap, freeing allocated data. -/// -/// @param __heap Binary heap -#define BHEAP_CLEAR(__heap) VECTOR_CLEAR(__heap) - -/// Generic comparator for a min-heap. (minimum value at top) -/// Returns -1 if v1 is smaller, 1 if v2 is smaller, 0 if equal. -/// -/// @param v1 First value -/// @param v2 Second value -/// @return negative if v1 is top, positive if v2 is top, 0 if equal -#define BHEAP_MINTOPCMP(v1,v2) ( v1 == v2 ? 0 : v1 < v2 ? -1 : 1 ) - -/// Generic comparator for a max-heap. (maximum value at top) -/// Returns -1 if v1 is bigger, 1 if v2 is bigger, 0 if equal. -/// -/// @param v1 First value -/// @param v2 Second value -/// @return negative if v1 is top, positive if v2 is top, 0 if equal -#define BHEAP_MAXTOPCMP(v1,v2) ( v1 == v2 ? 0 : v1 > v2 ? -1 : 1 ) + BHEAP_SIFTDOWN(_heap, _idx, _i_, _topcmp, _swp); \ + } while(false) + +/** + * Restores a heap (after modifying the item at _idx). + * + * @param _heap Binary heap. + * @param _idx Index. + * @param _topcmp Comparator. + * @param _swp Swapper. + */ +#define BHEAP_UPDATE(_heap, _idx, _topcmp, _swp) \ + do { \ + BHEAP_SIFTDOWN(_heap, 0, _idx, _topcmp, _swp); \ + BHEAP_SIFTUP(_heap, _idx, _topcmp, _swp); \ + } while(false) + +/** + * Clears the binary heap, freeing allocated data. + * + * @param _heap Binary heap. + */ +#define BHEAP_CLEAR(_heap) \ + VECTOR_CLEAR(_heap) + +/** + * Generic comparator for a min-heap (minimum value at top). + * + * Returns -1 if v1 is smaller, 1 if v2 is smaller, 0 if equal. + * + * @warning + * Arguments may be evaluted more than once. + * + * @param v1 First value. + * @param v2 Second value. + * @return negative if v1 is top, positive if v2 is top, 0 if equal. + */ +#define BHEAP_MINTOPCMP(v1, v2) \ + ( v1 == v2 ? 0 : v1 < v2 ? -1 : 1 ) + +/** + * Generic comparator for a max-heap (maximum value at top). + * + * Returns -1 if v1 is bigger, 1 if v2 is bigger, 0 if equal. + * + * @warning + * Arguments may be evaluted more than once. + * + * @param v1 First value. + * @param v2 Second value. + * @return negative if v1 is top, positive if v2 is top, 0 if equal. + */ +#define BHEAP_MAXTOPCMP(v1, v2) \ + ( v1 == v2 ? 0 : v1 > v2 ? -1 : 1 ) #endif /* COMMON_DB_H */ diff --git a/src/common/mmo.h b/src/common/mmo.h index 012eec935..73d4510a1 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -198,7 +198,7 @@ #define JOBL_BABY 0x2000 //8192 #define JOBL_THIRD 0x4000 //16384 -struct HPluginData; +struct hplugin_data_store; enum item_types { IT_HEALING = 0, @@ -661,10 +661,7 @@ struct guild { unsigned short instances; struct channel_data *channel; - - /* HPM Custom Struct */ - struct HPluginData **hdata; - unsigned int hdatac; + struct hplugin_data_store *hdata; ///< HPM Plugin Data Store }; struct guild_castle { diff --git a/src/common/socket.c b/src/common/socket.c index de8ca4682..f1318ab47 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -623,7 +623,6 @@ static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseF sockt->session[fd]->rdata_tick = sockt->last_tick; sockt->session[fd]->session_data = NULL; sockt->session[fd]->hdata = NULL; - sockt->session[fd]->hdatac = 0; return 0; } @@ -638,16 +637,7 @@ static void delete_session(int fd) aFree(sockt->session[fd]->wdata); if( sockt->session[fd]->session_data ) aFree(sockt->session[fd]->session_data); - if (sockt->session[fd]->hdata) { - unsigned int i; - for(i = 0; i < sockt->session[fd]->hdatac; i++) { - if( sockt->session[fd]->hdata[i]->flag.free ) { - aFree(sockt->session[fd]->hdata[i]->data); - } - aFree(sockt->session[fd]->hdata[i]); - } - aFree(sockt->session[fd]->hdata); - } + HPM->data_store_destroy(&sockt->session[fd]->hdata); aFree(sockt->session[fd]); sockt->session[fd] = NULL; } @@ -977,7 +967,7 @@ static int connect_check_(uint32 ip) // Search the allow list for( i=0; i < access_allownum; ++i ){ - if( (ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask) ){ + if (SUBNET_MATCH(ip, access_allow[i].ip, access_allow[i].mask)) { if( access_debug ){ ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", CONVIP(ip), @@ -990,7 +980,7 @@ static int connect_check_(uint32 ip) } // Search the deny list for( i=0; i < access_denynum; ++i ){ - if( (ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask) ){ + if (SUBNET_MATCH(ip, access_deny[i].ip, access_deny[i].mask)) { if( access_debug ){ ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", CONVIP(ip), @@ -1226,20 +1216,9 @@ void socket_final(void) aFree(sockt->session); - if (sockt->lan_subnet) - aFree(sockt->lan_subnet); - sockt->lan_subnet = NULL; - sockt->lan_subnet_count = 0; - - if (sockt->allowed_ip) - aFree(sockt->allowed_ip); - sockt->allowed_ip = NULL; - sockt->allowed_ip_count = 0; - - if (sockt->trusted_ip) - aFree(sockt->trusted_ip); - sockt->trusted_ip = NULL; - sockt->trusted_ip_count = 0; + VECTOR_CLEAR(sockt->lan_subnets); + VECTOR_CLEAR(sockt->allowed_ips); + VECTOR_CLEAR(sockt->trusted_ips); } /// Closes a socket. @@ -1615,13 +1594,13 @@ void send_shortlist_do_sends() uint32 socket_lan_subnet_check(uint32 ip, struct s_subnet *info) { int i; - ARR_FIND(0, sockt->lan_subnet_count, i, (sockt->lan_subnet[i].ip & sockt->lan_subnet[i].mask) == (ip & sockt->lan_subnet[i].mask)); - if (i < sockt->lan_subnet_count) { + ARR_FIND(0, VECTOR_LENGTH(sockt->lan_subnets), i, SUBNET_MATCH(ip, VECTOR_INDEX(sockt->lan_subnets, i).ip, VECTOR_INDEX(sockt->lan_subnets, i).mask)); + if (i != VECTOR_LENGTH(sockt->lan_subnets)) { if (info) { - info->ip = sockt->lan_subnet[i].ip; - info->mask = sockt->lan_subnet[i].mask; + info->ip = VECTOR_INDEX(sockt->lan_subnets, i).ip; + info->mask = VECTOR_INDEX(sockt->lan_subnets, i).mask; } - return sockt->lan_subnet[i].ip; + return VECTOR_INDEX(sockt->lan_subnets, i).ip; } if (info) { info->ip = info->mask = 0; @@ -1639,8 +1618,8 @@ uint32 socket_lan_subnet_check(uint32 ip, struct s_subnet *info) bool socket_allowed_ip_check(uint32 ip) { int i; - ARR_FIND(0, sockt->allowed_ip_count, i, (sockt->allowed_ip[i].ip & sockt->allowed_ip[i].mask) == (ip & sockt->allowed_ip[i].mask) ); - if (i < sockt->allowed_ip_count) + ARR_FIND(0, VECTOR_LENGTH(sockt->allowed_ips), i, SUBNET_MATCH(ip, VECTOR_INDEX(sockt->allowed_ips, i).ip, VECTOR_INDEX(sockt->allowed_ips, i).mask)); + if (i != VECTOR_LENGTH(sockt->allowed_ips)) return true; return sockt->trusted_ip_check(ip); // If an address is trusted, it's automatically also allowed. } @@ -1655,8 +1634,8 @@ bool socket_allowed_ip_check(uint32 ip) bool socket_trusted_ip_check(uint32 ip) { int i; - ARR_FIND(0, sockt->trusted_ip_count, i, (sockt->trusted_ip[i].ip & sockt->trusted_ip[i].mask) == (ip & sockt->trusted_ip[i].mask)); - if (i < sockt->trusted_ip_count) + ARR_FIND(0, VECTOR_LENGTH(sockt->trusted_ips), i, SUBNET_MATCH(ip, VECTOR_INDEX(sockt->trusted_ips, i).ip, VECTOR_INDEX(sockt->trusted_ips, i).mask)); + if (i != VECTOR_LENGTH(sockt->trusted_ips)) return true; return false; } @@ -1667,39 +1646,38 @@ bool socket_trusted_ip_check(uint32 ip) * Entries will be appended to the variable-size array pointed to by list/count. * * @param[in] t The list to parse. - * @param[in,out] list Pointer to the head of the output array to append to. Must not be NULL (but the array may be empty). - * @param[in,out] count Pointer to the counter of the output array to append to. Must not be NULL (but it may contain zero). + * @param[in,out] list Vector to append to. Must not be NULL (but the vector may be empty). * @param[in] filename Current filename, for output/logging reasons. * @param[in] groupname Current group name, for output/logging reasons. * @return The amount of entries read, zero in case of errors. */ -int socket_net_config_read_sub(config_setting_t *t, struct s_subnet **list, int *count, const char *filename, const char *groupname) +int socket_net_config_read_sub(config_setting_t *t, struct s_subnet_vector *list, const char *filename, const char *groupname) { int i, len; char ipbuf[64], maskbuf[64]; nullpo_retr(0, list); - nullpo_retr(0, count); if (t == NULL) return 0; len = libconfig->setting_length(t); + VECTOR_ENSURE(*list, len, 1); for (i = 0; i < len; ++i) { const char *subnet = libconfig->setting_get_string_elem(t, i); - struct s_subnet *l = NULL; + struct s_subnet *entry = NULL; if (sscanf(subnet, "%63[^:]:%63[^:]", ipbuf, maskbuf) != 2) { ShowWarning("Invalid IP:Subnet entry in configuration file %s: '%s' (%s)\n", filename, subnet, groupname); + continue; } - RECREATE(*list, struct s_subnet, *count + 1); - l = *list; - l[*count].ip = sockt->str2ip(ipbuf); - l[*count].mask = sockt->str2ip(maskbuf); - ++*count; + VECTOR_PUSHZEROED(*list); + entry = &VECTOR_LAST(*list); + entry->ip = sockt->str2ip(ipbuf); + entry->mask = sockt->str2ip(maskbuf); } - return *count; + return (int)VECTOR_LENGTH(*list); } /** @@ -1718,45 +1696,29 @@ void socket_net_config_read(const char *filename) return; } - if (sockt->lan_subnet) { - aFree(sockt->lan_subnet); - sockt->lan_subnet = NULL; - } - sockt->lan_subnet_count = 0; - if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "lan_subnets"), &sockt->lan_subnet, &sockt->lan_subnet_count, filename, "lan_subnets") > 0) - ShowStatus("Read information about %d LAN subnets.\n", sockt->lan_subnet_count); + VECTOR_CLEAR(sockt->lan_subnets); + if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "lan_subnets"), &sockt->lan_subnets, filename, "lan_subnets") > 0) + ShowStatus("Read information about %d LAN subnets.\n", (int)VECTOR_LENGTH(sockt->lan_subnets)); - if (sockt->trusted_ip) { - aFree(sockt->trusted_ip); - sockt->trusted_ip = NULL; - } - sockt->trusted_ip_count = 0; - if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "trusted"), &sockt->trusted_ip, &sockt->trusted_ip_count, filename, "trusted") > 0) - ShowStatus("Read information about %d trusted IP ranges.\n", sockt->trusted_ip_count); - for (i = 0; i < sockt->allowed_ip_count; ++i) { - if ((sockt->allowed_ip[i].ip & sockt->allowed_ip[i].mask) == 0) { - ShowError("Using a wildcard IP range in the trusted server IPs is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your '%s' trusted list to fit your network configuration.\n", filename); - break; - } + VECTOR_CLEAR(sockt->trusted_ips); + if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "trusted"), &sockt->trusted_ips, filename, "trusted") > 0) + ShowStatus("Read information about %d trusted IP ranges.\n", (int)VECTOR_LENGTH(sockt->trusted_ips)); + ARR_FIND(0, VECTOR_LENGTH(sockt->trusted_ips), i, SUBNET_MATCH(0, VECTOR_INDEX(sockt->trusted_ips, i).ip, VECTOR_INDEX(sockt->trusted_ips, i).mask)); + if (i != VECTOR_LENGTH(sockt->trusted_ips)) { + ShowError("Using a wildcard IP range in the trusted server IPs is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your '%s' trusted list to fit your network configuration.\n", filename); } - if (sockt->allowed_ip) { - aFree(sockt->allowed_ip); - sockt->allowed_ip = NULL; - } - sockt->allowed_ip_count = 0; - if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "allowed"), &sockt->allowed_ip, &sockt->allowed_ip_count, filename, "allowed") > 0) - ShowStatus("Read information about %d allowed server IP ranges.\n", sockt->allowed_ip_count); - if (sockt->allowed_ip_count == 0) { + VECTOR_CLEAR(sockt->allowed_ips); + if (sockt->net_config_read_sub(libconfig->lookup(&network_config, "allowed"), &sockt->allowed_ips, filename, "allowed") > 0) + ShowStatus("Read information about %d allowed server IP ranges.\n", (int)VECTOR_LENGTH(sockt->allowed_ips)); + if (VECTOR_LENGTH(sockt->allowed_ips) + VECTOR_LENGTH(sockt->trusted_ips) == 0) { ShowError("No allowed server IP ranges configured. This server won't be able to accept connections from any char servers.\n"); } - for (i = 0; i < sockt->allowed_ip_count; ++i) { - if ((sockt->allowed_ip[i].ip & sockt->allowed_ip[i].mask) == 0) { - ShowWarning("Using a wildcard IP range in the allowed server IPs is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your '%s' allowed list to fit your network configuration.\n", filename); - break; - } + ARR_FIND(0, VECTOR_LENGTH(sockt->allowed_ips), i, SUBNET_MATCH(0, VECTOR_INDEX(sockt->allowed_ips, i).ip, VECTOR_INDEX(sockt->allowed_ips, i).mask)); + if (i != VECTOR_LENGTH(sockt->allowed_ips)) { + ShowWarning("Using a wildcard IP range in the allowed server IPs is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your '%s' allowed list to fit your network configuration.\n", filename); } libconfig->destroy(&network_config); return; @@ -1773,12 +1735,9 @@ void socket_defaults(void) { memset(&sockt->addr_, 0, sizeof(sockt->addr_)); sockt->naddr_ = 0; /* */ - sockt->lan_subnet_count = 0; - sockt->lan_subnet = NULL; - sockt->allowed_ip_count = 0; - sockt->allowed_ip = NULL; - sockt->trusted_ip_count = 0; - sockt->trusted_ip = NULL; + VECTOR_INIT(sockt->lan_subnets); + VECTOR_INIT(sockt->allowed_ips); + VECTOR_INIT(sockt->trusted_ips); sockt->init = socket_init; sockt->final = socket_final; diff --git a/src/common/socket.h b/src/common/socket.h index a995bffc8..426f8e4bb 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -7,6 +7,7 @@ #include "common/hercules.h" #include "common/conf.h" +#include "common/db.h" #ifdef WIN32 # include "common/winapi.h" @@ -17,7 +18,7 @@ # include <sys/types.h> #endif -struct HPluginData; +struct hplugin_data_store; #define FIFOSIZE_SERVERLINK 256*1024 @@ -104,9 +105,7 @@ struct socket_data { ParseFunc func_parse; void* session_data; // stores application-specific data related to the session - - struct HPluginData **hdata; - unsigned int hdatac; + struct hplugin_data_store *hdata; ///< HPM Plugin Data Store. }; struct hSockOpt { @@ -120,6 +119,9 @@ struct s_subnet { uint32 mask; }; +/// A vector of subnets/IP ranges. +VECTOR_STRUCT_DECL(s_subnet_vector, struct s_subnet); + /// Use a shortlist of sockets instead of iterating all sessions for sockets /// that have data to send or need eof handling. /// Adapted to use a static array instead of a linked list. @@ -131,6 +133,11 @@ struct s_subnet { #define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF #define MAKEIP(a,b,c,d) ((uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) )) +/// Applies a subnet mask to an IP +#define APPLY_MASK(ip, mask) ((ip)&(mask)) +/// Verifies the match between two IPs, with a subnet mask applied +#define SUBNET_MATCH(ip1, ip2, mask) (APPLY_MASK((ip1), (mask)) == APPLY_MASK((ip2), (mask))) + /** * Socket.c interface, mostly for reading however. **/ @@ -145,12 +152,9 @@ struct socket_interface { struct socket_data **session; - struct s_subnet *lan_subnet; ///< LAN subnets array - int lan_subnet_count; ///< LAN subnets count - struct s_subnet *trusted_ip; ///< Trusted IP ranges array - int trusted_ip_count; ///< Trusted IP ranges count - struct s_subnet *allowed_ip; ///< Allowed server IP ranges array - int allowed_ip_count; ///< Allowed server IP ranges count + struct s_subnet_vector lan_subnets; ///< LAN subnets. + struct s_subnet_vector trusted_ips; ///< Trusted IP ranges + struct s_subnet_vector allowed_ips; ///< Allowed server IP ranges /* */ void (*init) (void); @@ -189,7 +193,7 @@ struct socket_interface { uint32 (*lan_subnet_check) (uint32 ip, struct s_subnet *info); bool (*allowed_ip_check) (uint32 ip); bool (*trusted_ip_check) (uint32 ip); - int (*net_config_read_sub) (config_setting_t *t, struct s_subnet **list, int *count, const char *filename, const char *groupname); + int (*net_config_read_sub) (config_setting_t *t, struct s_subnet_vector *list, const char *filename, const char *groupname); void (*net_config_read) (const char *filename); }; diff --git a/src/common/timer.c b/src/common/timer.c index 793706511..f6ce00d54 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -239,6 +239,10 @@ int64 timer_gettick(void) { /// Adds a timer to the timer_heap static void push_timer_heap(int tid) { BHEAP_ENSURE(timer_heap, 1, 256); +#ifdef __clang_analyzer__ // Clang's static analyzer warns that BHEAP_ENSURE might set BHEAP_DATA(timer_heap) to NULL. +#include "assert.h" + assert(BHEAP_DATA(timer_heap) != NULL); +#endif // __clang_analyzer__ BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP, swap); } @@ -348,14 +352,21 @@ int64 timer_addtick(int tid, int64 tick) { return timer->settick(tid, timer_data[tid].tick+tick); } -/// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). -/// Returns the new tick value, or -1 if it fails. -int64 timer_settick(int tid, int64 tick) { - size_t i; +/** + * Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). + * + * @param tid The timer ID. + * @param tick New expiration time. + * @return The new tick value. + * @retval -1 in case of failure. + */ +int64 timer_settick(int tid, int64 tick) +{ + int i; // search timer position ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); - if( i == BHEAP_LENGTH(timer_heap) ) { + if (i == BHEAP_LENGTH(timer_heap)) { ShowError("timer_settick: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); return -1; } @@ -373,13 +384,18 @@ int64 timer_settick(int tid, int64 tick) { return tick; } -/// Executes all expired timers. -/// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). -int do_timer(int64 tick) { +/** + * Executes all expired timers. + * + * @param tick The current tick. + * @return The value of the smallest non-expired timer (or 1 second if there aren't any). + */ +int do_timer(int64 tick) +{ int64 diff = TIMER_MAX_INTERVAL; // return value // process all timers one by one - while( BHEAP_LENGTH(timer_heap) ) { + while (BHEAP_LENGTH(timer_heap) > 0) { int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) diff = DIFF_TICK(timer_data[tid].tick, tick); |