summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2015-10-11 16:11:43 +0300
committerAndrei Karas <akaras@inbox.ru>2015-10-11 16:11:43 +0300
commit6c0f05b05e9bf09f40df3e3fe7f768f7435abcec (patch)
tree6973517e1821f128b36955fc258419131b98f7fc /src/common
parentd70d9d4d19f0deae2a2aceb047872611d5047ae0 (diff)
parent845139091f0305d264800491ce25152856c20374 (diff)
downloadhercules-6c0f05b05e9bf09f40df3e3fe7f768f7435abcec.tar.gz
hercules-6c0f05b05e9bf09f40df3e3fe7f768f7435abcec.tar.bz2
hercules-6c0f05b05e9bf09f40df3e3fe7f768f7435abcec.tar.xz
hercules-6c0f05b05e9bf09f40df3e3fe7f768f7435abcec.zip
Merge pull request #760 from HerculesWS/738-vectors
Change several variable-size array to VECTOR (common, char)
Diffstat (limited to 'src/common')
-rw-r--r--src/common/HPM.c696
-rw-r--r--src/common/HPM.h66
-rw-r--r--src/common/HPMDataCheck.h1
-rw-r--r--src/common/HPMi.h121
-rw-r--r--src/common/cbasetypes.h2
-rw-r--r--src/common/console.c286
-rw-r--r--src/common/console.h18
-rw-r--r--src/common/core.c35
-rw-r--r--src/common/core.h4
-rw-r--r--src/common/db.h1321
-rw-r--r--src/common/mmo.h7
-rw-r--r--src/common/socket.c133
-rw-r--r--src/common/socket.h26
-rw-r--r--src/common/timer.c34
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);