summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/HPM.c232
-rw-r--r--src/common/HPM.h18
-rw-r--r--src/common/HPMDataCheck.h70
-rw-r--r--src/common/HPMSymbols.inc.h281
-rw-r--r--src/common/HPMi.h43
-rw-r--r--src/common/Makefile.in34
-rw-r--r--src/common/atomic.h2
-rw-r--r--src/common/cbasetypes.h86
-rw-r--r--src/common/conf.c381
-rw-r--r--src/common/conf.h156
-rw-r--r--src/common/console.c87
-rw-r--r--src/common/console.h24
-rw-r--r--src/common/core.c143
-rw-r--r--src/common/core.h2
-rw-r--r--src/common/db.c724
-rw-r--r--src/common/db.h392
-rw-r--r--src/common/des.c162
-rw-r--r--src/common/des.h45
-rw-r--r--src/common/ers.c24
-rw-r--r--src/common/ers.h2
-rw-r--r--src/common/grfio.c515
-rw-r--r--src/common/grfio.h108
-rw-r--r--src/common/mapindex.c37
-rw-r--r--src/common/mapindex.h8
-rw-r--r--src/common/md5calc.c178
-rw-r--r--src/common/md5calc.h44
-rw-r--r--src/common/memmgr.c85
-rw-r--r--src/common/memmgr.h8
-rw-r--r--src/common/mmo.h165
-rw-r--r--src/common/mutex.c170
-rw-r--r--src/common/mutex.h168
-rw-r--r--src/common/nullpo.c2
-rw-r--r--src/common/nullpo.h2
-rw-r--r--src/common/random.c62
-rw-r--r--src/common/random.h84
-rw-r--r--src/common/showmsg.c28
-rw-r--r--src/common/showmsg.h13
-rw-r--r--src/common/socket.c653
-rw-r--r--src/common/socket.h47
-rw-r--r--src/common/spinlock.h89
-rw-r--r--src/common/sql.c272
-rw-r--r--src/common/sql.h80
-rw-r--r--src/common/strlib.c20
-rw-r--r--src/common/strlib.h8
-rw-r--r--src/common/sysinfo.c133
-rw-r--r--src/common/sysinfo.h1
-rw-r--r--src/common/thread.c250
-rw-r--r--src/common/thread.h232
-rw-r--r--src/common/timer.c80
-rw-r--r--src/common/timer.h2
-rw-r--r--src/common/utils.c31
-rw-r--r--src/common/utils.h5
-rw-r--r--src/common/winapi.h2
53 files changed, 4232 insertions, 2258 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c
index d9c3262d7..c84b447e8 100644
--- a/src/common/HPM.c
+++ b/src/common/HPM.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2016 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
#include "common/timer.h"
#include "common/utils.h"
#include "common/nullpo.h"
+#include "plugins/HPMHooking.h"
#include <stdio.h>
#include <stdlib.h>
@@ -51,11 +52,12 @@ struct malloc_interface iMalloc_HPM;
struct malloc_interface *HPMiMalloc;
struct HPM_interface HPM_s;
struct HPM_interface *HPM;
+struct HPMHooking_core_interface HPMHooking_core_s;
/**
* (char*) data name -> (unsigned int) HPMDataCheck[] index
**/
-DBMap *datacheck_db;
+struct DBMap *datacheck_db;
int datacheck_version;
const struct s_HPMDataCheck *datacheck_data;
@@ -101,6 +103,7 @@ void hplugin_export_symbol(void *value, const char *name)
void *hplugin_import_symbol(char *name, unsigned int pID)
{
int i;
+ nullpo_retr(NULL, name);
ARR_FIND(0, VECTOR_LENGTH(HPM->symbols), i, strcmp(VECTOR_INDEX(HPM->symbols, i)->name, name) == 0);
if (i != VECTOR_LENGTH(HPM->symbols))
@@ -131,6 +134,7 @@ bool hplugin_iscompatible(char* version) {
bool hplugin_exists(const char *filename)
{
int i;
+ nullpo_retr(false, filename);
for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) {
if (strcmpi(VECTOR_INDEX(HPM->plugins, i)->filename,filename) == 0)
return true;
@@ -214,11 +218,11 @@ bool hplugin_data_store_validate(enum HPluginDataTypes type, struct hplugin_data
break;
default:
if (HPM->data_store_validate_sub == NULL) {
- ShowError("HPM:validateHPData failed, type %d needs sub-handler!\n",type);
+ ShowError("HPM:validateHPData failed, type %u 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);
+ ShowError("HPM:HPM:validateHPData failed, unknown type %u!\n", type);
return false;
}
break;
@@ -228,7 +232,7 @@ bool hplugin_data_store_validate(enum HPluginDataTypes type, struct hplugin_data
store = *storeptr;
}
if (store->type != type) {
- ShowError("HPM:HPM:validateHPData failed, store type mismatch %d != %d.\n",store->type, type);
+ ShowError("HPM:HPM:validateHPData failed, store type mismatch %u != %u.\n", store->type, type);
return false;
}
return true;
@@ -253,10 +257,11 @@ void hplugins_addToHPData(enum HPluginDataTypes type, uint32 pluginID, struct hp
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);
+ ShowError("HPM:addToHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
return;
}
store = *storeptr;
+ nullpo_retv(store);
/* duplicate check */
ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid);
@@ -294,7 +299,7 @@ void *hplugins_getFromHPData(enum HPluginDataTypes type, uint32 pluginID, struct
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);
+ ShowError("HPM:getFromHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
return NULL;
}
if (!store)
@@ -322,7 +327,7 @@ void hplugins_removeFromHPData(enum HPluginDataTypes type, uint32 pluginID, stru
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);
+ ShowError("HPM:removeFromHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
return;
}
if (!store)
@@ -341,13 +346,13 @@ void hplugins_removeFromHPData(enum HPluginDataTypes type, uint32 pluginID, stru
/* TODO: add ability for tracking using pID for the upcoming runtime load/unload support. */
bool HPM_AddHook(enum HPluginHookType type, const char *target, void *hook, unsigned int pID)
{
- if (!HPM->hooking) {
+ if (!HPM->hooking->enabled) {
ShowError("HPM:AddHook Fail! '%s' tried to hook to '%s' but HPMHooking is disabled!\n",HPM->pid2name(pID),target);
return false;
}
/* search if target is a known hook point within 'common' */
/* if not check if a sub-hooking list is available (from the server) and run it by */
- if (HPM->addhook_sub && HPM->addhook_sub(type,target,hook,pID))
+ if (HPM->hooking->addhook_sub != NULL && HPM->hooking->addhook_sub(type,target,hook,pID))
return true;
ShowError("HPM:AddHook: unknown Hooking Point '%s'!\n",target);
@@ -358,12 +363,12 @@ bool HPM_AddHook(enum HPluginHookType type, const char *target, void *hook, unsi
void HPM_HookStop(const char *func, unsigned int pID)
{
/* track? */
- HPM->force_return = true;
+ HPM->hooking->force_return = true;
}
-bool HPM_HookStopped (void)
+bool HPM_HookStopped(void)
{
- return HPM->force_return;
+ return HPM->hooking->force_return;
}
/**
@@ -387,12 +392,12 @@ bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecF
ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), i, strcmp(VECTOR_INDEX(cmdline->args_data, i).name, name) == 0);
- if (i != VECTOR_LENGTH(cmdline->args_data)) {
- ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
- return false;
- }
+ if (i != VECTOR_LENGTH(cmdline->args_data)) {
+ ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
+ return false;
+ }
- return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL);
+ return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL);
}
/**
@@ -405,7 +410,7 @@ bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecF
* @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 (*parse_func) (const char *key, const char *val), int (*return_func) (const char *key))
+bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *name, void (*parse_func) (const char *key, const char *val), int (*return_func) (const char *key), bool required)
{
struct HPConfListenStorage *conf;
int i;
@@ -440,11 +445,13 @@ bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *na
safestrncpy(conf->key, name, HPM_ADDCONF_LENGTH);
conf->parse_func = parse_func;
conf->return_func = return_func;
+ conf->required = required;
return true;
}
-struct hplugin *hplugin_load(const char* filename) {
+struct hplugin *hplugin_load(const char* filename)
+{
struct hplugin *plugin;
struct hplugin_info *info;
struct HPMi_interface **HPMi;
@@ -560,6 +567,7 @@ struct hplugin *hplugin_load(const char* filename) {
/* id */
plugin->hpi->pid = plugin->idx;
/* core */
+ plugin->hpi->memmgr = HPMiMalloc;
#ifdef CONSOLE_INPUT
plugin->hpi->addCPCommand = console->input->addCommand;
#endif // CONSOLE_INPUT
@@ -567,16 +575,20 @@ struct hplugin *hplugin_load(const char* filename) {
plugin->hpi->addToHPData = hplugins_addToHPData;
plugin->hpi->getFromHPData = hplugins_getFromHPData;
plugin->hpi->removeFromHPData = hplugins_removeFromHPData;
- plugin->hpi->AddHook = HPM_AddHook;
- plugin->hpi->HookStop = HPM_HookStop;
- plugin->hpi->HookStopped = HPM_HookStopped;
plugin->hpi->addArg = hpm_add_arg;
plugin->hpi->addConf = hplugins_addconf;
+ if ((plugin->hpi->hooking = plugin_import(plugin->dll, "HPMHooking_s", struct HPMHooking_interface *)) != NULL) {
+ plugin->hpi->hooking->AddHook = HPM_AddHook;
+ plugin->hpi->hooking->HookStop = HPM_HookStop;
+ plugin->hpi->hooking->HookStopped = HPM_HookStopped;
+ }
/* server specific */
if( HPM->load_sub )
HPM->load_sub(plugin);
- ShowStatus("HPM: Loaded plugin '"CL_WHITE"%s"CL_RESET"' (%s).\n", plugin->info->name, plugin->info->version);
+ ShowStatus("HPM: Loaded plugin '"CL_WHITE"%s"CL_RESET"' (%s)%s.\n",
+ plugin->info->name, plugin->info->version,
+ plugin->hpi->hooking != NULL ? " built with HPMHooking support" : "");
return plugin;
}
@@ -589,6 +601,7 @@ struct hplugin *hplugin_load(const char* filename) {
void hplugin_unload(struct hplugin* plugin)
{
int i;
+ nullpo_retv(plugin);
if (plugin->filename)
aFree(plugin->filename);
if (plugin->dll)
@@ -615,9 +628,10 @@ CMDLINEARG(loadplugin)
/**
* Reads the plugin configuration and loads the plugins as necessary.
*/
-void hplugins_config_read(void) {
- config_t plugins_conf;
- config_setting_t *plist = NULL;
+void hplugins_config_read(void)
+{
+ struct config_t plugins_conf;
+ struct config_setting_t *plist = NULL;
const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name
FILE *fp;
int i;
@@ -628,12 +642,12 @@ void hplugins_config_read(void) {
fclose(fp);
}
- if (libconfig->read_file(&plugins_conf, config_filename))
+ if (!libconfig->load_file(&plugins_conf, config_filename))
return;
plist = libconfig->lookup(&plugins_conf, "plugins_list");
for (i = 0; i < VECTOR_LENGTH(HPM->cmdline_load_plugins); i++) {
- config_setting_t *entry = libconfig->setting_add(plist, NULL, CONFIG_TYPE_STRING);
+ struct config_setting_t *entry = libconfig->setting_add(plist, NULL, CONFIG_TYPE_STRING);
config_setting_set_string(entry, VECTOR_INDEX(HPM->cmdline_load_plugins, i));
}
@@ -660,12 +674,13 @@ void hplugins_config_read(void) {
bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
if ((func = plugin_import(plugin->dll, "Hooked",const char * (*)(bool *))) != NULL
&& (addhook_sub = plugin_import(plugin->dll, "HPM_Plugin_AddHook",bool (*)(enum HPluginHookType, const char *, void *, unsigned int))) != NULL) {
- const char *failed = func(&HPM->force_return);
+ const char *failed = func(&HPM->hooking->force_return);
if (failed) {
ShowError("HPM: failed to retrieve '%s' for '"CL_WHITE"%s"CL_RESET"'!\n", failed, plugin_name);
} else {
- HPM->hooking = true;
- HPM->addhook_sub = addhook_sub;
+ HPM->hooking->enabled = true;
+ HPM->hooking->addhook_sub = addhook_sub;
+ HPM->hooking->Hooked = func; // The purpose of this is type-checking 'func' at compile time.
}
}
}
@@ -780,6 +795,7 @@ const char *HPM_file2ptr(const char *file)
{
int i;
+ nullpo_retr(NULL, file);
ARR_FIND(0, HPM->filenames.count, i, HPM->filenames.data[i].addr == file);
if (i != HPM->filenames.count) {
return HPM->filenames.data[i].name;
@@ -793,19 +809,29 @@ const char *HPM_file2ptr(const char *file)
return HPM->filenames.data[i].name;
}
-void* HPM_mmalloc(size_t size, const char *file, int line, const char *func) {
+
+void* HPM_mmalloc(size_t size, const char *file, int line, const char *func)
+{
return iMalloc->malloc(size,HPM_file2ptr(file),line,func);
}
-void* HPM_calloc(size_t num, size_t size, const char *file, int line, const char *func) {
+
+void* HPM_calloc(size_t num, size_t size, const char *file, int line, const char *func)
+{
return iMalloc->calloc(num,size,HPM_file2ptr(file),line,func);
}
-void* HPM_realloc(void *p, size_t size, const char *file, int line, const char *func) {
+
+void* HPM_realloc(void *p, size_t size, const char *file, int line, const char *func)
+{
return iMalloc->realloc(p,size,HPM_file2ptr(file),line,func);
}
-void* HPM_reallocz(void *p, size_t size, const char *file, int line, const char *func) {
+
+void* HPM_reallocz(void *p, size_t size, const char *file, int line, const char *func)
+{
return iMalloc->reallocz(p,size,HPM_file2ptr(file),line,func);
}
-char* HPM_astrdup(const char *p, const char *file, int line, const char *func) {
+
+char* HPM_astrdup(const char *p, const char *file, int line, const char *func)
+{
return iMalloc->astrdup(p,HPM_file2ptr(file),line,func);
}
@@ -818,7 +844,7 @@ char* HPM_astrdup(const char *p, const char *file, int line, const char *func) {
* @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)
+bool hplugins_parse_conf_entry(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);
@@ -841,6 +867,7 @@ bool hplugins_get_battle_conf(const char *w1, int *value)
{
int i;
+ nullpo_retr(false, w1);
nullpo_retr(false, value);
ARR_FIND(0, VECTOR_LENGTH(HPM->config_listeners[HPCT_BATTLE]), i, strcmpi(w1, VECTOR_INDEX(HPM->config_listeners[HPCT_BATTLE], i).key) == 0);
@@ -852,6 +879,106 @@ bool hplugins_get_battle_conf(const char *w1, int *value)
}
/**
+ * Parses configuration entries registered by plugins.
+ *
+ * @param config The configuration file to parse.
+ * @param filename Path to configuration file.
+ * @param point The type of configuration file.
+ * @param imported Whether the current config is imported from another file.
+ * @retval false in case of error.
+ */
+bool hplugins_parse_conf(const struct config_t *config, const char *filename, enum HPluginConfType point, bool imported)
+{
+ const struct config_setting_t *setting = NULL;
+ int i, val, type;
+ char buf[1024];
+ bool retval = true;
+
+ nullpo_retr(false, config);
+
+ for (i = 0; i < VECTOR_LENGTH(HPM->config_listeners[point]); i++) {
+ const struct HPConfListenStorage *entry = &VECTOR_INDEX(HPM->config_listeners[point], i);
+ const char *config_name = entry->key;
+ const char *str = NULL;
+ if ((setting = libconfig->lookup(config, config_name)) == NULL) {
+ if (!imported && entry->required) {
+ ShowWarning("Missing configuration '%s' in file %s!\n", config_name, filename);
+ retval = false;
+ }
+ continue;
+ }
+
+ switch ((type = config_setting_type(setting))) {
+ case CONFIG_TYPE_INT:
+ val = libconfig->setting_get_int(setting);
+ sprintf(buf, "%d", val); // FIXME: Remove this when support to int's as value is added
+ str = buf;
+ break;
+ case CONFIG_TYPE_BOOL:
+ val = libconfig->setting_get_bool(setting);
+ sprintf(buf, "%d", val); // FIXME: Remove this when support to int's as value is added
+ str = buf;
+ break;
+ case CONFIG_TYPE_STRING:
+ str = libconfig->setting_get_string(setting);
+ break;
+ default: // Unsupported type
+ ShowWarning("Setting %s has unsupported type %d, ignoring...\n", config_name, type);
+ retval = false;
+ continue;
+ }
+ entry->parse_func(config_name, str);
+ }
+ return retval;
+}
+
+/**
+ * parses battle config entries registered by plugins.
+ *
+ * @param config the configuration file to parse.
+ * @param filename path to configuration file.
+ * @param imported whether the current config is imported from another file.
+ * @retval false in case of error.
+ */
+bool hplugins_parse_battle_conf(const struct config_t *config, const char *filename, bool imported)
+{
+ const struct config_setting_t *setting = NULL;
+ int i, val, type;
+ char str[1024];
+ bool retval = true;
+
+ nullpo_retr(false, config);
+
+ for (i = 0; i < VECTOR_LENGTH(HPM->config_listeners[HPCT_BATTLE]); i++) {
+ const struct HPConfListenStorage *entry = &VECTOR_INDEX(HPM->config_listeners[HPCT_BATTLE], i);
+ const char *config_name = entry->key;
+ if ((setting = libconfig->lookup(config, config_name)) == NULL) {
+ if (!imported && entry->required) {
+ ShowWarning("Missing configuration '%s' in file %s!\n", config_name, filename);
+ retval = false;
+ }
+ continue;
+ }
+
+ switch ((type = config_setting_type(setting))) {
+ case CONFIG_TYPE_INT:
+ val = libconfig->setting_get_int(setting);
+ break;
+ case CONFIG_TYPE_BOOL:
+ val = libconfig->setting_get_bool(setting);
+ break;
+ default: // Unsupported type
+ ShowWarning("Setting %s has unsupported type %d, ignoring...\n", config_name, type);
+ retval = false;
+ continue;
+ }
+ sprintf(str, "%d", val); // FIXME: Remove this when support to int's as value is added
+ entry->parse_func(config_name, str);
+ }
+ return retval;
+}
+
+/**
* Helper to destroy an interface's hplugin_data store and release any owned memory.
*
* The pointer will be cleared.
@@ -904,9 +1031,11 @@ void hplugin_data_store_create(struct hplugin_data_store **storeptr, enum HPlugi
/**
* Called by HPM->DataCheck on a plugins incoming data, ensures data structs in use are matching!
**/
-bool HPM_DataCheck(struct s_HPMDataCheck *src, unsigned int size, int version, char *name) {
+bool HPM_DataCheck(struct s_HPMDataCheck *src, unsigned int size, int version, char *name)
+{
unsigned int i, j;
+ nullpo_retr(false, src);
if (version != datacheck_version) {
ShowError("HPMDataCheck:%s: DataCheck API version mismatch %d != %d\n", name, datacheck_version, version);
return false;
@@ -931,7 +1060,8 @@ bool HPM_DataCheck(struct s_HPMDataCheck *src, unsigned int size, int version, c
return true;
}
-void HPM_datacheck_init(const struct s_HPMDataCheck *src, unsigned int length, int version) {
+void HPM_datacheck_init(const struct s_HPMDataCheck *src, unsigned int length, int version)
+{
unsigned int i;
datacheck_version = version;
@@ -947,11 +1077,13 @@ void HPM_datacheck_init(const struct s_HPMDataCheck *src, unsigned int length, i
}
}
-void HPM_datacheck_final(void) {
+void HPM_datacheck_final(void)
+{
db_destroy(datacheck_db);
}
-void hpm_init(void) {
+void hpm_init(void)
+{
int i;
datacheck_db = NULL;
datacheck_data = NULL;
@@ -962,8 +1094,8 @@ void hpm_init(void) {
HPM->off = false;
- memcpy(&iMalloc_HPM, iMalloc, sizeof(struct malloc_interface));
HPMiMalloc = &iMalloc_HPM;
+ *HPMiMalloc = *iMalloc;
HPMiMalloc->malloc = HPM_mmalloc;
HPMiMalloc->calloc = HPM_calloc;
HPMiMalloc->realloc = HPM_realloc;
@@ -1043,14 +1175,14 @@ void hpm_final(void)
return;
}
+
void hpm_defaults(void)
{
HPM = &HPM_s;
+ HPM->hooking = &HPMHooking_core_s;
memset(&HPM->filenames, 0, sizeof(HPM->filenames));
VECTOR_INIT(HPM->cmdline_load_plugins);
- HPM->force_return = false;
- HPM->hooking = false;
/* */
HPM->init = hpm_init;
HPM->final = hpm_final;
@@ -1067,8 +1199,9 @@ void hpm_defaults(void)
HPM->pid2name = hplugins_id2name;
HPM->parse_packets = hplugins_parse_packets;
HPM->load_sub = NULL;
- HPM->addhook_sub = NULL;
- HPM->parseConf = hplugins_parse_conf;
+ HPM->parse_conf_entry = hplugins_parse_conf_entry;
+ HPM->parse_conf = hplugins_parse_conf;
+ HPM->parse_battle_conf = hplugins_parse_battle_conf;
HPM->getBattleConf = hplugins_get_battle_conf;
HPM->DataCheck = HPM_DataCheck;
HPM->datacheck_init = HPM_datacheck_init;
@@ -1078,4 +1211,9 @@ void hpm_defaults(void)
HPM->data_store_create = hplugin_data_store_create;
HPM->data_store_validate = hplugin_data_store_validate;
HPM->data_store_validate_sub = NULL;
+
+ HPM->hooking->enabled = false;
+ HPM->hooking->force_return = false;
+ HPM->hooking->addhook_sub = NULL;
+ HPM->hooking->Hooked = NULL;
}
diff --git a/src/common/HPM.h b/src/common/HPM.h
index 109549aad..e55397022 100644
--- a/src/common/HPM.h
+++ b/src/common/HPM.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2016 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,6 +65,10 @@
#endif // WIN32
+/* Forward Declarations */
+struct HPMHooking_core_interface;
+struct config_t;
+
struct hplugin {
DLL dll;
unsigned int idx;
@@ -119,6 +123,7 @@ struct HPConfListenStorage {
char key[HPM_ADDCONF_LENGTH];
void (*parse_func) (const char *key, const char *val);
int (*return_func) (const char *key);
+ bool required;
};
/* Hercules Plugin Manager Interface */
@@ -126,9 +131,6 @@ struct HPM_interface {
/* vars */
unsigned int version[2];
bool off;
- bool hooking;
- /* hooking */
- bool force_return;
/* data */
VECTOR_DECL(struct hplugin *) plugins;
VECTOR_DECL(struct hpm_symbol *) symbols;
@@ -156,12 +158,13 @@ struct HPM_interface {
void *(*import_symbol) (char *name, unsigned int pID);
void (*share) (void *value, const char *name);
void (*config_read) (void);
+ bool (*parse_battle_conf) (const struct config_t *config, const char *filename, bool imported);
char *(*pid2name) (unsigned int pid);
unsigned char (*parse_packets) (int fd, int packet_id, enum HPluginPacketHookingPoints point);
void (*load_sub) (struct hplugin *plugin);
- bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
/* for custom config parsing */
- bool (*parseConf) (const char *w1, const char *w2, enum HPluginConfType point);
+ bool (*parse_conf) (const struct config_t *config, const char *filename, enum HPluginConfType point, bool imported);
+ bool (*parse_conf_entry) (const char *w1, const char *w2, enum HPluginConfType point);
bool (*getBattleConf) (const char* w1, int *value);
/* validates plugin data */
bool (*DataCheck) (struct s_HPMDataCheck *src, unsigned int size, int version, char *name);
@@ -173,6 +176,9 @@ struct HPM_interface {
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);
+
+ /* hooking */
+ struct HPMHooking_core_interface *hooking;
};
CMDLINEARG(loadplugin);
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 666d306db..2a1c092b7 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2014-2016 Hercules Dev Team
+ * Copyright (C) 2014-2017 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,8 @@
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+
#ifndef HPM_DATA_CHECK_H
#define HPM_DATA_CHECK_H
@@ -148,7 +150,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#define COMMON_DB_H
#endif // COMMON_DB_H
#ifdef COMMON_DES_H
- { "BIT64", sizeof(struct BIT64), SERVER_TYPE_ALL },
+ { "des_bit64", sizeof(struct des_bit64), SERVER_TYPE_ALL },
+ { "des_interface", sizeof(struct des_interface), SERVER_TYPE_ALL },
#else
#define COMMON_DES_H
#endif // COMMON_DES_H
@@ -157,6 +160,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_ERS_H
#endif // COMMON_ERS_H
+ #ifdef COMMON_GRFIO_H
+ { "grfio_interface", sizeof(struct grfio_interface), SERVER_TYPE_MAP },
+ #else
+ #define COMMON_GRFIO_H
+ #endif // COMMON_GRFIO_H
#ifdef COMMON_HPMI_H
{ "HPMi_interface", sizeof(struct HPMi_interface), SERVER_TYPE_ALL },
{ "hplugin_info", sizeof(struct hplugin_info), SERVER_TYPE_ALL },
@@ -169,6 +177,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_MAPINDEX_H
#endif // COMMON_MAPINDEX_H
+ #ifdef COMMON_MD5CALC_H
+ { "md5_interface", sizeof(struct md5_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_MD5CALC_H
+ #endif // COMMON_MD5CALC_H
#ifdef COMMON_MEMMGR_H
{ "malloc_interface", sizeof(struct malloc_interface), SERVER_TYPE_ALL },
#else
@@ -208,11 +221,21 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_MMO_H
#endif // COMMON_MMO_H
+ #ifdef COMMON_MUTEX_H
+ { "mutex_interface", sizeof(struct mutex_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_MUTEX_H
+ #endif // COMMON_MUTEX_H
#ifdef COMMON_NULLPO_H
{ "nullpo_interface", sizeof(struct nullpo_interface), SERVER_TYPE_ALL },
#else
#define COMMON_NULLPO_H
#endif // COMMON_NULLPO_H
+ #ifdef COMMON_RANDOM_H
+ { "rnd_interface", sizeof(struct rnd_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_RANDOM_H
+ #endif // COMMON_RANDOM_H
#ifdef COMMON_SHOWMSG_H
{ "showmsg_interface", sizeof(struct showmsg_interface), SERVER_TYPE_ALL },
#else
@@ -228,7 +251,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#define COMMON_SOCKET_H
#endif // COMMON_SOCKET_H
#ifdef COMMON_SPINLOCK_H
- { "SPIN_LOCK", sizeof(struct SPIN_LOCK), SERVER_TYPE_ALL },
+ { "spin_lock", sizeof(struct spin_lock), SERVER_TYPE_ALL },
#else
#define COMMON_SPINLOCK_H
#endif // COMMON_SPINLOCK_H
@@ -251,6 +274,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_SYSINFO_H
#endif // COMMON_SYSINFO_H
+ #ifdef COMMON_THREAD_H
+ { "thread_interface", sizeof(struct thread_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_THREAD_H
+ #endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H
{ "TimerData", sizeof(struct TimerData), SERVER_TYPE_ALL },
{ "timer_interface", sizeof(struct timer_interface), SERVER_TYPE_ALL },
@@ -270,6 +298,32 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define LOGIN_ACCOUNT_H
#endif // LOGIN_ACCOUNT_H
+ #ifdef LOGIN_LCLIF_H
+ { "lclif_interface", sizeof(struct lclif_interface), SERVER_TYPE_LOGIN },
+ { "login_packet_db", sizeof(struct login_packet_db), SERVER_TYPE_LOGIN },
+ #else
+ #define LOGIN_LCLIF_H
+ #endif // LOGIN_LCLIF_H
+ #ifdef LOGIN_LCLIF_P_H
+ { "lclif_interface_dbs", sizeof(struct lclif_interface_dbs), SERVER_TYPE_LOGIN },
+ { "lclif_interface_private", sizeof(struct lclif_interface_private), SERVER_TYPE_LOGIN },
+ { "packet_AC_ACCEPT_LOGIN", sizeof(struct packet_AC_ACCEPT_LOGIN), SERVER_TYPE_LOGIN },
+ { "packet_AC_REFUSE_LOGIN", sizeof(struct packet_AC_REFUSE_LOGIN), SERVER_TYPE_LOGIN },
+ { "packet_AC_REFUSE_LOGIN_R2", sizeof(struct packet_AC_REFUSE_LOGIN_R2), SERVER_TYPE_LOGIN },
+ { "packet_CA_CHARSERVERCONNECT", sizeof(struct packet_CA_CHARSERVERCONNECT), SERVER_TYPE_LOGIN },
+ { "packet_CA_CONNECT_INFO_CHANGED", sizeof(struct packet_CA_CONNECT_INFO_CHANGED), SERVER_TYPE_LOGIN },
+ { "packet_CA_EXE_HASHCHECK", sizeof(struct packet_CA_EXE_HASHCHECK), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN", sizeof(struct packet_CA_LOGIN), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN2", sizeof(struct packet_CA_LOGIN2), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN3", sizeof(struct packet_CA_LOGIN3), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN4", sizeof(struct packet_CA_LOGIN4), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN_HAN", sizeof(struct packet_CA_LOGIN_HAN), SERVER_TYPE_LOGIN },
+ { "packet_CA_LOGIN_PCBANG", sizeof(struct packet_CA_LOGIN_PCBANG), SERVER_TYPE_LOGIN },
+ { "packet_CA_SSO_LOGIN_REQ", sizeof(struct packet_CA_SSO_LOGIN_REQ), SERVER_TYPE_LOGIN },
+ { "packet_SC_NOTIFY_BAN", sizeof(struct packet_SC_NOTIFY_BAN), SERVER_TYPE_LOGIN },
+ #else
+ #define LOGIN_LCLIF_P_H
+ #endif // LOGIN_LCLIF_P_H
#ifdef LOGIN_LOGIN_H
{ "Login_Config", sizeof(struct Login_Config), SERVER_TYPE_LOGIN },
{ "client_hash_node", sizeof(struct client_hash_node), SERVER_TYPE_LOGIN },
@@ -388,6 +442,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#ifdef MAP_IRC_BOT_H
{ "irc_bot_interface", sizeof(struct irc_bot_interface), SERVER_TYPE_MAP },
{ "irc_func", sizeof(struct irc_func), SERVER_TYPE_MAP },
+ { "message_flood", sizeof(struct message_flood), SERVER_TYPE_MAP },
#else
#define MAP_IRC_BOT_H
#endif // MAP_IRC_BOT_H
@@ -397,11 +452,14 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "item_combo", sizeof(struct item_combo), SERVER_TYPE_MAP },
{ "item_data", sizeof(struct item_data), SERVER_TYPE_MAP },
{ "item_group", sizeof(struct item_group), SERVER_TYPE_MAP },
+ { "item_option", sizeof(struct item_option), SERVER_TYPE_MAP },
{ "item_package", sizeof(struct item_package), SERVER_TYPE_MAP },
{ "item_package_must_entry", sizeof(struct item_package_must_entry), SERVER_TYPE_MAP },
{ "item_package_rand_entry", sizeof(struct item_package_rand_entry), SERVER_TYPE_MAP },
{ "item_package_rand_group", sizeof(struct item_package_rand_group), SERVER_TYPE_MAP },
{ "itemdb_interface", sizeof(struct itemdb_interface), SERVER_TYPE_MAP },
+ { "itemlist", sizeof(struct itemlist), SERVER_TYPE_MAP },
+ { "itemlist_entry", sizeof(struct itemlist_entry), SERVER_TYPE_MAP },
#else
#define MAP_ITEMDB_H
#endif // MAP_ITEMDB_H
@@ -485,8 +543,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#ifdef MAP_PACKETS_STRUCT_H
{ "EQUIPITEM_INFO", sizeof(struct EQUIPITEM_INFO), SERVER_TYPE_MAP },
{ "EQUIPSLOTINFO", sizeof(struct EQUIPSLOTINFO), SERVER_TYPE_MAP },
+ { "ItemOptions", sizeof(struct ItemOptions), SERVER_TYPE_MAP },
{ "NORMALITEM_INFO", sizeof(struct NORMALITEM_INFO), SERVER_TYPE_MAP },
- { "RndOptions", sizeof(struct RndOptions), SERVER_TYPE_MAP },
{ "packet_additem", sizeof(struct packet_additem), SERVER_TYPE_MAP },
{ "packet_authok", sizeof(struct packet_authok), SERVER_TYPE_MAP },
{ "packet_banking_check", sizeof(struct packet_banking_check), SERVER_TYPE_MAP },
@@ -504,6 +562,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "packet_bgqueue_revoke_req", sizeof(struct packet_bgqueue_revoke_req), SERVER_TYPE_MAP },
{ "packet_bgqueue_update_info", sizeof(struct packet_bgqueue_update_info), SERVER_TYPE_MAP },
{ "packet_cart_additem_ack", sizeof(struct packet_cart_additem_ack), SERVER_TYPE_MAP },
+ { "packet_chat_message", sizeof(struct packet_chat_message), SERVER_TYPE_MAP },
{ "packet_damage", sizeof(struct packet_damage), SERVER_TYPE_MAP },
{ "packet_dropflooritem", sizeof(struct packet_dropflooritem), SERVER_TYPE_MAP },
{ "packet_equip_item", sizeof(struct packet_equip_item), SERVER_TYPE_MAP },
@@ -546,6 +605,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "packet_unequipitem_ack", sizeof(struct packet_unequipitem_ack), SERVER_TYPE_MAP },
{ "packet_unit_walking", sizeof(struct packet_unit_walking), SERVER_TYPE_MAP },
{ "packet_viewequip_ack", sizeof(struct packet_viewequip_ack), SERVER_TYPE_MAP },
+ { "packet_whisper_message", sizeof(struct packet_whisper_message), SERVER_TYPE_MAP },
{ "packet_wis_end", sizeof(struct packet_wis_end), SERVER_TYPE_MAP },
#else
#define MAP_PACKETS_STRUCT_H
@@ -617,6 +677,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "casecheck_data", sizeof(struct casecheck_data), SERVER_TYPE_MAP },
{ "reg_db", sizeof(struct reg_db), SERVER_TYPE_MAP },
{ "script_array", sizeof(struct script_array), SERVER_TYPE_MAP },
+ { "script_buf", sizeof(struct script_buf), SERVER_TYPE_MAP },
{ "script_code", sizeof(struct script_code), SERVER_TYPE_MAP },
{ "script_data", sizeof(struct script_data), SERVER_TYPE_MAP },
{ "script_function", sizeof(struct script_function), SERVER_TYPE_MAP },
@@ -631,6 +692,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "script_syntax_data", sizeof(struct script_syntax_data), SERVER_TYPE_MAP },
{ "str_data_struct", sizeof(struct str_data_struct), SERVER_TYPE_MAP },
{ "string_translation", sizeof(struct string_translation), SERVER_TYPE_MAP },
+ { "string_translation_entry", sizeof(struct string_translation_entry), SERVER_TYPE_MAP },
#else
#define MAP_SCRIPT_H
#endif // MAP_SCRIPT_H
diff --git a/src/common/HPMSymbols.inc.h b/src/common/HPMSymbols.inc.h
index b06c43bf8..30ec45405 100644
--- a/src/common/HPMSymbols.inc.h
+++ b/src/common/HPMSymbols.inc.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2015-2016 Hercules Dev Team
+ * Copyright (C) 2013-2017 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,8 @@
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+
#if !defined(HERCULES_CORE)
#ifdef COMMON_UTILS_H /* HCache */
struct HCache_interface *HCache;
@@ -66,6 +68,9 @@ struct core_interface *core;
#ifdef COMMON_DB_H /* DB */
struct db_interface *DB;
#endif // COMMON_DB_H
+#ifdef COMMON_DES_H /* des */
+struct des_interface *des;
+#endif // COMMON_DES_H
#ifdef MAP_DUEL_H /* duel */
struct duel_interface *duel;
#endif // MAP_DUEL_H
@@ -75,6 +80,9 @@ struct elemental_interface *elemental;
#ifdef CHAR_GEOIP_H /* geoip */
struct geoip_interface *geoip;
#endif // CHAR_GEOIP_H
+#ifdef COMMON_GRFIO_H /* grfio */
+struct grfio_interface *grfio;
+#endif // COMMON_GRFIO_H
#ifdef MAP_GUILD_H /* guild */
struct guild_interface *guild;
#endif // MAP_GUILD_H
@@ -129,6 +137,9 @@ struct irc_bot_interface *ircbot;
#ifdef MAP_ITEMDB_H /* itemdb */
struct itemdb_interface *itemdb;
#endif // MAP_ITEMDB_H
+#ifdef LOGIN_LCLIF_H /* lclif */
+struct lclif_interface *lclif;
+#endif // LOGIN_LCLIF_H
#ifdef COMMON_CONF_H /* libconfig */
struct libconfig_interface *libconfig;
#endif // COMMON_CONF_H
@@ -144,9 +155,6 @@ struct loginif_interface *loginif;
#ifdef MAP_MAIL_H /* mail */
struct mail_interface *mail;
#endif // MAP_MAIL_H
-#ifdef COMMON_MEMMGR_H /* iMalloc */
-struct malloc_interface *iMalloc;
-#endif // COMMON_MEMMGR_H
#ifdef MAP_MAP_H /* map */
struct map_interface *map;
#endif // MAP_MAP_H
@@ -162,12 +170,18 @@ struct mapit_interface *mapit;
#ifdef MAP_MAPREG_H /* mapreg */
struct mapreg_interface *mapreg;
#endif // MAP_MAPREG_H
+#ifdef COMMON_MD5CALC_H /* md5 */
+struct md5_interface *md5;
+#endif // COMMON_MD5CALC_H
#ifdef MAP_MERCENARY_H /* mercenary */
struct mercenary_interface *mercenary;
#endif // MAP_MERCENARY_H
#ifdef MAP_MOB_H /* mob */
struct mob_interface *mob;
#endif // MAP_MOB_H
+#ifdef COMMON_MUTEX_H /* mutex */
+struct mutex_interface *mutex;
+#endif // COMMON_MUTEX_H
#ifdef MAP_NPC_H /* npc_chat */
struct npc_chat_interface *npc_chat;
#endif // MAP_NPC_H
@@ -201,6 +215,9 @@ struct pincode_interface *pincode;
#ifdef MAP_QUEST_H /* quest */
struct quest_interface *quest;
#endif // MAP_QUEST_H
+#ifdef COMMON_RANDOM_H /* rnd */
+struct rnd_interface *rnd;
+#endif // COMMON_RANDOM_H
#ifdef MAP_SCRIPT_H /* script */
struct script_interface *script;
#endif // MAP_SCRIPT_H
@@ -237,6 +254,9 @@ struct sv_interface *sv;
#ifdef COMMON_SYSINFO_H /* sysinfo */
struct sysinfo_interface *sysinfo;
#endif // COMMON_SYSINFO_H
+#ifdef COMMON_THREAD_H /* thread */
+struct thread_interface *thread;
+#endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H /* timer */
struct timer_interface *timer;
#endif // COMMON_TIMER_H
@@ -254,229 +274,328 @@ struct vending_interface *vending;
HPExport const char *HPM_shared_symbols(int server_type)
{
#ifdef COMMON_UTILS_H /* HCache */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("HCache", HCache)) return "HCache";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("HCache", HCache))
+ return "HCache";
#endif // COMMON_UTILS_H
#ifdef MAP_ATCOMMAND_H /* atcommand */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("atcommand", atcommand)) return "atcommand";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("atcommand", atcommand))
+ return "atcommand";
#endif // MAP_ATCOMMAND_H
#ifdef MAP_BATTLE_H /* battle */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("battle", battle)) return "battle";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("battle", battle))
+ return "battle";
#endif // MAP_BATTLE_H
#ifdef MAP_BATTLEGROUND_H /* bg */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("battlegrounds", bg)) return "battlegrounds";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("battlegrounds", bg))
+ return "battlegrounds";
#endif // MAP_BATTLEGROUND_H
#ifdef MAP_BUYINGSTORE_H /* buyingstore */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("buyingstore", buyingstore)) return "buyingstore";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("buyingstore", buyingstore))
+ return "buyingstore";
#endif // MAP_BUYINGSTORE_H
#ifdef MAP_CHANNEL_H /* channel */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("channel", channel)) return "channel";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("channel", channel))
+ return "channel";
#endif // MAP_CHANNEL_H
#ifdef CHAR_CHAR_H /* chr */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("chr", chr)) return "chr";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("chr", chr))
+ return "chr";
#endif // CHAR_CHAR_H
#ifdef MAP_CHAT_H /* chat */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("chat", chat)) return "chat";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("chat", chat))
+ return "chat";
#endif // MAP_CHAT_H
#ifdef MAP_CHRIF_H /* chrif */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("chrif", chrif)) return "chrif";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("chrif", chrif))
+ return "chrif";
#endif // MAP_CHRIF_H
#ifdef MAP_CLIF_H /* clif */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("clif", clif)) return "clif";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("clif", clif))
+ return "clif";
#endif // MAP_CLIF_H
#ifdef COMMON_CORE_H /* cmdline */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("cmdline", cmdline)) return "cmdline";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("cmdline", cmdline))
+ return "cmdline";
#endif // COMMON_CORE_H
#ifdef COMMON_CONSOLE_H /* console */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("console", console)) return "console";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("console", console))
+ return "console";
#endif // COMMON_CONSOLE_H
#ifdef COMMON_CORE_H /* core */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("core", core)) return "core";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("core", core))
+ return "core";
#endif // COMMON_CORE_H
#ifdef COMMON_DB_H /* DB */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("DB", DB)) return "DB";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("DB", DB))
+ return "DB";
#endif // COMMON_DB_H
+#ifdef COMMON_DES_H /* des */
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("des", des))
+ return "des";
+#endif // COMMON_DES_H
#ifdef MAP_DUEL_H /* duel */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("duel", duel)) return "duel";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("duel", duel))
+ return "duel";
#endif // MAP_DUEL_H
#ifdef MAP_ELEMENTAL_H /* elemental */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("elemental", elemental)) return "elemental";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("elemental", elemental))
+ return "elemental";
#endif // MAP_ELEMENTAL_H
#ifdef CHAR_GEOIP_H /* geoip */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("geoip", geoip)) return "geoip";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("geoip", geoip))
+ return "geoip";
#endif // CHAR_GEOIP_H
+#ifdef COMMON_GRFIO_H /* grfio */
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("grfio", grfio))
+ return "grfio";
+#endif // COMMON_GRFIO_H
#ifdef MAP_GUILD_H /* guild */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("guild", guild)) return "guild";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("guild", guild))
+ return "guild";
#endif // MAP_GUILD_H
#ifdef MAP_STORAGE_H /* gstorage */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("gstorage", gstorage)) return "gstorage";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("gstorage", gstorage))
+ return "gstorage";
#endif // MAP_STORAGE_H
#ifdef MAP_HOMUNCULUS_H /* homun */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("homun", homun)) return "homun";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("homun", homun))
+ return "homun";
#endif // MAP_HOMUNCULUS_H
#ifdef MAP_INSTANCE_H /* instance */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("instance", instance)) return "instance";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("instance", instance))
+ return "instance";
#endif // MAP_INSTANCE_H
#ifdef CHAR_INT_AUCTION_H /* inter_auction */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_auction", inter_auction)) return "inter_auction";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_auction", inter_auction))
+ return "inter_auction";
#endif // CHAR_INT_AUCTION_H
#ifdef CHAR_INT_ELEMENTAL_H /* inter_elemental */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_elemental", inter_elemental)) return "inter_elemental";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_elemental", inter_elemental))
+ return "inter_elemental";
#endif // CHAR_INT_ELEMENTAL_H
#ifdef CHAR_INT_GUILD_H /* inter_guild */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_guild", inter_guild)) return "inter_guild";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_guild", inter_guild))
+ return "inter_guild";
#endif // CHAR_INT_GUILD_H
#ifdef CHAR_INT_HOMUN_H /* inter_homunculus */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_homunculus", inter_homunculus)) return "inter_homunculus";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_homunculus", inter_homunculus))
+ return "inter_homunculus";
#endif // CHAR_INT_HOMUN_H
#ifdef CHAR_INTER_H /* inter */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter", inter)) return "inter";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter", inter))
+ return "inter";
#endif // CHAR_INTER_H
#ifdef CHAR_INT_MAIL_H /* inter_mail */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_mail", inter_mail)) return "inter_mail";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_mail", inter_mail))
+ return "inter_mail";
#endif // CHAR_INT_MAIL_H
#ifdef CHAR_INT_MERCENARY_H /* inter_mercenary */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_mercenary", inter_mercenary)) return "inter_mercenary";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_mercenary", inter_mercenary))
+ return "inter_mercenary";
#endif // CHAR_INT_MERCENARY_H
#ifdef CHAR_INT_PARTY_H /* inter_party */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_party", inter_party)) return "inter_party";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_party", inter_party))
+ return "inter_party";
#endif // CHAR_INT_PARTY_H
#ifdef CHAR_INT_PET_H /* inter_pet */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_pet", inter_pet)) return "inter_pet";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_pet", inter_pet))
+ return "inter_pet";
#endif // CHAR_INT_PET_H
#ifdef CHAR_INT_QUEST_H /* inter_quest */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_quest", inter_quest)) return "inter_quest";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_quest", inter_quest))
+ return "inter_quest";
#endif // CHAR_INT_QUEST_H
#ifdef CHAR_INT_STORAGE_H /* inter_storage */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("inter_storage", inter_storage)) return "inter_storage";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_storage", inter_storage))
+ return "inter_storage";
#endif // CHAR_INT_STORAGE_H
#ifdef MAP_INTIF_H /* intif */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("intif", intif)) return "intif";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("intif", intif))
+ return "intif";
#endif // MAP_INTIF_H
#ifdef MAP_IRC_BOT_H /* ircbot */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("ircbot", ircbot)) return "ircbot";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("ircbot", ircbot))
+ return "ircbot";
#endif // MAP_IRC_BOT_H
#ifdef MAP_ITEMDB_H /* itemdb */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("itemdb", itemdb)) return "itemdb";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("itemdb", itemdb))
+ return "itemdb";
#endif // MAP_ITEMDB_H
+#ifdef LOGIN_LCLIF_H /* lclif */
+ if ((server_type&(SERVER_TYPE_LOGIN)) != 0 && !HPM_SYMBOL("lclif", lclif))
+ return "lclif";
+#endif // LOGIN_LCLIF_H
#ifdef COMMON_CONF_H /* libconfig */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("libconfig", libconfig)) return "libconfig";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("libconfig", libconfig))
+ return "libconfig";
#endif // COMMON_CONF_H
#ifdef MAP_LOG_H /* logs */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("logs", logs)) return "logs";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("logs", logs))
+ return "logs";
#endif // MAP_LOG_H
#ifdef LOGIN_LOGIN_H /* login */
-if ((server_type&(SERVER_TYPE_LOGIN)) && !HPM_SYMBOL("login", login)) return "login";
+ if ((server_type&(SERVER_TYPE_LOGIN)) != 0 && !HPM_SYMBOL("login", login))
+ return "login";
#endif // LOGIN_LOGIN_H
#ifdef CHAR_LOGINIF_H /* loginif */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("loginif", loginif)) return "loginif";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("loginif", loginif))
+ return "loginif";
#endif // CHAR_LOGINIF_H
#ifdef MAP_MAIL_H /* mail */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mail", mail)) return "mail";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("mail", mail))
+ return "mail";
#endif // MAP_MAIL_H
-#ifdef COMMON_MEMMGR_H /* iMalloc */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("iMalloc", iMalloc)) return "iMalloc";
-#endif // COMMON_MEMMGR_H
#ifdef MAP_MAP_H /* map */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("map", map)) return "map";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("map", map))
+ return "map";
#endif // MAP_MAP_H
#ifdef CHAR_MAPIF_H /* mapif */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("mapif", mapif)) return "mapif";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("mapif", mapif))
+ return "mapif";
#endif // CHAR_MAPIF_H
#ifdef COMMON_MAPINDEX_H /* mapindex */
-if ((server_type&(SERVER_TYPE_MAP|SERVER_TYPE_CHAR)) && !HPM_SYMBOL("mapindex", mapindex)) return "mapindex";
+ if ((server_type&(SERVER_TYPE_MAP|SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("mapindex", mapindex))
+ return "mapindex";
#endif // COMMON_MAPINDEX_H
#ifdef MAP_MAP_H /* mapit */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mapit", mapit)) return "mapit";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("mapit", mapit))
+ return "mapit";
#endif // MAP_MAP_H
#ifdef MAP_MAPREG_H /* mapreg */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mapreg", mapreg)) return "mapreg";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("mapreg", mapreg))
+ return "mapreg";
#endif // MAP_MAPREG_H
+#ifdef COMMON_MD5CALC_H /* md5 */
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("md5", md5))
+ return "md5";
+#endif // COMMON_MD5CALC_H
#ifdef MAP_MERCENARY_H /* mercenary */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mercenary", mercenary)) return "mercenary";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("mercenary", mercenary))
+ return "mercenary";
#endif // MAP_MERCENARY_H
#ifdef MAP_MOB_H /* mob */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mob", mob)) return "mob";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("mob", mob))
+ return "mob";
#endif // MAP_MOB_H
+#ifdef COMMON_MUTEX_H /* mutex */
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("mutex", mutex))
+ return "mutex";
+#endif // COMMON_MUTEX_H
#ifdef MAP_NPC_H /* npc_chat */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("npc_chat", npc_chat)) return "npc_chat";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("npc_chat", npc_chat))
+ return "npc_chat";
#endif // MAP_NPC_H
#ifdef MAP_NPC_H /* npc */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("npc", npc)) return "npc";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("npc", npc))
+ return "npc";
#endif // MAP_NPC_H
#ifdef COMMON_NULLPO_H /* nullpo */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("nullpo", nullpo)) return "nullpo";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("nullpo", nullpo))
+ return "nullpo";
#endif // COMMON_NULLPO_H
#ifdef MAP_PARTY_H /* party */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("party", party)) return "party";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("party", party))
+ return "party";
#endif // MAP_PARTY_H
#ifdef MAP_PATH_H /* path */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("path", path)) return "path";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("path", path))
+ return "path";
#endif // MAP_PATH_H
#ifdef MAP_PC_GROUPS_H /* pcg */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("pc_groups", pcg)) return "pc_groups";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("pc_groups", pcg))
+ return "pc_groups";
#endif // MAP_PC_GROUPS_H
#ifdef MAP_PC_H /* pc */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("pc", pc)) return "pc";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("pc", pc))
+ return "pc";
#endif // MAP_PC_H
#ifdef MAP_NPC_H /* libpcre */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("libpcre", libpcre)) return "libpcre";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("libpcre", libpcre))
+ return "libpcre";
#endif // MAP_NPC_H
#ifdef MAP_PET_H /* pet */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("pet", pet)) return "pet";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("pet", pet))
+ return "pet";
#endif // MAP_PET_H
#ifdef CHAR_PINCODE_H /* pincode */
-if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("pincode", pincode)) return "pincode";
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("pincode", pincode))
+ return "pincode";
#endif // CHAR_PINCODE_H
#ifdef MAP_QUEST_H /* quest */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("quest", quest)) return "quest";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("quest", quest))
+ return "quest";
#endif // MAP_QUEST_H
+#ifdef COMMON_RANDOM_H /* rnd */
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("rnd", rnd))
+ return "rnd";
+#endif // COMMON_RANDOM_H
#ifdef MAP_SCRIPT_H /* script */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("script", script)) return "script";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("script", script))
+ return "script";
#endif // MAP_SCRIPT_H
#ifdef MAP_SEARCHSTORE_H /* searchstore */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("searchstore", searchstore)) return "searchstore";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("searchstore", searchstore))
+ return "searchstore";
#endif // MAP_SEARCHSTORE_H
#ifdef COMMON_SHOWMSG_H /* showmsg */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("showmsg", showmsg)) return "showmsg";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("showmsg", showmsg))
+ return "showmsg";
#endif // COMMON_SHOWMSG_H
#ifdef MAP_SKILL_H /* skill */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("skill", skill)) return "skill";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("skill", skill))
+ return "skill";
#endif // MAP_SKILL_H
#ifdef COMMON_SOCKET_H /* sockt */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("sockt", sockt)) return "sockt";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("sockt", sockt))
+ return "sockt";
#endif // COMMON_SOCKET_H
#ifdef COMMON_SQL_H /* SQL */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("SQL", SQL)) return "SQL";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("SQL", SQL))
+ return "SQL";
#endif // COMMON_SQL_H
#ifdef MAP_STATUS_H /* status */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("status", status)) return "status";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("status", status))
+ return "status";
#endif // MAP_STATUS_H
#ifdef MAP_STORAGE_H /* storage */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("storage", storage)) return "storage";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("storage", storage))
+ return "storage";
#endif // MAP_STORAGE_H
#ifdef COMMON_STRLIB_H /* StrBuf */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("StrBuf", StrBuf)) return "StrBuf";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("StrBuf", StrBuf))
+ return "StrBuf";
#endif // COMMON_STRLIB_H
#ifdef COMMON_STRLIB_H /* strlib */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("strlib", strlib)) return "strlib";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("strlib", strlib))
+ return "strlib";
#endif // COMMON_STRLIB_H
#ifdef COMMON_STRLIB_H /* sv */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("sv", sv)) return "sv";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("sv", sv))
+ return "sv";
#endif // COMMON_STRLIB_H
#ifdef COMMON_SYSINFO_H /* sysinfo */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("sysinfo", sysinfo)) return "sysinfo";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("sysinfo", sysinfo))
+ return "sysinfo";
#endif // COMMON_SYSINFO_H
+#ifdef COMMON_THREAD_H /* thread */
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("thread", thread))
+ return "thread";
+#endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H /* timer */
-if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("timer", timer)) return "timer";
+ if ((server_type&(SERVER_TYPE_ALL)) != 0 && !HPM_SYMBOL("timer", timer))
+ return "timer";
#endif // COMMON_TIMER_H
#ifdef MAP_TRADE_H /* trade */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("trade", trade)) return "trade";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("trade", trade))
+ return "trade";
#endif // MAP_TRADE_H
#ifdef MAP_UNIT_H /* unit */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("unit", unit)) return "unit";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("unit", unit))
+ return "unit";
#endif // MAP_UNIT_H
#ifdef MAP_VENDING_H /* vending */
-if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("vending", vending)) return "vending";
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("vending", vending))
+ return "vending";
#endif // MAP_VENDING_H
return NULL;
}
diff --git a/src/common/HPMi.h b/src/common/HPMi.h
index cf3e16277..143c325c1 100644
--- a/src/common/HPMi.h
+++ b/src/common/HPMi.h
@@ -24,15 +24,16 @@
#include "common/console.h"
#include "common/core.h"
#include "common/showmsg.h"
-#include "common/sql.h"
+struct HPMHooking_interface;
+struct Sql; // common/sql.h
struct script_state;
struct AtCommandInfo;
struct socket_data;
struct map_session_data;
struct hplugin_data_store;
-#define HPM_VERSION "1.1"
+#define HPM_VERSION "1.2"
#define HPM_ADDCONF_LENGTH 40
struct hplugin_info {
@@ -71,11 +72,6 @@ enum HPluginPacketHookingPoints {
hpPHP_MAX,
};
-enum HPluginHookType {
- HOOK_TYPE_PRE,
- HOOK_TYPE_POST,
-};
-
/**
* Data types for plugin custom data.
*/
@@ -107,13 +103,6 @@ enum HPluginConfType {
HPCT_MAX,
};
-#define addHookPre(tname,hook) (HPMi->AddHook(HOOK_TYPE_PRE,(tname),(hook),HPMi->pid))
-#define addHookPost(tname,hook) (HPMi->AddHook(HOOK_TYPE_POST,(tname),(hook),HPMi->pid))
-/* need better names ;/ */
-/* will not run the original function after pre-hook processing is complete (other hooks will run) */
-#define hookStop() (HPMi->HookStop(__func__,HPMi->pid))
-#define hookStopped() (HPMi->HookStopped())
-
#define addArg(name, param,func,help) (HPMi->addArg(HPMi->pid,(name),(param),(cmdline_arg_ ## func),(help)))
/* HPData handy redirects */
/* session[] */
@@ -199,19 +188,19 @@ enum HPluginConfType {
/* HPMi->addPacket */
#define addPacket(cmd,len,receive,point) HPMi->addPacket(cmd,len,receive,point,HPMi->pid)
/* HPMi->addBattleConf */
-#define addBattleConf(bcname,funcname,returnfunc) HPMi->addConf(HPMi->pid,HPCT_BATTLE,bcname,funcname,returnfunc)
+#define addBattleConf(bcname, funcname, returnfunc, required) HPMi->addConf(HPMi->pid, HPCT_BATTLE, bcname, funcname, returnfunc, required)
/* HPMi->addLogin */
-#define addLoginConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_LOGIN,bcname,funcname,NULL)
+#define addLoginConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_LOGIN, bcname, funcname, NULL, false)
/* HPMi->addChar */
-#define addCharConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_CHAR,bcname,funcname,NULL)
+#define addCharConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_CHAR, bcname, funcname, NULL, false)
/* HPMi->addCharInter */
-#define addCharInterConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_CHAR_INTER,bcname,funcname,NULL)
+#define addCharInterConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_CHAR_INTER, bcname, funcname, NULL, false)
/* HPMi->addMapInter */
-#define addMapInterConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_MAP_INTER,bcname,funcname,NULL)
+#define addMapInterConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_MAP_INTER, bcname, funcname, NULL, false)
/* HPMi->addLog */
-#define addLogConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_LOG,bcname,funcname,NULL)
+#define addLogConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_LOG, bcname, funcname, NULL, false)
/* HPMi->addScript */
-#define addScriptConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_SCRIPT,bcname,funcname,NULL)
+#define addScriptConf(bcname, funcname) HPMi->addConf(HPMi->pid, HPCT_SCRIPT, bcname, funcname, NULL, false)
/* HPMi->addPCGPermission */
#define addGroupPermission(pcgname,maskptr) HPMi->addPCGPermission(HPMi->pid,pcgname,&maskptr)
@@ -231,18 +220,18 @@ struct HPMi_interface {
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 */
- bool (*AddHook) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
- void (*HookStop) (const char *func, unsigned int pID);
- bool (*HookStopped) (void);
/* program --arg/-a */
bool (*addArg) (unsigned int pluginID, char *name, bool has_param, CmdlineExecFunc func, const char *help);
/* battle-config recv param */
- bool (*addConf) (unsigned int pluginID, enum HPluginConfType type, char *name, void (*parse_func) (const char *key, const char *val), int (*return_func) (const char *key));
+ bool (*addConf) (unsigned int pluginID, enum HPluginConfType type, char *name, void (*parse_func) (const char *key, const char *val), int (*return_func) (const char *key), bool required);
/* pc group permission */
void (*addPCGPermission) (unsigned int pluginID, char *name, unsigned int *mask);
- Sql *sql_handle;
+ struct Sql *sql_handle;
+
+ /* Hooking */
+ struct HPMHooking_interface *hooking;
+ struct malloc_interface *memmgr;
};
#ifdef HERCULES_CORE
#define HPM_SYMBOL(n, s) (HPM->share((s), (n)), true)
diff --git a/src/common/Makefile.in b/src/common/Makefile.in
index 9d4b2d044..6e7ffa088 100644
--- a/src/common/Makefile.in
+++ b/src/common/Makefile.in
@@ -1,7 +1,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2012-2015 Hercules Dev Team
+# Copyright (C) 2012-2016 Hercules Dev Team
# Copyright (C) Athena Dev Teams
#
# Hercules is free software: you can redistribute it and/or modify
@@ -50,7 +50,9 @@ COMMON_C += console.c core.c memmgr.c socket.c
COMMON_H = atomic.h cbasetypes.h conf.h console.h core.h db.h des.h ers.h \
grfio.h hercules.h HPM.h HPMi.h memmgr.h mapindex.h md5calc.h \
mmo.h mutex.h nullpo.h random.h showmsg.h socket.h spinlock.h \
- sql.h strlib.h sysinfo.h thread.h timer.h utils.h winapi.h
+ sql.h strlib.h sysinfo.h thread.h timer.h utils.h winapi.h \
+ ../plugins/HPMHooking.h
+COMMON_PH =
COMMON_SQL_OBJ = obj_sql/sql.o
COMMON_SQL_H = sql.h
@@ -95,7 +97,7 @@ help:
Makefile: Makefile.in
@$(MAKE) -C ../.. src/common/Makefile
-$(SYSINFO_INC): $(COMMON_C) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H)
+$(SYSINFO_INC): $(COMMON_C) $(COMMON_PH) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H)
@echo " MAKE $@"
@$(MAKE) -C ../.. sysinfo
@@ -131,25 +133,27 @@ common_mini: $(COMMON_MINI_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) obj_all/common
common_sql: $(COMMON_SQL_OBJ) obj_sql/common_sql.a Makefile
-obj_all/sysinfo.o: sysinfo.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(SYSINFO_INC) | obj_all
+# missing object files
+$(MT19937AR_OBJ):
+ @echo " MAKE $@"
+ @$(MAKE) -C $(MT19937AR_D)
+
+$(LIBCONFIG_OBJ):
+ @echo " MAKE $@"
+ @$(MAKE) -C $(LIBCONFIG_D)
+
+.SECONDEXPANSION:
+
+obj_all/sysinfo.o: sysinfo.c $(filter sysinfo.p.h, $(COMMON_PH)) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(SYSINFO_INC) | obj_all
obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all
@echo " CC $<"
@$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
-obj_all/mini%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all
+obj_all/mini%.o: %.c $$(filter %.p.h, $(COMMON_PH)) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all
@echo " CC $<"
@$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) -DMINICORE @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
-obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_sql
+obj_sql/%.o: %.c $$(filter %.p.h, $(COMMON_PH)) $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_sql
@echo " CC $<"
@$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
-
-# missing object files
-$(MT19937AR_OBJ):
- @echo " MAKE $@"
- @$(MAKE) -C $(MT19937AR_D)
-
-$(LIBCONFIG_OBJ):
- @echo " MAKE $@"
- @$(MAKE) -C $(LIBCONFIG_D)
diff --git a/src/common/atomic.h b/src/common/atomic.h
index 82d579bf4..b370052a9 100644
--- a/src/common/atomic.h
+++ b/src/common/atomic.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h
index 61d0646eb..2c36c23bc 100644
--- a/src/common/cbasetypes.h
+++ b/src/common/cbasetypes.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -94,7 +94,7 @@
// debug function name
#ifndef __NETBSD__
-#if __STDC_VERSION__ < 199901L
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
# define __func__ __FUNCTION__
# else
@@ -109,6 +109,14 @@
# define __attribute__(x)
#endif
+/// Feature/extension checking macros
+#ifndef __has_extension /* Available in clang and gcc >= 3 */
+#define __has_extension(x) 0
+#endif
+#ifndef __has_feature /* Available in clang and gcc >= 5 */
+#define __has_feature(x) __has_extension(x)
+#endif
+
//////////////////////////////////////////////////////////////////////////
// portable printf/scanf format macros and integer definitions
// NOTE: Visual C++ uses <inttypes.h> and <stdint.h> provided in /3rdparty
@@ -118,16 +126,6 @@
#include <limits.h>
#include <time.h>
-// temporary fix for bugreport:4961 (unintended conversion from signed to unsigned)
-// (-20 >= UCHAR_MAX) returns true
-// (-20 >= USHRT_MAX) returns true
-#if defined(__FreeBSD__) && defined(__x86_64)
-#undef UCHAR_MAX
-#define UCHAR_MAX ((unsigned char)0xff)
-#undef USHRT_MAX
-#define USHRT_MAX ((unsigned short)0xffff)
-#endif
-
// ILP64 isn't supported, so always 32 bits?
#ifndef UINT_MAX
#define UINT_MAX 0xffffffff
@@ -262,16 +260,13 @@ typedef uintptr_t uintptr;
#if defined(__BORLANDC__) || _MSC_VER < 1900
#define snprintf _snprintf
#endif
-#if defined(_MSC_VER) && _MSC_VER < 1400
-#define vsnprintf _vsnprintf
-#endif
#else
#define strcmpi strcasecmp
#define stricmp strcasecmp
#define strncmpi strncasecmp
#define strnicmp strncasecmp
#endif
-#if defined(_MSC_VER) && _MSC_VER > 1200
+#if defined(_MSC_VER)
#define strtoull _strtoui64
#define strtoll _strtoi64
#endif
@@ -295,6 +290,28 @@ typedef uintptr_t uintptr;
#define analyzer_noreturn
#endif
+// gcc version (if any) - borrowed from Mana Plus
+#ifdef __GNUC__
+#define GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+#else
+#define GCC_VERSION 0
+#endif
+
+// Pragma macro only enabled on gcc >= 4.6 or clang - borrowed from Mana Plus
+#if defined(__GNUC__) && (defined(__clang__) || GCC_VERSION >= 40600)
+#define PRAGMA_GCC46(str) _Pragma(#str)
+#else // ! defined(__GNUC__) && (defined(__clang__) || GCC_VERSION >= 40600)
+#define PRAGMA_GCC46(str)
+#endif // ! defined(__GNUC__) && (defined(__clang__) || GCC_VERSION >= 40600)
+
+// fallthrough attribute only enabled on gcc >= 7.0
+#if defined(__GNUC__) && (GCC_VERSION >= 70000)
+#define FALLTHROUGH __attribute__ ((fallthrough));
+#else // ! defined(__GNUC__) && (GCC_VERSION >= 70000)
+#define FALLTHROUGH
+#endif // ! defined(__GNUC__) && (GCC_VERSION >= 70000)
// boolean types for C
#if !defined(_MSC_VER) || _MSC_VER >= 1800
@@ -327,24 +344,6 @@ typedef char bool;
//#define swap(a,b) if (a != b) ((a ^= b), (b ^= a), (a ^= b))
// but is vulnerable to 'if (foo) swap(bar, baz); else quux();', causing the else to nest incorrectly.
#define swap(a,b) do { if ((a) != (b)) { (a) ^= (b); (b) ^= (a); (a) ^= (b); } } while(0)
-#if 0 //to be activated soon, more tests needed on how VS works with the macro above
-#ifdef WIN32
-#undef swap
-#define swap(a,b)__asm { \
- __asm mov eax, dword ptr [a] \
- __asm cmp eax, dword ptr [b] \
- __asm je _ret \
- __asm xor eax, dword ptr [b] \
- __asm mov dword ptr [a], eax \
- __asm xor eax, dword ptr [b] \
- __asm mov dword ptr [b], eax \
- __asm xor eax, dword ptr [a] \
- __asm mov dword ptr [a], eax \
- __asm _ret: \
-}
-#endif
-#endif
-
#define swap_ptr(a,b) do { if ((a) != (b)) (a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); (b) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); (a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); } while(0)
#ifndef max
@@ -450,4 +449,23 @@ typedef char bool;
/** Support macros for marking structs as unavailable */
#define UNAVAILABLE_STRUCT int8 HERC__unavailable_struct
+/** Static assertion (only on compilers that support it) */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+// C11 version
+#define STATIC_ASSERT(ex, msg) _Static_assert(ex, msg)
+#elif __has_feature(c_static_assert)
+// Clang support (as per http://clang.llvm.org/docs/LanguageExtensions.html)
+#define STATIC_ASSERT(ex, msg) _Static_assert(ex, msg)
+#elif defined(__GNUC__) && GCC_VERSION >= 40700
+// GCC >= 4.7 is known to support it
+#define STATIC_ASSERT(ex, msg) _Static_assert(ex, msg)
+#elif defined(_MSC_VER)
+// MSVC doesn't support it, but it accepts the C++ style version
+#define STATIC_ASSERT(ex, msg) static_assert(ex, msg)
+#else
+// Otherise just ignore it until it's supported
+#define STATIC_ASSERT(ex, msg)
+#endif
+
+
#endif /* COMMON_CBASETYPES_H */
diff --git a/src/common/conf.c b/src/common/conf.c
index 3e8c08963..96b9bff9f 100644
--- a/src/common/conf.c
+++ b/src/common/conf.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,6 +23,8 @@
#include "conf.h"
#include "common/showmsg.h" // ShowError
+#include "common/strlib.h" // safestrncpy
+#include "common/utils.h" // exists
#include <libconfig/libconfig.h>
@@ -30,26 +32,43 @@
struct libconfig_interface libconfig_s;
struct libconfig_interface *libconfig;
-int conf_read_file(config_t *config, const char *config_filename) {
+/**
+ * Initializes 'config' and loads a configuration file.
+ *
+ * Shows error and destroys 'config' in case of failure.
+ * It is the caller's care to destroy 'config' in case of success.
+ *
+ * @param config The config file to initialize.
+ * @param config_filename The file to read.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_load_file(struct config_t *config, const char *config_filename)
+{
libconfig->init(config);
- if (!libconfig->read_file_src(config, config_filename)) {
+ if (!exists(config_filename)) {
+ ShowError("Unable to load '%s' - File not found\n", config_filename);
+ return CONFIG_FALSE;
+ }
+ if (libconfig->read_file_src(config, config_filename) != CONFIG_TRUE) {
ShowError("%s:%d - %s\n", config_error_file(config),
config_error_line(config), config_error_text(config));
libconfig->destroy(config);
- return 1;
+ return CONFIG_FALSE;
}
- return 0;
+ return CONFIG_TRUE;
}
//
// Functions to copy settings from libconfig/contrib
//
-void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src) {
+void config_setting_copy_simple(struct config_setting_t *parent, const struct config_setting_t *src)
+{
if (config_setting_is_aggregate(src)) {
libconfig->setting_copy_aggregate(parent, src);
- }
- else {
- config_setting_t *set;
+ } else {
+ struct config_setting_t *set;
if( libconfig->setting_get_member(parent, config_setting_name(src)) != NULL )
return;
@@ -73,8 +92,9 @@ void config_setting_copy_simple(config_setting_t *parent, const config_setting_t
}
}
-void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src) {
- config_setting_t *set = NULL;
+void config_setting_copy_elem(struct config_setting_t *parent, const struct config_setting_t *src)
+{
+ struct config_setting_t *set = NULL;
if (config_setting_is_aggregate(src))
libconfig->setting_copy_aggregate(parent, src);
@@ -93,8 +113,9 @@ void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *
}
}
-void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src) {
- config_setting_t *newAgg;
+void config_setting_copy_aggregate(struct config_setting_t *parent, const struct config_setting_t *src)
+{
+ struct config_setting_t *newAgg;
int i, n;
if( libconfig->setting_get_member(parent, config_setting_name(src)) != NULL )
@@ -116,7 +137,8 @@ void config_setting_copy_aggregate(config_setting_t *parent, const config_settin
}
}
-int config_setting_copy(config_setting_t *parent, const config_setting_t *src) {
+int config_setting_copy(struct config_setting_t *parent, const struct config_setting_t *src)
+{
if (!config_setting_is_group(parent) && !config_setting_is_list(parent))
return CONFIG_FALSE;
@@ -128,14 +150,311 @@ int config_setting_copy(config_setting_t *parent, const config_setting_t *src) {
return CONFIG_TRUE;
}
+/**
+ * Converts the value of a setting that is type CONFIG_TYPE_BOOL to bool.
+ *
+ * @param setting The setting to read.
+ *
+ * @return The converted value.
+ * @retval false in case of failure.
+ */
+bool config_setting_get_bool_real(const struct config_setting_t *setting)
+{
+ if (setting == NULL || setting->type != CONFIG_TYPE_BOOL)
+ return false;
+
+ return setting->value.ival ? true : false;
+}
+
+/**
+ * Same as config_setting_lookup_bool, but uses bool instead of int.
+ *
+ * @param[in] setting The setting to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] value The output value.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_setting_lookup_bool_real(const struct config_setting_t *setting, const char *name, bool *value)
+{
+ struct config_setting_t *member = config_setting_get_member(setting, name);
+
+ if (!member)
+ return CONFIG_FALSE;
+
+ if (config_setting_type(member) != CONFIG_TYPE_BOOL)
+ return CONFIG_FALSE;
+
+ *value = config_setting_get_bool_real(member);
+
+ return CONFIG_TRUE;
+}
+
+/**
+ * Converts and returns a configuration that is CONFIG_TYPE_INT to unsigned int (uint32).
+ *
+ * @param setting The setting to read.
+ *
+ * @return The converted value.
+ * @retval 0 in case of failure.
+ */
+uint32 config_setting_get_uint32(const struct config_setting_t *setting)
+{
+ if (setting == NULL || setting->type != CONFIG_TYPE_INT)
+ return 0;
+
+ if (setting->value.ival < 0)
+ return 0;
+
+ return (uint32)setting->value.ival;
+}
+
+/**
+ * Looks up a configuration entry of type CONFIG_TYPE_INT and reads it as uint32.
+ *
+ * @param[in] setting The setting to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] value The output value.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_setting_lookup_uint32(const struct config_setting_t *setting, const char *name, uint32 *value)
+{
+ struct config_setting_t *member = config_setting_get_member(setting, name);
+
+ if (!member)
+ return CONFIG_FALSE;
+
+ if (config_setting_type(member) != CONFIG_TYPE_INT)
+ return CONFIG_FALSE;
+
+ *value = config_setting_get_uint32(member);
+
+ return CONFIG_TRUE;
+}
+
+/**
+ * Converts and returns a configuration that is CONFIG_TYPE_INT to uint16
+ *
+ * @param setting The setting to read.
+ *
+ * @return The converted value.
+ * @retval 0 in case of failure.
+ */
+uint16 config_setting_get_uint16(const struct config_setting_t *setting)
+{
+ if (setting == NULL || setting->type != CONFIG_TYPE_INT)
+ return 0;
+
+ if (setting->value.ival > UINT16_MAX)
+ return UINT16_MAX;
+ if (setting->value.ival < UINT16_MIN)
+ return UINT16_MIN;
+
+ return (uint16)setting->value.ival;
+}
+
+/**
+ * Looks up a configuration entry of type CONFIG_TYPE_INT and reads it as uint16.
+ *
+ * @param[in] setting The setting to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] value The output value.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_setting_lookup_uint16(const struct config_setting_t *setting, const char *name, uint16 *value)
+{
+ struct config_setting_t *member = config_setting_get_member(setting, name);
+
+ if (!member)
+ return CONFIG_FALSE;
+
+ if (config_setting_type(member) != CONFIG_TYPE_INT)
+ return CONFIG_FALSE;
+
+ *value = config_setting_get_uint16(member);
+
+ return CONFIG_TRUE;
+}
+
+/**
+ * Converts and returns a configuration that is CONFIG_TYPE_INT to int16
+ *
+ * @param setting The setting to read.
+ *
+ * @return The converted value.
+ * @retval 0 in case of failure.
+ */
+int16 config_setting_get_int16(const struct config_setting_t *setting)
+{
+ if (setting == NULL || setting->type != CONFIG_TYPE_INT)
+ return 0;
+
+ if (setting->value.ival > INT16_MAX)
+ return INT16_MAX;
+ if (setting->value.ival < INT16_MIN)
+ return INT16_MIN;
+
+ return (int16)setting->value.ival;
+}
+
+/**
+ * Looks up a configuration entry of type CONFIG_TYPE_INT and reads it as int16.
+ *
+ * @param[in] setting The setting to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] value The output value.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_setting_lookup_int16(const struct config_setting_t *setting, const char *name, int16 *value)
+{
+ struct config_setting_t *member = config_setting_get_member(setting, name);
+
+ if (!member)
+ return CONFIG_FALSE;
+
+ if (config_setting_type(member) != CONFIG_TYPE_INT)
+ return CONFIG_FALSE;
+
+ *value = config_setting_get_int16(member);
+
+ return CONFIG_TRUE;
+}
+
+/**
+ * Looks up a configuration entry of type CONFIG_TYPE_STRING inside a struct config_setting_t and copies it into a (non-const) char buffer.
+ *
+ * @param[in] setting The setting to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] out The output buffer.
+ * @param[in] out_size The size of the output buffer.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_setting_lookup_mutable_string(const struct config_setting_t *setting, const char *name, char *out, size_t out_size)
+{
+ const char *str = NULL;
+
+ if (libconfig->setting_lookup_string(setting, name, &str) == CONFIG_TRUE) {
+ safestrncpy(out, str, out_size);
+ return CONFIG_TRUE;
+ }
+
+ return CONFIG_FALSE;
+}
+
+/**
+ * Looks up a configuration entry of type CONFIG_TYPE_STRING inside a struct config_t and copies it into a (non-const) char buffer.
+ *
+ * @param[in] config The configuration to read.
+ * @param[in] name The setting name to lookup.
+ * @param[out] out The output buffer.
+ * @param[in] out_size The size of the output buffer.
+ *
+ * @retval CONFIG_TRUE in case of success.
+ * @retval CONFIG_FALSE in case of failure.
+ */
+int config_lookup_mutable_string(const struct config_t *config, const char *name, char *out, size_t out_size)
+{
+ const char *str = NULL;
+
+ if (libconfig->lookup_string(config, name, &str) == CONFIG_TRUE) {
+ safestrncpy(out, str, out_size);
+ return CONFIG_TRUE;
+ }
+
+ return CONFIG_FALSE;
+}
+
+/**
+ * Wrapper for config_setting_get_int64() using defined-size variables
+ *
+ * @see config_setting_get_int64_real()
+ */
+int64 config_setting_get_int64_real(const struct config_setting_t *setting)
+{
+ return (int64)config_setting_get_int64(setting);
+}
+
+/**
+ * Wrapper for config_setting_lookup_int64() using defined-size variables
+ *
+ * @see config_setting_lookup_int64()
+ */
+int config_setting_lookup_int64_real(const struct config_setting_t *setting, const char *name, int64 *value)
+{
+ long long int lli = 0;
+
+ if (config_setting_lookup_int64(setting, name, &lli) != CONFIG_TRUE)
+ return CONFIG_FALSE;
+
+ *value = (int64)lli;
+
+ return CONFIG_TRUE;
+}
+
+/**
+ * Wrapper for config_setting_set_int64() using defined-size variables
+ *
+ * @see config_setting_set_int64()
+ */
+int config_setting_set_int64_real(struct config_setting_t *setting, int64 value)
+{
+ return config_setting_set_int64(setting, (long long int)value);
+}
+
+/**
+ * Wrapper for config_setting_get_int64_elem() using defined-size variables
+ *
+ * @see config_setting_get_int64_elem()
+ */
+int64 config_setting_get_int64_elem_real(const struct config_setting_t *setting, int idx)
+{
+ return (int64)config_setting_get_int64_elem(setting, idx);
+}
+
+/**
+ * Wrapper for config_setting_set_int64_elem() using defined-size variables
+ *
+ * @see config_setting_set_int64_elem()
+ */
+struct config_setting_t *config_setting_set_int64_elem_real(struct config_setting_t *setting, int idx, int64 value)
+{
+ return config_setting_set_int64_elem(setting, idx, (long long int)value);
+}
+
+/**
+ * Wrapper for config_lookup_int64() using defined-size variables
+ *
+ * @see config_lookup_int64()
+ */
+int config_lookup_int64_real(const struct config_t *config, const char *filepath, int64 *value)
+{
+ long long int lli = 0;
+
+ if (config_lookup_int64(config, filepath, &lli) != CONFIG_TRUE)
+ return CONFIG_FALSE;
+
+ *value = (int64)lli;
+
+ return CONFIG_TRUE;
+}
+
void libconfig_defaults(void) {
libconfig = &libconfig_s;
libconfig->read = config_read;
libconfig->write = config_write;
/* */
- libconfig->set_auto_convert = config_set_auto_convert;
- libconfig->get_auto_convert = config_get_auto_convert;
+ libconfig->set_options = config_set_options;
+ libconfig->get_options = config_get_options;
/* */
libconfig->read_string = config_read_string;
libconfig->read_file_src = config_read_file;
@@ -148,19 +467,20 @@ void libconfig_defaults(void) {
libconfig->destroy = config_destroy;
/* */
libconfig->setting_get_int = config_setting_get_int;
- libconfig->setting_get_int64 = config_setting_get_int64;
+ libconfig->setting_get_int64 = config_setting_get_int64_real;
libconfig->setting_get_float = config_setting_get_float;
libconfig->setting_get_bool = config_setting_get_bool;
libconfig->setting_get_string = config_setting_get_string;
/* */
+ libconfig->setting_lookup = config_setting_lookup;
libconfig->setting_lookup_int = config_setting_lookup_int;
- libconfig->setting_lookup_int64 = config_setting_lookup_int64;
+ libconfig->setting_lookup_int64 = config_setting_lookup_int64_real;
libconfig->setting_lookup_float = config_setting_lookup_float;
libconfig->setting_lookup_bool = config_setting_lookup_bool;
libconfig->setting_lookup_string = config_setting_lookup_string;
/* */
libconfig->setting_set_int = config_setting_set_int;
- libconfig->setting_set_int64 = config_setting_set_int64;
+ libconfig->setting_set_int64 = config_setting_set_int64_real;
libconfig->setting_set_float = config_setting_set_float;
libconfig->setting_set_bool = config_setting_set_bool;
libconfig->setting_set_string = config_setting_set_string;
@@ -169,13 +489,13 @@ void libconfig_defaults(void) {
libconfig->setting_get_format = config_setting_get_format;
/* */
libconfig->setting_get_int_elem = config_setting_get_int_elem;
- libconfig->setting_get_int64_elem = config_setting_get_int64_elem;
+ libconfig->setting_get_int64_elem = config_setting_get_int64_elem_real;
libconfig->setting_get_float_elem = config_setting_get_float_elem;
libconfig->setting_get_bool_elem = config_setting_get_bool_elem;
libconfig->setting_get_string_elem = config_setting_get_string_elem;
/* */
libconfig->setting_set_int_elem = config_setting_set_int_elem;
- libconfig->setting_set_int64_elem = config_setting_set_int64_elem;
+ libconfig->setting_set_int64_elem = config_setting_set_int64_elem_real;
libconfig->setting_set_float_elem = config_setting_set_float_elem;
libconfig->setting_set_bool_elem = config_setting_set_bool_elem;
libconfig->setting_set_string_elem = config_setting_set_string_elem;
@@ -193,17 +513,30 @@ void libconfig_defaults(void) {
libconfig->setting_set_hook = config_setting_set_hook;
/* */
libconfig->lookup = config_lookup;
- libconfig->lookup_from = config_lookup_from;
/* */
libconfig->lookup_int = config_lookup_int;
- libconfig->lookup_int64 = config_lookup_int64;
+ libconfig->lookup_int64 = config_lookup_int64_real;
libconfig->lookup_float = config_lookup_float;
libconfig->lookup_bool = config_lookup_bool;
libconfig->lookup_string = config_lookup_string;
/* those are custom and are from src/common/conf.c */
- libconfig->read_file = conf_read_file;
+ libconfig->load_file = config_load_file;
libconfig->setting_copy_simple = config_setting_copy_simple;
libconfig->setting_copy_elem = config_setting_copy_elem;
libconfig->setting_copy_aggregate = config_setting_copy_aggregate;
libconfig->setting_copy = config_setting_copy;
+
+ /* Functions to get different types */
+ libconfig->setting_get_bool_real = config_setting_get_bool_real;
+ libconfig->setting_get_uint32 = config_setting_get_uint32;
+ libconfig->setting_get_uint16 = config_setting_get_uint16;
+ libconfig->setting_get_int16 = config_setting_get_int16;
+
+ /* Functions to lookup different types */
+ libconfig->setting_lookup_int16 = config_setting_lookup_int16;
+ libconfig->setting_lookup_bool_real = config_setting_lookup_bool_real;
+ libconfig->setting_lookup_uint32 = config_setting_lookup_uint32;
+ libconfig->setting_lookup_uint16 = config_setting_lookup_uint16;
+ libconfig->setting_lookup_mutable_string = config_setting_lookup_mutable_string;
+ libconfig->lookup_mutable_string = config_lookup_mutable_string;
}
diff --git a/src/common/conf.h b/src/common/conf.h
index 19b13c51a..bd6acc4be 100644
--- a/src/common/conf.h
+++ b/src/common/conf.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -29,82 +29,94 @@
* The libconfig interface -- specially for plugins, but we enforce it throughout the core to be consistent
**/
struct libconfig_interface {
- int (*read) (config_t *config, FILE *stream);
- void (*write) (const config_t *config, FILE *stream);
+ int (*read) (struct config_t *config, FILE *stream);
+ void (*write) (const struct config_t *config, FILE *stream);
/* */
- void (*set_auto_convert) (config_t *config, int flag); // TODO: Replace with config_set_options
- int (*get_auto_convert) (const config_t *config); // TODO: Replace with config_get_options
+ void (*set_options) (struct config_t *config, int options);
+ int (*get_options) (const struct config_t *config);
/* */
- int (*read_string) (config_t *config, const char *str);
- int (*read_file_src) (config_t *config, const char *filename);
- int (*write_file) (config_t *config, const char *filename);
-
- void (*set_destructor) (config_t *config, void (*destructor)(void *));
- void (*set_include_dir) (config_t *config, const char *include_dir);
-
- void (*init) (config_t *config);
- void (*destroy) (config_t *config);
-
- int (*setting_get_int) (const config_setting_t *setting);
- long long (*setting_get_int64) (const config_setting_t *setting);
- double (*setting_get_float) (const config_setting_t *setting);
-
- int (*setting_get_bool) (const config_setting_t *setting);
-
- const char * (*setting_get_string) (const config_setting_t *setting);
-
- int (*setting_lookup_int) (const config_setting_t *setting, const char *name, int *value);
- int (*setting_lookup_int64) (const config_setting_t *setting, const char *name, long long *value);
- int (*setting_lookup_float) (const config_setting_t *setting, const char *name, double *value);
- int (*setting_lookup_bool) (const config_setting_t *setting, const char *name, int *value);
- int (*setting_lookup_string) (const config_setting_t *setting, const char *name, const char **value);
- int (*setting_set_int) (config_setting_t *setting ,int value);
- int (*setting_set_int64) (config_setting_t *setting, long long value);
- int (*setting_set_float) (config_setting_t *setting, double value);
- int (*setting_set_bool) (config_setting_t *setting, int value);
- int (*setting_set_string) (config_setting_t *setting, const char *value);
-
- int (*setting_set_format) (config_setting_t *setting, short format);
- short (*setting_get_format) (const config_setting_t *setting);
-
- int (*setting_get_int_elem) (const config_setting_t *setting, int idx);
- long long (*setting_get_int64_elem) (const config_setting_t *setting, int idx);
- double (*setting_get_float_elem) (const config_setting_t *setting, int idx);
- int (*setting_get_bool_elem) (const config_setting_t *setting, int idx);
- const char * (*setting_get_string_elem) (const config_setting_t *setting, int idx);
- config_setting_t * (*setting_set_int_elem) (config_setting_t *setting, int idx, int value);
- config_setting_t * (*setting_set_int64_elem) (config_setting_t *setting, int idx, long long value);
- config_setting_t * (*setting_set_float_elem) (config_setting_t *setting, int idx, double value);
- config_setting_t * (*setting_set_bool_elem) (config_setting_t *setting, int idx, int value);
- config_setting_t * (*setting_set_string_elem) (config_setting_t *setting, int idx, const char *value);
-
- int (*setting_index) (const config_setting_t *setting);
- int (*setting_length) (const config_setting_t *setting);
-
- config_setting_t * (*setting_get_elem) (const config_setting_t *setting, unsigned int idx);
- config_setting_t * (*setting_get_member) (const config_setting_t *setting, const char *name);
-
- config_setting_t * (*setting_add) (config_setting_t *parent, const char *name, int type);
- int (*setting_remove) (config_setting_t *parent, const char *name);
-
- int (*setting_remove_elem) (config_setting_t *parent, unsigned int idx);
- void (*setting_set_hook) (config_setting_t *setting, void *hook);
-
- config_setting_t * (*lookup) (const config_t *config, const char *filepath);
- config_setting_t * (*lookup_from) (config_setting_t *setting, const char *filepath);
- int (*lookup_int) (const config_t *config, const char *filepath, int *value);
- int (*lookup_int64) (const config_t *config, const char *filepath, long long *value);
- int (*lookup_float) (const config_t *config, const char *filepath, double *value);
- int (*lookup_bool) (const config_t *config, const char *filepath, int *value);
- int (*lookup_string) (const config_t *config, const char *filepath, const char **value);
+ int (*read_string) (struct config_t *config, const char *str);
+ int (*read_file_src) (struct config_t *config, const char *filename);
+ int (*write_file) (struct config_t *config, const char *filename);
+
+ void (*set_destructor) (struct config_t *config, void (*destructor)(void *));
+ void (*set_include_dir) (struct config_t *config, const char *include_dir);
+
+ void (*init) (struct config_t *config);
+ void (*destroy) (struct config_t *config);
+
+ int (*setting_get_int) (const struct config_setting_t *setting);
+ int64 (*setting_get_int64) (const struct config_setting_t *setting);
+ double (*setting_get_float) (const struct config_setting_t *setting);
+
+ int (*setting_get_bool) (const struct config_setting_t *setting);
+
+ const char * (*setting_get_string) (const struct config_setting_t *setting);
+
+ struct config_setting_t * (*setting_lookup) (struct config_setting_t *setting, const char *name);
+ int (*setting_lookup_int) (const struct config_setting_t *setting, const char *name, int *value);
+ int (*setting_lookup_int64) (const struct config_setting_t *setting, const char *name, int64 *value);
+ int (*setting_lookup_float) (const struct config_setting_t *setting, const char *name, double *value);
+ int (*setting_lookup_bool) (const struct config_setting_t *setting, const char *name, int *value);
+ int (*setting_lookup_string) (const struct config_setting_t *setting, const char *name, const char **value);
+ int (*setting_set_int) (struct config_setting_t *setting, int value);
+ int (*setting_set_int64) (struct config_setting_t *setting, int64 value);
+ int (*setting_set_float) (struct config_setting_t *setting, double value);
+ int (*setting_set_bool) (struct config_setting_t *setting, int value);
+ int (*setting_set_string) (struct config_setting_t *setting, const char *value);
+
+ int (*setting_set_format) (struct config_setting_t *setting, short format);
+ short (*setting_get_format) (const struct config_setting_t *setting);
+
+ int (*setting_get_int_elem) (const struct config_setting_t *setting, int idx);
+ int64 (*setting_get_int64_elem) (const struct config_setting_t *setting, int idx);
+ double (*setting_get_float_elem) (const struct config_setting_t *setting, int idx);
+ int (*setting_get_bool_elem) (const struct config_setting_t *setting, int idx);
+ const char * (*setting_get_string_elem) (const struct config_setting_t *setting, int idx);
+ struct config_setting_t * (*setting_set_int_elem) (struct config_setting_t *setting, int idx, int value);
+ struct config_setting_t * (*setting_set_int64_elem) (struct config_setting_t *setting, int idx, int64 value);
+ struct config_setting_t * (*setting_set_float_elem) (struct config_setting_t *setting, int idx, double value);
+ struct config_setting_t * (*setting_set_bool_elem) (struct config_setting_t *setting, int idx, int value);
+ struct config_setting_t * (*setting_set_string_elem) (struct config_setting_t *setting, int idx, const char *value);
+
+ int (*setting_index) (const struct config_setting_t *setting);
+ int (*setting_length) (const struct config_setting_t *setting);
+
+ struct config_setting_t * (*setting_get_elem) (const struct config_setting_t *setting, unsigned int idx);
+ struct config_setting_t * (*setting_get_member) (const struct config_setting_t *setting, const char *name);
+
+ struct config_setting_t * (*setting_add) (struct config_setting_t *parent, const char *name, int type);
+ int (*setting_remove) (struct config_setting_t *parent, const char *name);
+
+ int (*setting_remove_elem) (struct config_setting_t *parent, unsigned int idx);
+ void (*setting_set_hook) (struct config_setting_t *setting, void *hook);
+
+ struct config_setting_t * (*lookup) (const struct config_t *config, const char *filepath);
+ int (*lookup_int) (const struct config_t *config, const char *filepath, int *value);
+ int (*lookup_int64) (const struct config_t *config, const char *filepath, int64 *value);
+ int (*lookup_float) (const struct config_t *config, const char *filepath, double *value);
+ int (*lookup_bool) (const struct config_t *config, const char *filepath, int *value);
+ int (*lookup_string) (const struct config_t *config, const char *filepath, const char **value);
/* those are custom and are from src/common/conf.c */
/* Functions to copy settings from libconfig/contrib */
- int (*read_file) (config_t *config, const char *config_filename);
- void (*setting_copy_simple) (config_setting_t *parent, const config_setting_t *src);
- void (*setting_copy_elem) (config_setting_t *parent, const config_setting_t *src);
- void (*setting_copy_aggregate) (config_setting_t *parent, const config_setting_t *src);
- int (*setting_copy) (config_setting_t *parent, const config_setting_t *src);
+ int (*load_file) (struct config_t *config, const char *config_filename);
+ void (*setting_copy_simple) (struct config_setting_t *parent, const struct config_setting_t *src);
+ void (*setting_copy_elem) (struct config_setting_t *parent, const struct config_setting_t *src);
+ void (*setting_copy_aggregate) (struct config_setting_t *parent, const struct config_setting_t *src);
+ int (*setting_copy) (struct config_setting_t *parent, const struct config_setting_t *src);
+ /* Functions to get other types */
+ bool (*setting_get_bool_real) (const struct config_setting_t *setting);
+ uint32 (*setting_get_uint32) (const struct config_setting_t *setting);
+ uint16 (*setting_get_uint16) (const struct config_setting_t *setting);
+ int16 (*setting_get_int16) (const struct config_setting_t *setting);
+
+ int (*setting_lookup_bool_real) (const struct config_setting_t *setting, const char *name, bool *value);
+ int (*setting_lookup_uint32) (const struct config_setting_t *setting, const char *name, uint32 *value);
+ int (*setting_lookup_uint16) (const struct config_setting_t *setting, const char *name, uint16 *value);
+ int (*setting_lookup_int16) (const struct config_setting_t *setting, const char *name, int16 *value);
+ int (*setting_lookup_mutable_string) (const struct config_setting_t *setting, const char *name, char *out, size_t out_size);
+ int (*lookup_mutable_string) (const struct config_t *config, const char *name, char *out, size_t out_size);
};
#ifdef HERCULES_CORE
diff --git a/src/common/console.c b/src/common/console.c
index f0702d0da..0f79b9494 100644
--- a/src/common/console.c
+++ b/src/common/console.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -57,6 +57,7 @@ struct console_interface console_s;
struct console_interface *console;
#ifdef CONSOLE_INPUT
struct console_input_interface console_input_s;
+struct spin_lock console_ptlock_s;
struct {
char queue[CONSOLE_PARSE_SIZE][MAX_CONSOLE_INPUT];
@@ -67,7 +68,8 @@ struct {
/*======================================
* CORE : Display title
*--------------------------------------*/
-void display_title(void) {
+void display_title(void)
+{
const char *vcstype = sysinfo->vcstype();
ShowMessage("\n");
@@ -90,6 +92,7 @@ void display_title(void) {
ShowInfo("CPU: '"CL_WHITE"%s [%d]"CL_RESET"'\n", sysinfo->cpu(), sysinfo->cpucores());
ShowInfo("Compiled with %s\n", sysinfo->compiler());
ShowInfo("Compile Flags: %s\n", sysinfo->cflags());
+ ShowInfo("Timer Function Type: %s\n", sysinfo->time());
}
/**
@@ -97,7 +100,7 @@ void display_title(void) {
*/
void display_gplnotice(void)
{
- ShowInfo("Hercules, Copyright (C) 2012-2015, Hercules Dev Team and others.\n");
+ ShowInfo("Hercules, Copyright (C) 2012-2016, Hercules Dev Team and others.\n");
ShowInfo("Licensed under the GNU General Public License, version 3 or later.\n");
}
@@ -128,21 +131,24 @@ int console_parse_key_pressed(void)
/**
* Stops server
**/
-CPCMD_C(exit,server) {
+CPCMD_C(exit, server)
+{
core->runflag = 0;
}
/**
* Displays ERS-related statistics (Entry Reusage System)
**/
-CPCMD_C(ers_report,server) {
+CPCMD_C(ers_report, server)
+{
ers_report();
}
/**
* Displays memory usage
**/
-CPCMD_C(mem_report,server) {
+CPCMD_C(mem_report, server)
+{
#ifdef USE_MEMMGR
memmgr_report(line?atoi(line):0);
#endif
@@ -169,7 +175,8 @@ CPCMD(help)
* [Ind/Hercules]
* Displays current malloc usage
*/
-CPCMD_C(malloc_usage,server) {
+CPCMD_C(malloc_usage, server)
+{
unsigned int val = (unsigned int)iMalloc->usage();
ShowInfo("malloc_usage: %.2f MB\n",(double)(val)/1024);
}
@@ -178,7 +185,8 @@ CPCMD_C(malloc_usage,server) {
* Skips an sql update
* Usage: sql update skip UPDATE-FILE.sql
**/
-CPCMD_C(skip,update) {
+CPCMD_C(skip, update)
+{
if( !line ) {
ShowDebug("usage example: sql update skip 2013-02-14--16-15.sql\n");
return;
@@ -309,6 +317,7 @@ void console_parse_create(char *name, CParseFunc func)
char sublist[CP_CMD_LENGTH * 5];
struct CParseEntry *cmd;
+ nullpo_retv(name);
safestrncpy(sublist, name, CP_CMD_LENGTH * 5);
tok = strtok(sublist,":");
@@ -362,6 +371,7 @@ void console_parse_list_subs(struct CParseEntry *cmd, unsigned char depth)
{
int i;
char msg[CP_CMD_LENGTH * 2];
+ nullpo_retv(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);
@@ -389,6 +399,7 @@ void console_parse_sub(char *line)
char sublist[CP_CMD_LENGTH * 5];
int i;
+ nullpo_retv(line);
memcpy(bline, line, 200);
tok = strtok(line, " ");
@@ -442,9 +453,12 @@ void console_parse_sub(char *line)
}
ShowError("Is only a category, type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist);
}
-void console_parse(char* line) {
+
+void console_parse(char *line)
+{
int c, i = 0, len = MAX_CONSOLE_INPUT - 1;/* we leave room for the \0 :P */
+ nullpo_retv(line);
while( (c = fgetc(stdin)) != EOF ) {
if( --len == 0 )
break;
@@ -456,65 +470,73 @@ void console_parse(char* line) {
line[i++] = '\0';
}
-void *cThread_main(void *x) {
+
+void *cThread_main(void *x)
+{
while( console->input->ptstate ) {/* loopx */
if( console->input->key_pressed() ) {
char input[MAX_CONSOLE_INPUT];
console->input->parse(input);
if( input[0] != '\0' ) {/* did we get something? */
- EnterSpinLock(&console->input->ptlock);
+ EnterSpinLock(console->input->ptlock);
if( cinput.count == CONSOLE_PARSE_SIZE ) {
- LeaveSpinLock(&console->input->ptlock);
+ LeaveSpinLock(console->input->ptlock);
continue;/* drop */
}
safestrncpy(cinput.queue[cinput.count++],input,MAX_CONSOLE_INPUT);
- LeaveSpinLock(&console->input->ptlock);
+ LeaveSpinLock(console->input->ptlock);
}
}
- ramutex_lock( console->input->ptmutex );
- racond_wait( console->input->ptcond, console->input->ptmutex, -1 );
- ramutex_unlock( console->input->ptmutex );
+ mutex->lock(console->input->ptmutex);
+ mutex->cond_wait(console->input->ptcond, console->input->ptmutex, -1);
+ mutex->unlock(console->input->ptmutex);
}
return NULL;
}
-int console_parse_timer(int tid, int64 tick, int id, intptr_t data) {
+
+int console_parse_timer(int tid, int64 tick, int id, intptr_t data)
+{
int i;
- EnterSpinLock(&console->input->ptlock);
+ EnterSpinLock(console->input->ptlock);
for(i = 0; i < cinput.count; i++) {
console->input->parse_sub(cinput.queue[i]);
}
cinput.count = 0;
- LeaveSpinLock(&console->input->ptlock);
- racond_signal(console->input->ptcond);
+ LeaveSpinLock(console->input->ptlock);
+ mutex->cond_signal(console->input->ptcond);
return 0;
}
-void console_parse_final(void) {
+
+void console_parse_final(void)
+{
if( console->input->ptstate ) {
InterlockedDecrement(&console->input->ptstate);
- racond_signal(console->input->ptcond);
+ mutex->cond_signal(console->input->ptcond);
/* wait for thread to close */
- rathread_wait(console->input->pthread, NULL);
+ thread->wait(console->input->pthread, NULL);
- racond_destroy(console->input->ptcond);
- ramutex_destroy(console->input->ptmutex);
+ mutex->cond_destroy(console->input->ptcond);
+ mutex->destroy(console->input->ptmutex);
}
}
-void console_parse_init(void) {
+
+void console_parse_init(void)
+{
cinput.count = 0;
console->input->ptstate = 1;
- InitializeSpinLock(&console->input->ptlock);
+ InitializeSpinLock(console->input->ptlock);
- console->input->ptmutex = ramutex_create();
- console->input->ptcond = racond_create();
+ console->input->ptmutex = mutex->create();
+ console->input->ptcond = mutex->cond_create();
- if( (console->input->pthread = rathread_create(console->input->pthread_main, NULL)) == NULL ){
+ if( (console->input->pthread = thread->create(console->input->pthread_main, NULL)) == NULL ){
ShowFatalError("console_parse_init: failed to spawn console_parse thread.\n");
exit(EXIT_FAILURE);
}
@@ -522,7 +544,9 @@ void console_parse_init(void) {
timer->add_func_list(console->input->parse_timer, "console_parse_timer");
timer->add_interval(timer->gettick() + 1000, console->input->parse_timer, 0, 0, 500);/* start listening in 1s; re-try every 0.5s */
}
-void console_setSQL(Sql *SQL_handle) {
+
+void console_setSQL(struct Sql *SQL_handle)
+{
console->input->SQL = SQL_handle;
}
#endif /* CONSOLE_INPUT */
@@ -561,6 +585,7 @@ void console_defaults(void)
console->display_gplnotice = display_gplnotice;
#ifdef CONSOLE_INPUT
console->input = &console_input_s;
+ console->input->ptlock = &console_ptlock_s;
console->input->parse_init = console_parse_init;
console->input->parse_final = console_parse_final;
console->input->parse_timer = console_parse_timer;
diff --git a/src/common/console.h b/src/common/console.h
index 43f48b865..dd3a9cf2e 100644
--- a/src/common/console.h
+++ b/src/common/console.h
@@ -22,10 +22,14 @@
#include "common/hercules.h"
#include "common/db.h"
-#include "common/mutex.h"
#include "common/spinlock.h"
-#include "common/sql.h"
-#include "common/thread.h"
+
+/* Forward Declarations */
+struct Sql; // common/sql.h
+struct cond_data;
+struct mutex_data;
+struct spin_lock;
+struct thread_handle;
/**
* Queue Max
@@ -69,16 +73,16 @@ struct CParseEntry {
struct console_input_interface {
#ifdef CONSOLE_INPUT
/* vars */
- SPIN_LOCK ptlock;/* parse thread lock */
- rAthread *pthread;/* parse thread */
- volatile int32 ptstate;/* parse thread state */
- ramutex *ptmutex;/* parse thread mutex */
- racond *ptcond;/* parse thread cond */
+ struct spin_lock *ptlock; ///< parse thread lock.
+ struct thread_handle *pthread; ///< parse thread.
+ volatile int32 ptstate; ///< parse thread state.
+ struct mutex_data *ptmutex; ///< parse thread mutex.
+ struct cond_data *ptcond; ///< parse thread conditional variable.
/* */
VECTOR_DECL(struct CParseEntry *) command_list;
VECTOR_DECL(struct CParseEntry *) commands;
/* */
- Sql *SQL;
+ struct Sql *SQL;
/* */
void (*parse_init) (void);
void (*parse_final) (void);
@@ -90,7 +94,7 @@ struct console_input_interface {
void (*load_defaults) (void);
void (*parse_list_subs) (struct CParseEntry *cmd, unsigned char depth);
void (*addCommand) (char *name, CParseFunc func);
- void (*setSQL) (Sql *SQL_handle);
+ void (*setSQL) (struct Sql *SQL_handle);
#else // not CONSOLE_INPUT
UNAVAILABLE_STRUCT;
#endif
diff --git a/src/common/core.c b/src/common/core.c
index 201d4f5e8..9a131d042 100644
--- a/src/common/core.c
+++ b/src/common/core.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -26,23 +26,27 @@
#include "common/cbasetypes.h"
#include "common/console.h"
#include "common/db.h"
+#include "common/des.h"
+#include "common/grfio.h"
#include "common/memmgr.h"
#include "common/mmo.h"
-#include "common/random.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
#include "common/sysinfo.h"
-#include "common/nullpo.h"
+#include "common/timer.h"
+#include "common/utils.h"
#ifndef MINICORE
# include "common/HPM.h"
# include "common/conf.h"
# include "common/ers.h"
+# include "common/md5calc.h"
+# include "common/mutex.h"
+# include "common/random.h"
# include "common/socket.h"
# include "common/sql.h"
# include "common/thread.h"
-# include "common/timer.h"
-# include "common/utils.h"
#endif
#ifndef _WIN32
@@ -54,6 +58,28 @@
#include <stdio.h>
#include <stdlib.h>
+/*
+ * Uncomment the line below if you want to silence the root warning on startup
+ * (not recommended, as it opens the machine to security risks. You should
+ * never ever run software as root unless it requires the extra privileges
+ * (which Hercules does not.)
+ * More info:
+ * http://www.tldp.org/HOWTO/Security-HOWTO/local-security.html
+ * http://www.gentoo.org/doc/en/security/security-handbook.xml?style=printable&part=1&chap=1#doc_chap4
+ * http://wiki.centos.org/TipsAndTricks/BecomingRoot
+ * http://fedoraproject.org/wiki/Configuring_Sudo
+ * https://help.ubuntu.com/community/RootSudo
+ * http://www.freebsdwiki.net/index.php/Root
+ *
+ * If your service provider forces (or encourages) you to run server software
+ * as root, please complain to them before and after uncommenting this line,
+ * since it is a very bad idea.
+ * Please note that NO SUPPORT will be given if you uncomment the following line.
+ */
+//#define I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+// And don't complain to us if the XYZ plugin you installed wiped your hard disk, or worse.
+// Note: This feature is deprecated, and should not be used.
+
/// Called when a terminate signal is received.
void (*shutdown_callback)(void) = NULL;
@@ -74,7 +100,8 @@ struct core_interface *core = &core_s;
#ifndef POSIX
#define compat_signal(signo, func) signal((signo), (func))
#else
-sigfunc *compat_signal(int signo, sigfunc *func) {
+sigfunc *compat_signal(int signo, sigfunc *func)
+{
struct sigaction sact, oact;
sact.sa_handler = func;
@@ -95,7 +122,8 @@ sigfunc *compat_signal(int signo, sigfunc *func) {
* CORE : Console events for Windows
*--------------------------------------*/
#ifdef _WIN32
-static BOOL WINAPI console_handler(DWORD c_event) {
+static BOOL WINAPI console_handler(DWORD c_event)
+{
switch(c_event) {
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
@@ -111,7 +139,8 @@ static BOOL WINAPI console_handler(DWORD c_event) {
return TRUE;
}
-static void cevents_init(void) {
+static void cevents_init(void)
+{
if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE)
ShowWarning ("Unable to install the console handler!\n");
}
@@ -120,7 +149,8 @@ static void cevents_init(void) {
/*======================================
* CORE : Signal Sub Function
*--------------------------------------*/
-static void sig_proc(int sn) {
+static void sig_proc(int sn)
+{
static int is_called = 0;
switch (sn) {
@@ -153,7 +183,8 @@ static void sig_proc(int sn) {
}
}
-void signals_init (void) {
+void signals_init (void)
+{
compat_signal(SIGTERM, sig_proc);
compat_signal(SIGINT, sig_proc);
#ifndef _DEBUG // need unhandled exceptions to debug on Windows
@@ -172,14 +203,55 @@ void signals_init (void) {
/**
* Warns the user if executed as superuser (root)
+ *
+ * @retval false if the check didn't pass and the program should be terminated.
*/
-void usercheck(void) {
+bool usercheck(void)
+{
+#ifndef _WIN32
if (sysinfo->is_superuser()) {
- ShowWarning("You are running Hercules with root privileges, it is not necessary.\n");
+ if (!isatty(fileno(stdin))) {
+#ifdef BUILDBOT
+ return true;
+#else // BUILDBOT
+ ShowFatalError("You are running Hercules with root privileges, it is not necessary, nor recommended. "
+ "Aborting.\n");
+ return false; // Don't allow noninteractive execution regardless.
+#endif // BUILDBOT
+ }
+ ShowError("You are running Hercules with root privileges, it is not necessary, nor recommended.\n");
+#ifdef I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+#ifndef BUILDBOT
+#warning This Hercules build is not eligible to obtain support by the developers.
+#warning The setting I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT is deprecated and should not be used.
+#endif // BUILDBOT
+#else // not I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+ ShowNotice("Execution will be paused for 60 seconds. Press Ctrl-C if you wish to quit.\n");
+ ShowNotice("If you want to get rid of this message, please open %s and uncomment, near the top, the line saying:\n"
+ "\t\"//#define I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT\"\n", __FILE__);
+ ShowNotice("Note: In a near future, this courtesy notice will go away. "
+ "Please update your infrastructure not to require root privileges before then.\n");
+ ShowWarning("It's recommended that you " CL_WHITE "press CTRL-C now!" CL_RESET "\n");
+ {
+ int i;
+ for (i = 0; i < 60; i++) {
+ ShowMessage("\a *");
+ HSleep(1);
+ }
+ }
+ ShowMessage("\n");
+ ShowNotice("Resuming operations with root privileges. "
+ CL_RED "If anything breaks, you get to keep the pieces, "
+ "and the Hercules developers won't be able to help you."
+ CL_RESET "\n");
+#endif // I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
}
+#endif // not _WIN32
+ return true;
}
-void core_defaults(void) {
+void core_defaults(void)
+{
nullpo_defaults();
#ifndef MINICORE
hpm_defaults();
@@ -191,24 +263,34 @@ void core_defaults(void) {
malloc_defaults();
showmsg_defaults();
cmdline_defaults();
+ des_defaults();
+ grfio_defaults(); // Note: grfio is lazily loaded. grfio->init() and grfio->final() are not automatically called.
#ifndef MINICORE
+ mutex_defaults();
libconfig_defaults();
sql_defaults();
timer_defaults();
db_defaults();
socket_defaults();
+ rnd_defaults();
+ md5_defaults();
+ thread_defaults();
#endif
}
+
/**
* Returns the source (core or plugin name) for the given command-line argument
*/
-const char *cmdline_arg_source(struct CmdlineArgData *arg) {
+const char *cmdline_arg_source(struct CmdlineArgData *arg)
+{
#ifdef MINICORE
return "core";
#else // !MINICORE
+ nullpo_retr(NULL, arg);
return HPM->pid2name(arg->pluginID);
#endif // MINICORE
}
+
/**
* Defines a command line argument.
*
@@ -220,9 +302,11 @@ const char *cmdline_arg_source(struct CmdlineArgData *arg) {
* @param options options associated to the command-line argument. @see enum cmdline_options.
* @return the success status.
*/
-bool cmdline_arg_add(unsigned int pluginID, const char *name, char shortname, CmdlineExecFunc func, const char *help, unsigned int options) {
+bool cmdline_arg_add(unsigned int pluginID, const char *name, char shortname, CmdlineExecFunc func, const char *help, unsigned int options)
+{
struct CmdlineArgData *data = NULL;
+ nullpo_retr(false, name);
VECTOR_ENSURE(cmdline->args_data, 1, 1);
VECTOR_PUSHZEROED(cmdline->args_data);
data = &VECTOR_LAST(cmdline->args_data);
@@ -230,11 +314,15 @@ bool cmdline_arg_add(unsigned int pluginID, const char *name, char shortname, Cm
data->name = aStrdup(name);
data->shortname = shortname;
data->func = func;
- data->help = aStrdup(help);
+ if (help)
+ data->help = aStrdup(help);
+ else
+ data->help = NULL;
data->options = options;
return true;
}
+
/**
* Help screen to be displayed by '--help'.
*/
@@ -258,6 +346,7 @@ static CMDLINEARG(help)
}
return false;
}
+
/**
* Info screen to be displayed by '--version'.
*/
@@ -268,6 +357,7 @@ static CMDLINEARG(version)
ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n");
return false;
}
+
/**
* Checks if there is a value available for the current argument
*
@@ -285,6 +375,7 @@ bool cmdline_arg_next_value(const char *name, int current_arg, int argc)
return true;
}
+
/**
* Executes the command line arguments handlers.
*
@@ -306,11 +397,15 @@ 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;
+
+ nullpo_ret(argv);
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 '-'
+ if ((options&(CMDLINE_OPT_SILENT|CMDLINE_OPT_PREINIT)) != 0)
+ continue;
ShowError("Invalid option '%s'.\n", argv[i]);
exit(EXIT_FAILURE);
}
@@ -348,6 +443,7 @@ int cmdline_exec(int argc, char **argv, unsigned int options)
}
return count;
}
+
/**
* Defines the global command-line arguments.
*/
@@ -391,10 +487,12 @@ void cmdline_defaults(void)
cmdline->arg_next_value = cmdline_arg_next_value;
cmdline->arg_source = cmdline_arg_source;
}
+
/*======================================
* CORE : MAINROUTINE
*--------------------------------------*/
-int main (int argc, char **argv) {
+int main (int argc, char **argv)
+{
int retval = EXIT_SUCCESS;
{// initialize program arguments
char *p1 = SERVER_NAME = argv[0];
@@ -423,7 +521,8 @@ int main (int argc, char **argv) {
if (!(showmsg->silent&0x1))
console->display_title();
- usercheck();
+ if (!usercheck())
+ return EXIT_FAILURE;
#ifdef MINICORE // minimalist Core
do_init(argc,argv);
@@ -432,7 +531,7 @@ int main (int argc, char **argv) {
set_server_type();
Sql_Init();
- rathread_init();
+ thread->init();
DB->init();
signals_init();
@@ -443,8 +542,7 @@ int main (int argc, char **argv) {
timer->init();
/* timer first */
- rnd_init();
- srand((unsigned int)timer->gettick());
+ rnd->init();
console->init();
@@ -469,8 +567,9 @@ int main (int argc, char **argv) {
timer->final();
sockt->final();
DB->final();
- rathread_final();
+ thread->final();
ers_final();
+ rnd->final();
#endif
cmdline->final();
//sysinfo->final(); Called by iMalloc->final()
diff --git a/src/common/core.h b/src/common/core.h
index 4aaa6cfac..a8726fcef 100644
--- a/src/common/core.h
+++ b/src/common/core.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/db.c b/src/common/db.c
index ca9a70f7c..91592fdac 100644
--- a/src/common/db.c
+++ b/src/common/db.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,7 +21,7 @@
/*****************************************************************************\
* This file is separated in five sections:
- * (1) Private typedefs, enums, structures, defines and global variables
+ * (1) Private enums, structures, defines and global variables
* (2) Private functions
* (3) Protected functions used internally
* (4) Protected functions used in the interface of the database
@@ -93,6 +93,7 @@
#include "common/ers.h"
#include "common/memmgr.h"
#include "common/mmo.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
@@ -102,17 +103,17 @@
struct db_interface DB_s;
struct db_interface *DB;
-/*****************************************************************************\
- * (1) Private typedefs, enums, structures, defines and global variables of *
- * the database system. *
- * DB_ENABLE_STATS - Define to enable database statistics. *
- * HASH_SIZE - Define with the size of the hashtable. *
- * DBNColor - Enumeration of colors of the nodes. *
- * DBNode - Structure of a node in RED-BLACK trees. *
- * struct db_free - Structure that holds a deleted node to be freed. *
- * DBMap_impl - Structure of the database. *
- * stats - Statistics about the database system. *
-\*****************************************************************************/
+/*****************************************************************************
+ * (1) Private enums, structures, defines and global variables of the *
+ * database system. *
+ * DB_ENABLE_STATS - Define to enable database statistics. *
+ * HASH_SIZE - Define with the size of the hashtable. *
+ * enum DBNodeColor - Enumeration of colors of the nodes. *
+ * struct DBNode - Structure of a node in RED-BLACK trees. *
+ * struct db_free - Structure that holds a deleted node to be freed. *
+ * struct DBMap_impl - Structure of the database. *
+ * stats - Statistics about the database system. *
+ *****************************************************************************/
/**
* If defined statistics about database nodes, database creating/destruction
@@ -129,19 +130,19 @@ struct db_interface *DB;
/**
* Size of the hashtable in the database.
* @private
- * @see DBMap_impl#ht
+ * @see struct DBMap_impl#ht
*/
#define HASH_SIZE (256+27)
/**
* The color of individual nodes.
* @private
- * @see struct dbn
+ * @see struct DBNode
*/
-typedef enum node_color {
+enum DBNodeColor {
RED,
- BLACK
-} node_color;
+ BLACK,
+};
/**
* A node in a RED-BLACK tree of the database.
@@ -153,31 +154,31 @@ typedef enum node_color {
* @param deleted If the node is deleted
* @param color Color of the node
* @private
- * @see DBMap_impl#ht
+ * @see struct DBMap_impl#ht
*/
-typedef struct dbn {
+struct DBNode {
// Tree structure
- struct dbn *parent;
- struct dbn *left;
- struct dbn *right;
+ struct DBNode *parent;
+ struct DBNode *left;
+ struct DBNode *right;
// Node data
- DBKey key;
- DBData data;
+ union DBKey key;
+ struct DBData data;
// Other
- node_color color;
+ enum DBNodeColor color;
unsigned deleted : 1;
-} DBNode;
+};
/**
* Structure that holds a deleted node.
* @param node Deleted node
* @param root Address to the root of the tree
* @private
- * @see DBMap_impl#free_list
+ * @see struct DBMap_impl#free_list
*/
struct db_free {
- DBNode *node;
- DBNode **root;
+ struct DBNode *node;
+ struct DBNode **root;
};
/**
@@ -200,9 +201,9 @@ struct db_free {
* @param maxlen Maximum length of strings in DB_STRING and DB_ISTRING databases
* @param global_lock Global lock of the database
* @private
- * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short)
+ * @see #db_alloc()
*/
-typedef struct DBMap_impl {
+struct DBMap_impl {
// Database interface
struct DBMap vtable;
// File and line of allocation
@@ -218,14 +219,14 @@ typedef struct DBMap_impl {
DBComparator cmp;
DBHasher hash;
DBReleaser release;
- DBNode *ht[HASH_SIZE];
- DBNode *cache;
- DBType type;
- DBOptions options;
+ struct DBNode *ht[HASH_SIZE];
+ struct DBNode *cache;
+ enum DBType type;
+ enum DBOptions options;
uint32 item_count;
unsigned short maxlen;
unsigned global_lock : 1;
-} DBMap_impl;
+};
/**
* Complete iterator structure.
@@ -234,17 +235,17 @@ typedef struct DBMap_impl {
* @param ht_index Current index of the hashtable
* @param node Current node
* @private
- * @see #DBIterator
- * @see #DBMap_impl
- * @see #DBNode
+ * @see struct DBIterator
+ * @see struct DBMap_impl
+ * @see struct DBNode
*/
-typedef struct DBIterator_impl {
+struct DBIterator_impl {
// Iterator interface
struct DBIterator vtable;
- DBMap_impl* db;
+ struct DBMap_impl *db;
int ht_index;
- DBNode *node;
-} DBIterator_impl;
+ struct DBNode *node;
+};
#if defined(DB_ENABLE_STATS)
/**
@@ -382,12 +383,12 @@ struct eri *db_alloc_ers;
* @param node Node to be rotated
* @param root Pointer to the root of the tree
* @private
- * @see #db_rebalance(DBNode *,DBNode **)
- * @see #db_rebalance_erase(DBNode *,DBNode **)
+ * @see #db_rebalance()
+ * @see #db_rebalance_erase()
*/
-static void db_rotate_left(DBNode *node, DBNode **root)
+static void db_rotate_left(struct DBNode *node, struct DBNode **root)
{
- DBNode *y = node->right;
+ struct DBNode *y = node->right;
DB_COUNTSTAT(db_rotate_left);
// put the left of y at the right of node
@@ -413,12 +414,12 @@ static void db_rotate_left(DBNode *node, DBNode **root)
* @param node Node to be rotated
* @param root Pointer to the root of the tree
* @private
- * @see #db_rebalance(DBNode *,DBNode **)
- * @see #db_rebalance_erase(DBNode *,DBNode **)
+ * @see #db_rebalance()
+ * @see #db_rebalance_erase()
*/
-static void db_rotate_right(DBNode *node, DBNode **root)
+static void db_rotate_right(struct DBNode *node, struct DBNode **root)
{
- DBNode *y = node->left;
+ struct DBNode *y = node->left;
DB_COUNTSTAT(db_rotate_right);
// put the right of y at the left of node
@@ -445,13 +446,13 @@ static void db_rotate_right(DBNode *node, DBNode **root)
* @param node Node to be rebalanced
* @param root Pointer to the root of the tree
* @private
- * @see #db_rotate_left(DBNode *,DBNode **)
- * @see #db_rotate_right(DBNode *,DBNode **)
- * @see #db_obj_put(DBMap*,DBKey,DBData)
+ * @see #db_rotate_left()
+ * @see #db_rotate_right()
+ * @see #db_obj_put()
*/
-static void db_rebalance(DBNode *node, DBNode **root)
+static void db_rebalance(struct DBNode *node, struct DBNode **root)
{
- DBNode *y;
+ struct DBNode *y;
DB_COUNTSTAT(db_rebalance);
// Restore the RED-BLACK properties
@@ -507,15 +508,15 @@ static void db_rebalance(DBNode *node, DBNode **root)
* @param node Node to be erased from the tree
* @param root Root of the tree
* @private
- * @see #db_rotate_left(DBNode *,DBNode **)
- * @see #db_rotate_right(DBNode *,DBNode **)
- * @see #db_free_unlock(DBMap_impl*)
+ * @see #db_rotate_left()
+ * @see #db_rotate_right()
+ * @see #db_free_unlock()
*/
-static void db_rebalance_erase(DBNode *node, DBNode **root)
+static void db_rebalance_erase(struct DBNode *node, struct DBNode **root)
{
- DBNode *y = node;
- DBNode *x = NULL;
- DBNode *x_parent = NULL;
+ struct DBNode *y = node;
+ struct DBNode *x = NULL;
+ struct DBNode *x_parent = NULL;
DB_COUNTSTAT(db_rebalance_erase);
// Select where to change the tree
@@ -561,7 +562,7 @@ static void db_rebalance_erase(DBNode *node, DBNode **root)
y->parent = node->parent;
// switch colors
{
- node_color tmp = y->color;
+ enum DBNodeColor tmp = y->color;
y->color = node->color;
node->color = tmp;
}
@@ -583,7 +584,7 @@ static void db_rebalance_erase(DBNode *node, DBNode **root)
// Restore the RED-BLACK properties
if (y->color != RED) {
while (x != *root && (x == NULL || x->color == BLACK)) {
- DBNode *w;
+ struct DBNode *w;
if (x == x_parent->left) {
w = x_parent->right;
if (w->color == RED) {
@@ -648,11 +649,11 @@ static void db_rebalance_erase(DBNode *node, DBNode **root)
* @param key Key being tested
* @return not 0 if considered NULL, 0 otherwise
* @private
- * @see #db_obj_get(DBMap*,DBKey)
- * @see #db_obj_put(DBMap*,DBKey,DBData)
- * @see #db_obj_remove(DBMap*,DBKey)
+ * @see #db_obj_get()
+ * @see #db_obj_put()
+ * @see #db_obj_remove()
*/
-static int db_is_key_null(DBType type, DBKey key)
+static int db_is_key_null(enum DBType type, union DBKey key)
{
DB_COUNTSTAT(db_is_key_null);
switch (type) {
@@ -671,26 +672,26 @@ static int db_is_key_null(DBType type, DBKey key)
* @param key Key to be duplicated
* @param Duplicated key
* @private
- * @see #db_free_add(DBMap_impl*,DBNode *,DBNode **)
- * @see #db_free_remove(DBMap_impl*,DBNode *)
- * @see #db_obj_put(DBMap*,DBKey,void *)
- * @see #db_dup_key_free(DBMap_impl*,DBKey)
+ * @see #db_free_add()
+ * @see #db_free_remove()
+ * @see #db_obj_put()
+ * @see #db_dup_key_free()
*/
-static DBKey db_dup_key(DBMap_impl* db, DBKey key)
+static union DBKey db_dup_key(struct DBMap_impl *db, union DBKey key)
{
- char *str;
- size_t len;
-
DB_COUNTSTAT(db_dup_key);
switch (db->type) {
case DB_STRING:
case DB_ISTRING:
- len = strnlen(key.str, db->maxlen);
- str = (char*)aMalloc(len + 1);
+ {
+ size_t len = strnlen(key.str, db->maxlen);
+ char *str = aMalloc(len + 1);
+
memcpy(str, key.str, len);
str[len] = '\0';
- key.str = str;
+ key.mutstr = str;
return key;
+ }
default:
return key;
@@ -702,15 +703,15 @@ static DBKey db_dup_key(DBMap_impl* db, DBKey key)
* @param db Database the key is being used in
* @param key Key to be freed
* @private
- * @see #db_dup_key(DBMap_impl*,DBKey)
+ * @see #db_dup_key()
*/
-static void db_dup_key_free(DBMap_impl* db, DBKey key)
+static void db_dup_key_free(struct DBMap_impl *db, union DBKey key)
{
DB_COUNTSTAT(db_dup_key_free);
switch (db->type) {
case DB_STRING:
case DB_ISTRING:
- aFree((char*)key.str);
+ aFree(key.mutstr);
return;
default:
@@ -727,15 +728,15 @@ static void db_dup_key_free(DBMap_impl* db, DBKey key)
* @param node Target node
* @private
* @see #struct db_free
- * @see DBMap_impl#free_list
- * @see DBMap_impl#free_count
- * @see DBMap_impl#free_max
- * @see #db_obj_remove(DBMap*,DBKey)
- * @see #db_free_remove(DBMap_impl*,DBNode *)
+ * @see struct DBMap_impl#free_list
+ * @see struct DBMap_impl#free_count
+ * @see struct DBMap_impl#free_max
+ * @see #db_obj_remove()
+ * @see #db_free_remove()
*/
-static void db_free_add(DBMap_impl* db, DBNode *node, DBNode **root)
+static void db_free_add(struct DBMap_impl *db, struct DBNode *node, struct DBNode **root)
{
- DBKey old_key;
+ union DBKey old_key;
DB_COUNTSTAT(db_free_add);
if (db->free_lock == (unsigned int)~0) {
@@ -777,12 +778,12 @@ static void db_free_add(DBMap_impl* db, DBNode *node, DBNode **root)
* @param node Node being removed from free_list
* @private
* @see #struct db_free
- * @see DBMap_impl#free_list
- * @see DBMap_impl#free_count
- * @see #db_obj_put(DBMap*,DBKey,DBData)
- * @see #db_free_add(DBMap_impl*,DBNode**,DBNode*)
+ * @see struct DBMap_impl#free_list
+ * @see struct DBMap_impl#free_count
+ * @see #db_obj_put()
+ * @see #db_free_add()
*/
-static void db_free_remove(DBMap_impl* db, DBNode *node)
+static void db_free_remove(struct DBMap_impl *db, struct DBNode *node)
{
unsigned int i;
@@ -808,10 +809,10 @@ static void db_free_remove(DBMap_impl* db, DBNode *node)
* Increment the free_lock of the database.
* @param db Target database
* @private
- * @see DBMap_impl#free_lock
- * @see #db_unlock(DBMap_impl*)
+ * @see struct DBMap_impl#free_lock
+ * @see #db_unlock()
*/
-static void db_free_lock(DBMap_impl* db)
+static void db_free_lock(struct DBMap_impl *db)
{
DB_COUNTSTAT(db_free_lock);
if (db->free_lock == (unsigned int)~0) {
@@ -830,11 +831,11 @@ static void db_free_lock(DBMap_impl* db)
* NOTE: Frees the duplicated keys of the nodes
* @param db Target database
* @private
- * @see DBMap_impl#free_lock
- * @see #db_free_dbn(DBNode*)
- * @see #db_lock(DBMap_impl*)
+ * @see struct DBMap_impl#free_lock
+ * @see #db_free_dbn()
+ * @see #db_lock()
*/
-static void db_free_unlock(DBMap_impl* db)
+static void db_free_unlock(struct DBMap_impl *db)
{
unsigned int i;
@@ -889,11 +890,11 @@ static void db_free_unlock(DBMap_impl* db)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_INT
+ * @see enum DBType#DB_INT
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_int_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int_cmp);
@@ -911,11 +912,11 @@ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_UINT
+ * @see enum DBType#DB_UINT
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_uint_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint_cmp);
@@ -932,11 +933,11 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_STRING
+ * @see enum DBType#DB_STRING
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_string_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
DB_COUNTSTAT(db_string_cmp);
return strncmp((const char *)key1.str, (const char *)key2.str, maxlen);
@@ -950,11 +951,11 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_ISTRING
+ * @see enum DBType#DB_ISTRING
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_istring_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
DB_COUNTSTAT(db_istring_cmp);
return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen);
@@ -969,11 +970,11 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_INT64
+ * @see enum DBType#DB_INT64
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_int64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_int64_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int64_cmp);
@@ -991,11 +992,11 @@ static int db_int64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key2 Key being compared to
* @param maxlen Maximum length of the key to hash
* @return 0 if equal, negative if lower and positive if higher
- * @see DBType#DB_UINT64
+ * @see enum DBType#DB_UINT64
* @see #DBComparator
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-static int db_uint64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+static int db_uint64_cmp(union DBKey key1, union DBKey key2, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint64_cmp);
@@ -1012,11 +1013,11 @@ static int db_uint64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_INT
+ * @see enum DBType#DB_INT
* @see #DBHasher
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-static uint64 db_int_hash(DBKey key, unsigned short maxlen)
+static uint64 db_int_hash(union DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int_hash);
@@ -1030,11 +1031,11 @@ static uint64 db_int_hash(DBKey key, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_UINT
+ * @see enum DBType#DB_UINT
* @see #DBHasher
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-static uint64 db_uint_hash(DBKey key, unsigned short maxlen)
+static uint64 db_uint_hash(union DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint_hash);
@@ -1046,11 +1047,11 @@ static uint64 db_uint_hash(DBKey key, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_STRING
+ * @see enum DBType#DB_STRING
* @see #DBHasher
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-static uint64 db_string_hash(DBKey key, unsigned short maxlen)
+static uint64 db_string_hash(union DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -1073,10 +1074,10 @@ static uint64 db_string_hash(DBKey key, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_ISTRING
- * @see #db_default_hash(DBType)
+ * @see enum DBType#DB_ISTRING
+ * @see #db_default_hash()
*/
-static uint64 db_istring_hash(DBKey key, unsigned short maxlen)
+static uint64 db_istring_hash(union DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -1101,11 +1102,11 @@ static uint64 db_istring_hash(DBKey key, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_INT64
+ * @see enum DBType#DB_INT64
* @see #DBHasher
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-static uint64 db_int64_hash(DBKey key, unsigned short maxlen)
+static uint64 db_int64_hash(union DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int64_hash);
@@ -1119,11 +1120,11 @@ static uint64 db_int64_hash(DBKey key, unsigned short maxlen)
* @param key Key to be hashed
* @param maxlen Maximum length of the key to hash
* @return hash of the key
- * @see DBType#DB_UINT64
+ * @see enum DBType#DB_UINT64
* @see #DBHasher
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-static uint64 db_uint64_hash(DBKey key, unsigned short maxlen)
+static uint64 db_uint64_hash(union DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint64_hash);
@@ -1137,9 +1138,9 @@ static uint64 db_uint64_hash(DBKey key, unsigned short maxlen)
* @param which What is being requested to be released
* @protected
* @see #DBReleaser
- * @see #db_default_releaser(DBType,DBOptions)
+ * @see #db_default_releaser()
*/
-static void db_release_nothing(DBKey key, DBData data, DBRelease which)
+static void db_release_nothing(union DBKey key, struct DBData data, enum DBReleaseOption which)
{
(void)key;(void)data;(void)which;//not used
DB_COUNTSTAT(db_release_nothing);
@@ -1152,13 +1153,14 @@ static void db_release_nothing(DBKey key, DBData data, DBRelease which)
* @param which What is being requested to be released
* @protected
* @see #DBReleaser
- * @see #db_default_release(DBType,DBOptions)
+ * @see #db_default_release()
*/
-static void db_release_key(DBKey key, DBData data, DBRelease which)
+static void db_release_key(union DBKey key, struct DBData data, enum DBReleaseOption which)
{
(void)data;//not used
DB_COUNTSTAT(db_release_key);
- if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer
+ if (which&DB_RELEASE_KEY)
+ aFree(key.mutstr); // FIXME: Ensure this is the right db type.
}
/**
@@ -1167,12 +1169,12 @@ static void db_release_key(DBKey key, DBData data, DBRelease which)
* @param data Data of the database entry
* @param which What is being requested to be released
* @protected
- * @see #DBData
- * @see #DBRelease
+ * @see struct DBData
+ * @see enum DBReleaseOption
* @see #DBReleaser
- * @see #db_default_release(DBType,DBOptions)
+ * @see #db_default_release()
*/
-static void db_release_data(DBKey key, DBData data, DBRelease which)
+static void db_release_data(union DBKey key, struct DBData data, enum DBReleaseOption which)
{
(void)key;//not used
DB_COUNTSTAT(db_release_data);
@@ -1188,16 +1190,17 @@ static void db_release_data(DBKey key, DBData data, DBRelease which)
* @param data Data of the database entry
* @param which What is being requested to be released
* @protected
- * @see #DBKey
- * @see #DBData
- * @see #DBRelease
+ * @see union DBKey
+ * @see struct DBData
+ * @see enum DBReleaseOption
* @see #DBReleaser
- * @see #db_default_release(DBType,DBOptions)
+ * @see #db_default_release()
*/
-static void db_release_both(DBKey key, DBData data, DBRelease which)
+static void db_release_both(union DBKey key, struct DBData data, enum DBReleaseOption which)
{
DB_COUNTSTAT(db_release_both);
- if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer
+ if (which&DB_RELEASE_KEY)
+ aFree(key.mutstr); // FIXME: Ensure this is the right db type.
if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) {
aFree(data.u.ptr);
data.u.ptr = NULL;
@@ -1245,11 +1248,11 @@ static void db_release_both(DBKey key, DBData data, DBRelease which)
* @param out_key Key of the entry
* @return Data of the entry
* @protected
- * @see DBIterator#first
+ * @see struct DBIterator#first()
*/
-DBData* dbit_obj_first(DBIterator* self, DBKey* out_key)
+struct DBData *dbit_obj_first(struct DBIterator *self, union DBKey *out_key)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
DB_COUNTSTAT(dbit_first);
// position before the first entry
@@ -1267,11 +1270,11 @@ DBData* dbit_obj_first(DBIterator* self, DBKey* out_key)
* @param out_key Key of the entry
* @return Data of the entry
* @protected
- * @see DBIterator#last
+ * @see struct DBIterator#last()
*/
-DBData* dbit_obj_last(DBIterator* self, DBKey* out_key)
+struct DBData *dbit_obj_last(struct DBIterator *self, union DBKey *out_key)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
DB_COUNTSTAT(dbit_last);
// position after the last entry
@@ -1289,14 +1292,14 @@ DBData* dbit_obj_last(DBIterator* self, DBKey* out_key)
* @param out_key Key of the entry
* @return Data of the entry
* @protected
- * @see DBIterator#next
+ * @see struct DBIterator#next()
*/
-DBData* dbit_obj_next(DBIterator* self, DBKey* out_key)
+struct DBData *dbit_obj_next(struct DBIterator *self, union DBKey *out_key)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
- DBNode *node;
- DBNode *parent;
- struct dbn fake;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
+ struct DBNode *node;
+ struct DBNode *parent;
+ struct DBNode fake;
DB_COUNTSTAT(dbit_next);
if( it->ht_index < 0 )
@@ -1348,7 +1351,7 @@ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key)
{// found next entry
it->node = node;
if( out_key )
- memcpy(out_key, &node->key, sizeof(DBKey));
+ memcpy(out_key, &node->key, sizeof(union DBKey));
return &node->data;
}
}
@@ -1365,14 +1368,14 @@ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key)
* @param out_key Key of the entry
* @return Data of the entry
* @protected
- * @see DBIterator#prev
+ * @see struct DBIterator#prev()
*/
-DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key)
+struct DBData *dbit_obj_prev(struct DBIterator *self, union DBKey *out_key)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
- DBNode *node;
- DBNode *parent;
- struct dbn fake;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
+ struct DBNode *node;
+ struct DBNode *parent;
+ struct DBNode fake;
DB_COUNTSTAT(dbit_prev);
if( it->ht_index >= HASH_SIZE )
@@ -1424,7 +1427,7 @@ DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key)
{// found previous entry
it->node = node;
if( out_key )
- memcpy(out_key, &node->key, sizeof(DBKey));
+ memcpy(out_key, &node->key, sizeof(union DBKey));
return &node->data;
}
}
@@ -1440,11 +1443,11 @@ DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key)
* @param self Iterator
* @return true if the entry exists
* @protected
- * @see DBIterator#exists
+ * @see struct DBIterator#exists()
*/
-bool dbit_obj_exists(DBIterator* self)
+bool dbit_obj_exists(struct DBIterator *self)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
DB_COUNTSTAT(dbit_exists);
return (it->node && !it->node->deleted);
@@ -1452,32 +1455,34 @@ bool dbit_obj_exists(DBIterator* self)
/**
* Removes the current entry from the database.
- * NOTE: {@link DBIterator#exists} will return false until another entry
- * is fetched
+ *
+ * NOTE: struct DBIterator#exists() will return false until another entry is
+ * fetched.
+ *
* Puts data of the removed entry in out_data, if out_data is not NULL (unless data has been released)
* @param self Iterator
* @param out_data Data of the removed entry.
* @return 1 if entry was removed, 0 otherwise
* @protected
- * @see DBMap#remove
- * @see DBIterator#remove
+ * @see struct DBMap#remove()
+ * @see struct DBIterator#remove()
*/
-int dbit_obj_remove(DBIterator* self, DBData *out_data)
+int dbit_obj_remove(struct DBIterator *self, struct DBData *out_data)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
- DBNode *node;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
+ struct DBNode *node;
int retval = 0;
DB_COUNTSTAT(dbit_remove);
node = it->node;
if( node && !node->deleted )
{
- DBMap_impl* db = it->db;
+ struct DBMap_impl *db = it->db;
if( db->cache == node )
db->cache = NULL;
db->release(node->key, node->data, DB_RELEASE_DATA);
if( out_data )
- memcpy(out_data, &node->data, sizeof(DBData));
+ memcpy(out_data, &node->data, sizeof(struct DBData));
retval = 1;
db_free_add(db, node, &db->ht[it->ht_index]);
}
@@ -1489,9 +1494,9 @@ int dbit_obj_remove(DBIterator* self, DBData *out_data)
* @param self Iterator
* @protected
*/
-void dbit_obj_destroy(DBIterator* self)
+void dbit_obj_destroy(struct DBIterator *self)
{
- DBIterator_impl* it = (DBIterator_impl*)self;
+ struct DBIterator_impl *it = (struct DBIterator_impl *)self;
DB_COUNTSTAT(dbit_destroy);
// unlock the database
@@ -1509,10 +1514,10 @@ void dbit_obj_destroy(DBIterator* self)
* @return New iterator
* @protected
*/
-static DBIterator* db_obj_iterator(DBMap* self)
+static struct DBIterator *db_obj_iterator(struct DBMap *self)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBIterator_impl* it;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBIterator_impl *it;
DB_COUNTSTAT(db_iterator);
it = ers_alloc(db_iterator_ers, struct DBIterator_impl);
@@ -1539,12 +1544,12 @@ static DBIterator* db_obj_iterator(DBMap* self)
* @param key Key that identifies the entry
* @return true is the entry exists
* @protected
- * @see DBMap#exists
+ * @see struct DBMap#exists()
*/
-static bool db_obj_exists(DBMap* self, DBKey key)
+static bool db_obj_exists(struct DBMap *self, union DBKey key)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBNode *node;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBNode *node;
bool found = false;
DB_COUNTSTAT(db_exists);
@@ -1589,13 +1594,13 @@ static bool db_obj_exists(DBMap* self, DBKey key)
* @param key Key that identifies the entry
* @return Data of the entry or NULL if not found
* @protected
- * @see DBMap#get
+ * @see struct DBMap#get()
*/
-static DBData* db_obj_get(DBMap* self, DBKey key)
+static struct DBData *db_obj_get(struct DBMap *self, union DBKey key)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBNode *node;
- DBData *data = NULL;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBNode *node;
+ struct DBData *data = NULL;
DB_COUNTSTAT(db_get);
if (db == NULL) return NULL; // nullpo candidate
@@ -1648,14 +1653,14 @@ static DBData* db_obj_get(DBMap* self, DBKey key)
* @param ... Extra arguments for match
* @return The number of entries that matched
* @protected
- * @see DBMap#vgetall
+ * @see struct DBMap#vgetall()
*/
-static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, va_list args)
+static unsigned int db_obj_vgetall(struct DBMap *self, struct DBData **buf, unsigned int max, DBMatcher match, va_list args)
{
- DBMap_impl* db = (DBMap_impl*)self;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
unsigned int i;
- DBNode *node;
- DBNode *parent;
+ struct DBNode *node;
+ struct DBNode *parent;
unsigned int ret = 0;
DB_COUNTSTAT(db_vgetall);
@@ -1705,7 +1710,8 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max,
}
/**
- * Just calls {@link DBMap#vgetall}.
+ * Just calls struct DBMap#vgetall().
+ *
* Get the data of the entries matched by <code>match</code>.
* It puts a maximum of <code>max</code> entries into <code>buf</code>.
* If <code>buf</code> is NULL, it only counts the matches.
@@ -1719,10 +1725,10 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max,
* @param ... Extra arguments for match
* @return The number of entries that matched
* @protected
- * @see DBMap#vgetall
- * @see DBMap#getall
+ * @see struct DBMap#vgetall()
+ * @see struct DBMap#getall()
*/
-static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, ...)
+static unsigned int db_obj_getall(struct DBMap *self, struct DBData **buf, unsigned int max, DBMatcher match, ...)
{
va_list args;
unsigned int ret;
@@ -1746,16 +1752,16 @@ static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, D
* @param args Extra arguments for create
* @return Data of the entry
* @protected
- * @see DBMap#vensure
+ * @see struct DBMap#vensure()
*/
-static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args)
+static struct DBData *db_obj_vensure(struct DBMap *self, union DBKey key, DBCreateData create, va_list args)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBNode *node;
- DBNode *parent = NULL;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBNode *node;
+ struct DBNode *parent = NULL;
unsigned int hash;
int c = 0;
- DBData *data = NULL;
+ struct DBData *data = NULL;
DB_COUNTSTAT(db_vensure);
if (db == NULL) return NULL; // nullpo candidate
@@ -1795,7 +1801,7 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li
return NULL;
}
DB_COUNTSTAT(db_node_alloc);
- node = ers_alloc(db->nodes, struct dbn);
+ node = ers_alloc(db->nodes, struct DBNode);
node->left = NULL;
node->right = NULL;
node->deleted = 0;
@@ -1835,7 +1841,8 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li
}
/**
- * Just calls {@link DBMap#vensure}.
+ * Just calls struct DBMap#vensure().
+ *
* Get the data of the entry identified by the key.
* If the entry does not exist, an entry is added with the data returned by
* <code>create</code>.
@@ -1845,13 +1852,13 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li
* @param ... Extra arguments for create
* @return Data of the entry
* @protected
- * @see DBMap#vensure
- * @see DBMap#ensure
+ * @see struct DBMap#vensure()
+ * @see struct DBMap#ensure()
*/
-static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...)
+static struct DBData *db_obj_ensure(struct DBMap *self, union DBKey key, DBCreateData create, ...)
{
va_list args;
- DBData *ret = NULL;
+ struct DBData *ret = NULL;
DB_COUNTSTAT(db_ensure);
if (self == NULL) return NULL; // nullpo candidate
@@ -1873,15 +1880,15 @@ static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...)
* @return 1 if if the entry already exists, 0 otherwise
* @protected
* @see #db_malloc_dbn(void)
- * @see DBMap#put
+ * @see struct DBMap#put()
* FIXME: If this method fails shouldn't it return another value?
* Other functions rely on this to know if they were able to put something [Panikon]
*/
-static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data)
+static int db_obj_put(struct DBMap *self, union DBKey key, struct DBData data, struct DBData *out_data)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBNode *node;
- DBNode *parent = NULL;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBNode *node;
+ struct DBNode *parent = NULL;
int c = 0, retval = 0;
unsigned int hash;
@@ -1934,7 +1941,7 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data)
// allocate a new node if necessary
if (node == NULL) {
DB_COUNTSTAT(db_node_alloc);
- node = ers_alloc(db->nodes, struct dbn);
+ node = ers_alloc(db->nodes, struct DBNode);
node->left = NULL;
node->right = NULL;
node->deleted = 0;
@@ -1973,19 +1980,19 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data)
/**
* Remove an entry from the database.
* Puts the previous data in out_data, if out_data is not NULL. (unless data has been released)
- * NOTE: The key (of the database) is released in {@link #db_free_add(DBMap_impl*,DBNode*,DBNode **)}.
+ * NOTE: The key (of the database) is released in #db_free_add().
* @param self Interface of the database
* @param key Key that identifies the entry
* @param out_data Previous data if the entry exists
* @return 1 if if the entry already exists, 0 otherwise
* @protected
- * @see #db_free_add(DBMap_impl*,DBNode*,DBNode **)
- * @see DBMap#remove
+ * @see #db_free_add()
+ * @see struct DBMap#remove()
*/
-static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data)
+static int db_obj_remove(struct DBMap *self, union DBKey key, struct DBData *out_data)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBNode *node;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ struct DBNode *node;
unsigned int hash;
int retval = 0;
@@ -2035,15 +2042,15 @@ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data)
* @param args Extra arguments for func
* @return Sum of the values returned by func
* @protected
- * @see DBMap#vforeach
+ * @see struct DBMap#vforeach()
*/
-static int db_obj_vforeach(DBMap* self, DBApply func, va_list args)
+static int db_obj_vforeach(struct DBMap *self, DBApply func, va_list args)
{
- DBMap_impl* db = (DBMap_impl*)self;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
unsigned int i;
int sum = 0;
- DBNode *node;
- DBNode *parent;
+ struct DBNode *node;
+ struct DBNode *parent;
DB_COUNTSTAT(db_vforeach);
if (db == NULL) return 0; // nullpo candidate
@@ -2086,7 +2093,8 @@ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args)
}
/**
- * Just calls {@link DBMap#vforeach}.
+ * Just calls struct DBMap#vforeach().
+ *
* Apply <code>func</code> to every entry in the database.
* Returns the sum of values returned by func.
* @param self Interface of the database
@@ -2094,10 +2102,10 @@ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args)
* @param ... Extra arguments for func
* @return Sum of the values returned by func
* @protected
- * @see DBMap#vforeach
- * @see DBMap#foreach
+ * @see struct DBMap#vforeach()
+ * @see struct DBMap#foreach()
*/
-static int db_obj_foreach(DBMap* self, DBApply func, ...)
+static int db_obj_foreach(struct DBMap *self, DBApply func, ...)
{
va_list args;
int ret;
@@ -2121,15 +2129,15 @@ static int db_obj_foreach(DBMap* self, DBApply func, ...)
* @param args Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vclear
+ * @see struct DBMap#vclear()
*/
-static int db_obj_vclear(DBMap* self, DBApply func, va_list args)
+static int db_obj_vclear(struct DBMap *self, DBApply func, va_list args)
{
- DBMap_impl* db = (DBMap_impl*)self;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
int sum = 0;
unsigned int i;
- DBNode *node;
- DBNode *parent;
+ struct DBNode *node;
+ struct DBNode *parent;
DB_COUNTSTAT(db_vclear);
if (db == NULL) return 0; // nullpo candidate
@@ -2182,7 +2190,8 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args)
}
/**
- * Just calls {@link DBMap#vclear}.
+ * Just calls struct DBMap#vclear().
+ *
* Removes all entries from the database.
* Before deleting an entry, func is applied to it.
* Releases the key and the data.
@@ -2194,10 +2203,10 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args)
* @param ... Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vclear
- * @see DBMap#clear
+ * @see struct DBMap#vclear()
+ * @see struct DBMap#clear()
*/
-static int db_obj_clear(DBMap* self, DBApply func, ...)
+static int db_obj_clear(struct DBMap *self, DBApply func, ...)
{
va_list args;
int ret;
@@ -2222,11 +2231,11 @@ static int db_obj_clear(DBMap* self, DBApply func, ...)
* @param args Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vdestroy
+ * @see struct DBMap#vdestroy()
*/
-static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
+static int db_obj_vdestroy(struct DBMap *self, DBApply func, va_list args)
{
- DBMap_impl* db = (DBMap_impl*)self;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
int sum;
DB_COUNTSTAT(db_vdestroy);
@@ -2265,7 +2274,7 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
}
/**
- * Just calls {@link DBMap#db_vdestroy}.
+ * Just calls struct DBMap#db_vdestroy().
* Finalize the database, feeing all the memory it uses.
* Before deleting an entry, func is applied to it.
* Releases the key and the data.
@@ -2277,10 +2286,10 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
* @param ... Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vdestroy
- * @see DBMap#destroy
+ * @see struct DBMap#vdestroy()
+ * @see struct DBMap#destroy()
*/
-static int db_obj_destroy(DBMap* self, DBApply func, ...)
+static int db_obj_destroy(struct DBMap *self, DBApply func, ...)
{
va_list args;
int ret;
@@ -2299,12 +2308,12 @@ static int db_obj_destroy(DBMap* self, DBApply func, ...)
* @param self Interface of the database
* @return Size of the database
* @protected
- * @see DBMap_impl#item_count
- * @see DBMap#size
+ * @see struct DBMap_impl#item_count
+ * @see struct DBMap#size()
*/
-static unsigned int db_obj_size(DBMap* self)
+static unsigned int db_obj_size(struct DBMap *self)
{
- DBMap_impl* db = (DBMap_impl*)self;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
unsigned int item_count;
DB_COUNTSTAT(db_size);
@@ -2322,16 +2331,17 @@ static unsigned int db_obj_size(DBMap* self)
* @param self Interface of the database
* @return Type of the database
* @protected
- * @see DBMap_impl#type
- * @see DBMap#type
+ * @see struct DBMap_impl#type
+ * @see struct DBMap#type()
*/
-static DBType db_obj_type(DBMap* self)
+static enum DBType db_obj_type(struct DBMap *self)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBType type;
+ struct DBMap_impl *db = (struct DBMap_impl *)self;
+ enum DBType type;
DB_COUNTSTAT(db_type);
- if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return?
+ if (db == NULL)
+ return (enum DBType)-1; // nullpo candidate - TODO what should this return?
db_free_lock(db);
type = db->type;
@@ -2345,13 +2355,13 @@ static DBType db_obj_type(DBMap* self)
* @param self Interface of the database
* @return Options of the database
* @protected
- * @see DBMap_impl#options
- * @see DBMap#options
+ * @see struct DBMap_impl#options
+ * @see struct DBMap#options()
*/
-static DBOptions db_obj_options(DBMap* self)
+static enum DBOptions db_obj_options(struct DBMap *self)
{
- DBMap_impl* db = (DBMap_impl*)self;
- DBOptions options;
+ struct DBMap_impl* db = (struct DBMap_impl *)self;
+ enum DBOptions options;
DB_COUNTSTAT(db_options);
if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return?
@@ -2371,17 +2381,17 @@ static DBOptions db_obj_options(DBMap* self)
* db_default_release - Get the default releaser for a type of database with the specified options.
* db_custom_release - Get a releaser that behaves a certain way.
* db_alloc - Allocate a new database.
- * db_i2key - Manual cast from 'int' to 'DBKey'.
- * db_ui2key - Manual cast from 'unsigned int' to 'DBKey'.
- * db_str2key - Manual cast from 'unsigned char *' to 'DBKey'.
- * db_i642key - Manual cast from 'int64' to 'DBKey'.
- * db_ui642key - Manual cast from 'uin64' to 'DBKey'.
- * db_i2data - Manual cast from 'int' to 'DBData'.
- * db_ui2data - Manual cast from 'unsigned int' to 'DBData'.
- * db_ptr2data - Manual cast from 'void*' to 'DBData'.
- * db_data2i - Gets 'int' value from 'DBData'.
- * db_data2ui - Gets 'unsigned int' value from 'DBData'.
- * db_data2ptr - Gets 'void*' value from 'DBData'.
+ * db_i2key - Manual cast from `int` to `union DBKey`.
+ * db_ui2key - Manual cast from `unsigned int` to `union DBKey`.
+ * db_str2key - Manual cast from `unsigned char *` to `union DBKey`.
+ * db_i642key - Manual cast from `int64` to `union DBKey`.
+ * db_ui642key - Manual cast from `uin64` to `union DBKey`.
+ * db_i2data - Manual cast from `int` to `struct DBData`.
+ * db_ui2data - Manual cast from `unsigned int` to `struct DBData`.
+ * db_ptr2data - Manual cast from `void*` to `struct DBData`.
+ * db_data2i - Gets `int` value from `struct DBData`.
+ * db_data2ui - Gets `unsigned int` value from `struct DBData`.
+ * db_data2ptr - Gets `void*` value from `struct DBData`.
* db_init - Initializes the database system.
* db_final - Finalizes the database system.
\*****************************************************************************/
@@ -2394,10 +2404,10 @@ static DBOptions db_obj_options(DBMap* self)
* @param options Original options of the database
* @return Fixed options of the database
* @private
- * @see #db_default_release(DBType,DBOptions)
- * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short)
+ * @see #db_default_release()
+ * @see #db_alloc()
*/
-DBOptions db_fix_options(DBType type, DBOptions options)
+enum DBOptions db_fix_options(enum DBType type, enum DBOptions options)
{
DB_COUNTSTAT(db_fix_options);
switch (type) {
@@ -2405,10 +2415,11 @@ DBOptions db_fix_options(DBType type, DBOptions options)
case DB_UINT:
case DB_INT64:
case DB_UINT64: // Numeric database, do nothing with the keys
- return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY));
+ return (enum DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY));
default:
ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options);
+ FALLTHROUGH
case DB_STRING:
case DB_ISTRING: // String databases, no fix required
return options;
@@ -2420,14 +2431,14 @@ DBOptions db_fix_options(DBType type, DBOptions options)
* @param type Type of database
* @return Comparator for the type of database or NULL if unknown database
* @public
- * @see #db_int_cmp(DBKey,DBKey,unsigned short)
- * @see #db_uint_cmp(DBKey,DBKey,unsigned short)
- * @see #db_string_cmp(DBKey,DBKey,unsigned short)
- * @see #db_istring_cmp(DBKey,DBKey,unsigned short)
- * @see #db_int64_cmp(DBKey,DBKey,unsigned short)
- * @see #db_uint64_cmp(DBKey,DBKey,unsigned short)
+ * @see #db_int_cmp()
+ * @see #db_uint_cmp()
+ * @see #db_string_cmp()
+ * @see #db_istring_cmp()
+ * @see #db_int64_cmp()
+ * @see #db_uint64_cmp()
*/
-DBComparator db_default_cmp(DBType type)
+DBComparator db_default_cmp(enum DBType type)
{
DB_COUNTSTAT(db_default_cmp);
switch (type) {
@@ -2448,14 +2459,14 @@ DBComparator db_default_cmp(DBType type)
* @param type Type of database
* @return Hasher of the type of database or NULL if unknown database
* @public
- * @see #db_int_hash(DBKey,unsigned short)
- * @see #db_uint_hash(DBKey,unsigned short)
- * @see #db_string_hash(DBKey,unsigned short)
- * @see #db_istring_hash(DBKey,unsigned short)
- * @see #db_int64_hash(DBKey,unsigned short)
- * @see #db_uint64_hash(DBKey,unsigned short)
+ * @see #db_int_hash()
+ * @see #db_uint_hash()
+ * @see #db_string_hash()
+ * @see #db_istring_hash()
+ * @see #db_int64_hash()
+ * @see #db_uint64_hash()
*/
-DBHasher db_default_hash(DBType type)
+DBHasher db_default_hash(enum DBType type)
{
DB_COUNTSTAT(db_default_hash);
switch (type) {
@@ -2474,19 +2485,21 @@ DBHasher db_default_hash(DBType type)
/**
* Returns the default releaser for the specified type of database with the
* specified options.
- * NOTE: the options are fixed with {@link #db_fix_options(DBType,DBOptions)}
- * before choosing the releaser.
+ *
+ * NOTE: the options are fixed with #db_fix_options() before choosing the
+ * releaser.
+ *
* @param type Type of database
* @param options Options of the database
* @return Default releaser for the type of database with the specified options
* @public
- * @see #db_release_nothing(DBKey,DBData,DBRelease)
- * @see #db_release_key(DBKey,DBData,DBRelease)
- * @see #db_release_data(DBKey,DBData,DBRelease)
- * @see #db_release_both(DBKey,DBData,DBRelease)
- * @see #db_custom_release(DBRelease)
+ * @see #db_release_nothing()
+ * @see #db_release_key()
+ * @see #db_release_data()
+ * @see #db_release_both()
+ * @see #db_custom_release()
*/
-DBReleaser db_default_release(DBType type, DBOptions options)
+DBReleaser db_default_release(enum DBType type, enum DBOptions options)
{
DB_COUNTSTAT(db_default_release);
options = DB->fix_options(type, options);
@@ -2505,13 +2518,13 @@ DBReleaser db_default_release(DBType type, DBOptions options)
* @param which Options that specified what the releaser releases
* @return Releaser for the specified release options
* @public
- * @see #db_release_nothing(DBKey,DBData,DBRelease)
- * @see #db_release_key(DBKey,DBData,DBRelease)
- * @see #db_release_data(DBKey,DBData,DBRelease)
- * @see #db_release_both(DBKey,DBData,DBRelease)
- * @see #db_default_release(DBType,DBOptions)
+ * @see #db_release_nothing()
+ * @see #db_release_key()
+ * @see #db_release_data()
+ * @see #db_release_both()
+ * @see #db_default_release()
*/
-DBReleaser db_custom_release(DBRelease which)
+DBReleaser db_custom_release(enum DBReleaseOption which)
{
DB_COUNTSTAT(db_custom_release);
switch (which) {
@@ -2527,8 +2540,10 @@ DBReleaser db_custom_release(DBRelease which)
/**
* Allocate a new database of the specified type.
- * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)}
- * before creating the database.
+ *
+ * NOTE: the options are fixed by #db_fix_options() before creating the
+ * database.
+ *
* @param file File where the database is being allocated
* @param line Line of the file where the database is being allocated
* @param type Type of database
@@ -2537,11 +2552,12 @@ DBReleaser db_custom_release(DBRelease which)
* databases. If 0, the maximum number of maxlen is used (64K).
* @return The interface of the database
* @public
- * @see #DBMap_impl
- * @see #db_fix_options(DBType,DBOptions)
+ * @see struct DBMap_impl
+ * @see #db_fix_options()
*/
-DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOptions options, unsigned short maxlen) {
- DBMap_impl* db;
+struct DBMap *db_alloc(const char *file, const char *func, int line, enum DBType type, enum DBOptions options, unsigned short maxlen)
+{
+ struct DBMap_impl *db;
unsigned int i;
char ers_name[50];
@@ -2588,7 +2604,7 @@ DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOpt
db->free_lock = 0;
/* Other */
snprintf(ers_name, 50, "db_alloc:nodes:%s:%s:%d",func,file,line);
- db->nodes = ers_new(sizeof(struct dbn),ers_name,ERS_OPT_WAIT|ERS_OPT_FREE_NAME|ERS_OPT_CLEAN);
+ db->nodes = ers_new(sizeof(struct DBNode),ers_name,ERS_OPT_WAIT|ERS_OPT_FREE_NAME|ERS_OPT_CLEAN);
db->cmp = DB->default_cmp(type);
db->hash = DB->default_hash(type);
db->release = DB->default_release(type, options);
@@ -2613,9 +2629,9 @@ DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOpt
* @return The key as a DBKey union
* @public
*/
-DBKey db_i2key(int key)
+union DBKey db_i2key(int key)
{
- DBKey ret;
+ union DBKey ret;
DB_COUNTSTAT(db_i2key);
ret.i = key;
@@ -2628,9 +2644,9 @@ DBKey db_i2key(int key)
* @return The key as a DBKey union
* @public
*/
-DBKey db_ui2key(unsigned int key)
+union DBKey db_ui2key(unsigned int key)
{
- DBKey ret;
+ union DBKey ret;
DB_COUNTSTAT(db_ui2key);
ret.ui = key;
@@ -2643,9 +2659,9 @@ DBKey db_ui2key(unsigned int key)
* @return The key as a DBKey union
* @public
*/
-DBKey db_str2key(const char *key)
+union DBKey db_str2key(const char *key)
{
- DBKey ret;
+ union DBKey ret;
DB_COUNTSTAT(db_str2key);
ret.str = key;
@@ -2658,9 +2674,9 @@ DBKey db_str2key(const char *key)
* @return The key as a DBKey union
* @public
*/
-DBKey db_i642key(int64 key)
+union DBKey db_i642key(int64 key)
{
- DBKey ret;
+ union DBKey ret;
DB_COUNTSTAT(db_i642key);
ret.i64 = key;
@@ -2673,9 +2689,9 @@ DBKey db_i642key(int64 key)
* @return The key as a DBKey union
* @public
*/
-DBKey db_ui642key(uint64 key)
+union DBKey db_ui642key(uint64 key)
{
- DBKey ret;
+ union DBKey ret;
DB_COUNTSTAT(db_ui642key);
ret.ui64 = key;
@@ -2688,9 +2704,9 @@ DBKey db_ui642key(uint64 key)
* @return The data as a DBData struct
* @public
*/
-DBData db_i2data(int data)
+struct DBData db_i2data(int data)
{
- DBData ret;
+ struct DBData ret;
DB_COUNTSTAT(db_i2data);
ret.type = DB_DATA_INT;
@@ -2704,9 +2720,9 @@ DBData db_i2data(int data)
* @return The data as a DBData struct
* @public
*/
-DBData db_ui2data(unsigned int data)
+struct DBData db_ui2data(unsigned int data)
{
- DBData ret;
+ struct DBData ret;
DB_COUNTSTAT(db_ui2data);
ret.type = DB_DATA_UINT;
@@ -2720,9 +2736,9 @@ DBData db_ui2data(unsigned int data)
* @return The data as a DBData struct
* @public
*/
-DBData db_ptr2data(void *data)
+struct DBData db_ptr2data(void *data)
{
- DBData ret;
+ struct DBData ret;
DB_COUNTSTAT(db_ptr2data);
ret.type = DB_DATA_PTR;
@@ -2737,7 +2753,7 @@ DBData db_ptr2data(void *data)
* @return Integer value of the data.
* @public
*/
-int db_data2i(DBData *data)
+int db_data2i(struct DBData *data)
{
DB_COUNTSTAT(db_data2i);
if (data && DB_DATA_INT == data->type)
@@ -2752,7 +2768,7 @@ int db_data2i(DBData *data)
* @return Unsigned int value of the data.
* @public
*/
-unsigned int db_data2ui(DBData *data)
+unsigned int db_data2ui(struct DBData *data)
{
DB_COUNTSTAT(db_data2ui);
if (data && DB_DATA_UINT == data->type)
@@ -2767,7 +2783,7 @@ unsigned int db_data2ui(DBData *data)
* @return Void* value of the data.
* @public
*/
-void* db_data2ptr(DBData *data)
+void *db_data2ptr(struct DBData *data)
{
DB_COUNTSTAT(db_data2ptr);
if (data && DB_DATA_PTR == data->type)
@@ -2780,7 +2796,8 @@ void* db_data2ptr(DBData *data)
* @public
* @see #db_final(void)
*/
-void db_init(void) {
+void db_init(void)
+{
db_iterator_ers = ers_new(sizeof(struct DBIterator_impl),"db.c::db_iterator_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
db_alloc_ers = ers_new(sizeof(struct DBMap_impl),"db.c::db_alloc_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
ers_chunk_size(db_alloc_ers, 50);
@@ -2892,7 +2909,7 @@ void db_final(void)
}
// Link DB System - jAthena
-void linkdb_insert( struct linkdb_node** head, void *key, void* data)
+void linkdb_insert(struct linkdb_node **head, void *key, void *data)
{
struct linkdb_node *node;
if( head == NULL ) return ;
@@ -2913,7 +2930,8 @@ void linkdb_insert( struct linkdb_node** head, void *key, void* data)
node->data = data;
}
-void linkdb_vforeach( struct linkdb_node** head, LinkDBFunc func, va_list ap) {
+void linkdb_vforeach(struct linkdb_node **head, LinkDBFunc func, va_list ap)
+{
struct linkdb_node *node;
if( head == NULL ) return;
node = *head;
@@ -2926,14 +2944,15 @@ void linkdb_vforeach( struct linkdb_node** head, LinkDBFunc func, va_list ap) {
}
}
-void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ...) {
+void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...)
+{
va_list ap;
va_start(ap, func);
linkdb_vforeach(head, func, ap);
va_end(ap);
}
-void* linkdb_search( struct linkdb_node** head, void *key)
+void* linkdb_search(struct linkdb_node **head, void *key)
{
int n = 0;
struct linkdb_node *node;
@@ -2958,7 +2977,7 @@ void* linkdb_search( struct linkdb_node** head, void *key)
return NULL;
}
-void* linkdb_erase( struct linkdb_node** head, void *key)
+void* linkdb_erase(struct linkdb_node **head, void *key)
{
struct linkdb_node *node;
if( head == NULL ) return NULL;
@@ -2980,7 +2999,7 @@ void* linkdb_erase( struct linkdb_node** head, void *key)
return NULL;
}
-void linkdb_replace( struct linkdb_node** head, void *key, void *data )
+void linkdb_replace(struct linkdb_node **head, void *key, void *data)
{
int n = 0;
struct linkdb_node *node;
@@ -3007,7 +3026,7 @@ void linkdb_replace( struct linkdb_node** head, void *key, void *data )
linkdb_insert( head, key, data );
}
-void linkdb_final( struct linkdb_node** head )
+void linkdb_final(struct linkdb_node **head)
{
struct linkdb_node *node, *node2;
if( head == NULL ) return ;
@@ -3019,7 +3038,9 @@ void linkdb_final( struct linkdb_node** head )
}
*head = NULL;
}
-void db_defaults(void) {
+
+void db_defaults(void)
+{
DB = &DB_s;
DB->alloc = db_alloc;
DB->custom_release = db_custom_release;
@@ -3040,5 +3061,4 @@ void db_defaults(void) {
DB->ui2key = db_ui2key;
DB->i642key = db_i642key;
DB->ui642key = db_ui642key;
-
}
diff --git a/src/common/db.h b/src/common/db.h
index b73970947..2918e5acb 100644
--- a/src/common/db.h
+++ b/src/common/db.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -43,8 +43,7 @@
* 2007/11/09 - Added an iterator to the database. *
* 2.1 (Athena build #???#) - Portability fix *
* - Fixed the portability of casting to union and added the functions *
- * {@link DBMap#ensure(DBMap,DBKey,DBCreateData,...)} and *
- * {@link DBMap#clear(DBMap,DBApply,...)}. *
+ * struct DBMap#ensure() and struct DBMap#clear(). *
* 2.0 (Athena build 4859) - Transition version *
* - Almost everything recoded with a strategy similar to objects, *
* database structure is maintained. *
@@ -64,41 +63,42 @@
#include <stdarg.h>
-/*****************************************************************************\
+/*****************************************************************************
* (1) Section with public typedefs, enums, unions, structures and defines. *
- * DBRelease - Enumeration of release options. *
- * DBType - Enumeration of database types. *
- * DBOptions - Bitfield enumeration of database options. *
- * DBKey - Union of used key types. *
- * DBDataType - Enumeration of data types. *
- * DBData - Struct for used data types. *
- * DBApply - Format of functions applied to the databases. *
- * DBMatcher - Format of matchers used in DBMap::getall. *
- * DBComparator - Format of the comparators used by the databases. *
- * DBHasher - Format of the hashers used by the databases. *
- * DBReleaser - Format of the releasers used by the databases. *
- * DBIterator - Database iterator. *
- * DBMap - Database interface. *
-\*****************************************************************************/
+ * enum DBReleaseOption - Enumeration of release options. *
+ * enum DBType - Enumeration of database types. *
+ * enum DBOptions - Bitfield enumeration of database options. *
+ * union DBKey - Union of used key types. *
+ * enum DBDataType - Enumeration of data types. *
+ * struct DBData - Struct for used data types. *
+ * DBApply - Format of functions applied to the databases. *
+ * DBMatcher - Format of matchers used in struct DBMap#getall(). *
+ * DBComparator - Format of the comparators used by the databases. *
+ * DBHasher - Format of the hashers used by the databases. *
+ * DBReleaser - Format of the releasers used by the databases. *
+ * struct DBIterator - Database iterator. *
+ * struct DBMap - Database interface. *
+ *****************************************************************************/
/**
* Bitfield with what should be released by the releaser function (if the
* function supports it).
* @public
* @see #DBReleaser
- * @see #db_custom_release(DBRelease)
+ * @see #db_custom_release()
*/
-typedef enum DBRelease {
+enum DBReleaseOption {
DB_RELEASE_NOTHING = 0x0,
DB_RELEASE_KEY = 0x1,
DB_RELEASE_DATA = 0x2,
DB_RELEASE_BOTH = DB_RELEASE_KEY|DB_RELEASE_DATA,
-} DBRelease;
+};
/**
* Supported types of database.
- * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the
- * types of databases.
+ *
+ * See #db_fix_options() for restrictions of the types of databases.
+ *
* @param DB_INT Uses int's for keys
* @param DB_UINT Uses unsigned int's for keys
* @param DB_STRING Uses strings for keys.
@@ -106,27 +106,28 @@ typedef enum DBRelease {
* @param DB_INT64 Uses int64's for keys
* @param DB_UINT64 Uses uint64's for keys
* @public
- * @see #DBOptions
- * @see #DBKey
- * @see #db_fix_options(DBType,DBOptions)
- * @see #db_default_cmp(DBType)
- * @see #db_default_hash(DBType)
- * @see #db_default_release(DBType,DBOptions)
- * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short)
- */
-typedef enum DBType {
+ * @see enum DBOptions
+ * @see union DBKey
+ * @see #db_fix_options()
+ * @see #db_default_cmp()
+ * @see #db_default_hash()
+ * @see #db_default_release()
+ * @see #db_alloc()
+ */
+enum DBType {
DB_INT,
DB_UINT,
DB_STRING,
DB_ISTRING,
DB_INT64,
DB_UINT64,
-} DBType;
+};
/**
* Bitfield of options that define the behavior of the database.
- * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the
- * types of databases.
+ *
+ * See #db_fix_options() for restrictions of the types of databases.
+ *
* @param DB_OPT_BASE Base options: does not duplicate keys, releases nothing
* and does not allow NULL keys or NULL data.
* @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY
@@ -134,17 +135,17 @@ typedef enum DBType {
* @param DB_OPT_RELEASE_KEY Releases the key.
* @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed
* from the database.
- * WARNING: for functions that return the data (like DBMap::remove),
+ * WARNING: for functions that return the data (like struct DBMap#remove()),
* a dangling pointer will be returned.
* @param DB_OPT_RELEASE_BOTH Releases both key and data.
* @param DB_OPT_ALLOW_NULL_KEY Allow NULL keys in the database.
* @param DB_OPT_ALLOW_NULL_DATA Allow NULL data in the database.
* @public
- * @see #db_fix_options(DBType,DBOptions)
- * @see #db_default_release(DBType,DBOptions)
- * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short)
+ * @see #db_fix_options()
+ * @see #db_default_release()
+ * @see #db_alloc()
*/
-typedef enum DBOptions {
+enum DBOptions {
DB_OPT_BASE = 0x00,
DB_OPT_DUP_KEY = 0x01,
DB_OPT_RELEASE_KEY = 0x02,
@@ -152,7 +153,7 @@ typedef enum DBOptions {
DB_OPT_RELEASE_BOTH = DB_OPT_RELEASE_KEY|DB_OPT_RELEASE_DATA,
DB_OPT_ALLOW_NULL_KEY = 0x08,
DB_OPT_ALLOW_NULL_DATA = 0x10,
-} DBOptions;
+};
/**
* Union of key types used by the database.
@@ -160,18 +161,19 @@ typedef enum DBOptions {
* @param ui Type of key for DB_UINT databases
* @param str Type of key for DB_STRING and DB_ISTRING databases
* @public
- * @see #DBType
- * @see DBMap#get
- * @see DBMap#put
- * @see DBMap#remove
+ * @see enum DBType
+ * @see struct DBMap#get()
+ * @see struct DBMap#put()
+ * @see struct DBMap#remove()
*/
-typedef union DBKey {
+union DBKey {
int i;
unsigned int ui;
const char *str;
+ char *mutstr;
int64 i64;
uint64 ui64;
-} DBKey;
+};
/**
* Supported types of database data.
@@ -179,13 +181,13 @@ typedef union DBKey {
* @param DB_DATA_UINT Uses unsigned ints for data.
* @param DB_DATA_PTR Uses void pointers for data.
* @public
- * @see #DBData
+ * @see struct DBData
*/
-typedef enum DBDataType {
+enum DBDataType {
DB_DATA_INT,
DB_DATA_UINT,
DB_DATA_PTR,
-} DBDataType;
+};
/**
* Struct for data types used by the database.
@@ -196,14 +198,14 @@ typedef enum DBDataType {
* @param u.ptr Data of void* type
* @public
*/
-typedef struct DBData {
- DBDataType type;
+struct DBData {
+ enum DBDataType type;
union {
int i;
unsigned int ui;
void *ptr;
} u;
-} DBData;
+};
/**
* Format of functions that create the data for the key when the entry doesn't
@@ -212,10 +214,10 @@ typedef struct DBData {
* @param args Extra arguments of the function
* @return Data identified by the key to be put in the database
* @public
- * @see DBMap#vensure
- * @see DBMap#ensure
+ * @see struct DBMap#vensure()
+ * @see struct DBMap#ensure()
*/
-typedef DBData (*DBCreateData)(DBKey key, va_list args);
+typedef struct DBData (*DBCreateData)(union DBKey key, va_list args);
/**
* Format of functions to be applied to an unspecified quantity of entries of
@@ -227,12 +229,12 @@ typedef DBData (*DBCreateData)(DBKey key, va_list args);
* @param args Extra arguments of the function
* @return Value to be added up by the function that is applying this
* @public
- * @see DBMap#vforeach
- * @see DBMap#foreach
- * @see DBMap#vdestroy
- * @see DBMap#destroy
+ * @see struct DBMap#vforeach()
+ * @see struct DBMap#foreach()
+ * @see struct DBMap#vdestroy()
+ * @see struct DBMap#destroy()
*/
-typedef int (*DBApply)(DBKey key, DBData *data, va_list args);
+typedef int (*DBApply)(union DBKey key, struct DBData *data, va_list args);
/**
* Format of functions that match database entries.
@@ -243,9 +245,9 @@ typedef int (*DBApply)(DBKey key, DBData *data, va_list args);
* @param args Extra arguments of the function
* @return 0 if a match, another number otherwise
* @public
- * @see DBMap#getall
+ * @see struct DBMap#getall()
*/
-typedef int (*DBMatcher)(DBKey key, DBData data, va_list args);
+typedef int (*DBMatcher)(union DBKey key, struct DBData data, va_list args);
/**
* Format of the comparators used internally by the database system.
@@ -257,9 +259,9 @@ typedef int (*DBMatcher)(DBKey key, DBData data, va_list args);
* databases.
* @return 0 if equal, negative if lower and positive if higher
* @public
- * @see #db_default_cmp(DBType)
+ * @see #db_default_cmp()
*/
-typedef int (*DBComparator)(DBKey key1, DBKey key2, unsigned short maxlen);
+typedef int (*DBComparator)(union DBKey key1, union DBKey key2, unsigned short maxlen);
/**
* Format of the hashers used internally by the database system.
@@ -269,9 +271,9 @@ typedef int (*DBComparator)(DBKey key1, DBKey key2, unsigned short maxlen);
* databases.
* @return Hash of the key
* @public
- * @see #db_default_hash(DBType)
+ * @see #db_default_hash()
*/
-typedef uint64 (*DBHasher)(DBKey key, unsigned short maxlen);
+typedef uint64 (*DBHasher)(union DBKey key, unsigned short maxlen);
/**
* Format of the releaser used by the database system.
@@ -281,27 +283,25 @@ typedef uint64 (*DBHasher)(DBKey key, unsigned short maxlen);
* @param data Data of the database entry
* @param which What is being requested to be released
* @public
- * @see #DBRelease
- * @see #db_default_releaser(DBType,DBOptions)
- * @see #db_custom_release(DBRelease)
+ * @see enum DBReleaseOption
+ * @see #db_default_releaser()
+ * @see #db_custom_release()
*/
-typedef void (*DBReleaser)(DBKey key, DBData data, DBRelease which);
-
-typedef struct DBIterator DBIterator;
-typedef struct DBMap DBMap;
+typedef void (*DBReleaser)(union DBKey key, struct DBData data, enum DBReleaseOption which);
/**
* Database iterator.
+ *
* Supports forward iteration, backward iteration and removing entries from the database.
* The iterator is initially positioned before the first entry of the database.
+ *
* While the iterator exists the database is locked internally, so invoke
- * {@link DBIterator#destroy} as soon as possible.
+ * struct DBIterator#destroy() as soon as possible.
+ *
* @public
- * @see #DBMap
+ * @see struct DBMap
*/
-struct DBIterator
-{
-
+struct DBIterator {
/**
* Fetches the first entry in the database.
* Returns the data of the entry.
@@ -311,7 +311,7 @@ struct DBIterator
* @return Data of the entry
* @protected
*/
- DBData* (*first)(DBIterator* self, DBKey* out_key);
+ struct DBData *(*first)(struct DBIterator *self, union DBKey *out_key);
/**
* Fetches the last entry in the database.
@@ -322,7 +322,7 @@ struct DBIterator
* @return Data of the entry
* @protected
*/
- DBData* (*last)(DBIterator* self, DBKey* out_key);
+ struct DBData *(*last)(struct DBIterator *self, union DBKey *out_key);
/**
* Fetches the next entry in the database.
@@ -333,7 +333,7 @@ struct DBIterator
* @return Data of the entry
* @protected
*/
- DBData* (*next)(DBIterator* self, DBKey* out_key);
+ struct DBData *(*next)(struct DBIterator *self, union DBKey *out_key);
/**
* Fetches the previous entry in the database.
@@ -344,7 +344,7 @@ struct DBIterator
* @return Data of the entry
* @protected
*/
- DBData* (*prev)(DBIterator* self, DBKey* out_key);
+ struct DBData *(*prev)(struct DBIterator *self, union DBKey *out_key);
/**
* Returns true if the fetched entry exists.
@@ -354,27 +354,29 @@ struct DBIterator
* @return true is the entry exists
* @protected
*/
- bool (*exists)(DBIterator* self);
+ bool (*exists)(struct DBIterator *self);
/**
* Removes the current entry from the database.
- * NOTE: {@link DBIterator#exists} will return false until another entry
- * is fetched
+ *
+ * NOTE: struct DBIterator#exists() will return false until another
+ * entry is fetched.
+ *
* Puts data of the removed entry in out_data, if out_data is not NULL.
* @param self Iterator
* @param out_data Data of the removed entry.
* @return 1 if entry was removed, 0 otherwise
* @protected
- * @see DBMap#remove
+ * @see struct DBMap#remove()
*/
- int (*remove)(DBIterator* self, DBData *out_data);
+ int (*remove)(struct DBIterator *self, struct DBData *out_data);
/**
* Destroys this iterator and unlocks the database.
* @param self Iterator
* @protected
*/
- void (*destroy)(DBIterator* self);
+ void (*destroy)(struct DBIterator *self);
};
@@ -382,7 +384,7 @@ struct DBIterator
* Public interface of a database. Only contains functions.
* All the functions take the interface as the first argument.
* @public
- * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short)
+ * @see #db_alloc()
*/
struct DBMap {
@@ -395,7 +397,7 @@ struct DBMap {
* @return New iterator
* @protected
*/
- DBIterator* (*iterator)(DBMap* self);
+ struct DBIterator *(*iterator)(struct DBMap *self);
/**
* Returns true if the entry exists.
@@ -404,7 +406,7 @@ struct DBMap {
* @return true is the entry exists
* @protected
*/
- bool (*exists)(DBMap* self, DBKey key);
+ bool (*exists)(struct DBMap *self, union DBKey key);
/**
* Get the data of the entry identified by the key.
@@ -413,10 +415,11 @@ struct DBMap {
* @return Data of the entry or NULL if not found
* @protected
*/
- DBData* (*get)(DBMap* self, DBKey key);
+ struct DBData *(*get)(struct DBMap *self, union DBKey key);
/**
- * Just calls {@link DBMap#vgetall}.
+ * Just calls struct DBMap#vgetall().
+ *
* Get the data of the entries matched by <code>match</code>.
* It puts a maximum of <code>max</code> entries into <code>buf</code>.
* If <code>buf</code> is NULL, it only counts the matches.
@@ -430,9 +433,9 @@ struct DBMap {
* @param ... Extra arguments for match
* @return The number of entries that matched
* @protected
- * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list)
+ * @see struct DBMap#vgetall()
*/
- unsigned int (*getall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, ...);
+ unsigned int (*getall)(struct DBMap *self, struct DBData **buf, unsigned int max, DBMatcher match, ...);
/**
* Get the data of the entries matched by <code>match</code>.
@@ -448,24 +451,25 @@ struct DBMap {
* @param ... Extra arguments for match
* @return The number of entries that matched
* @protected
- * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...)
+ * @see struct DBMap#getall()
*/
- unsigned int (*vgetall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, va_list args);
+ unsigned int (*vgetall)(struct DBMap *self, struct DBData **buf, unsigned int max, DBMatcher match, va_list args);
/**
- * Just calls {@link DBMap#vensure}.
- * Get the data of the entry identified by the key.
- * If the entry does not exist, an entry is added with the data returned by
- * <code>create</code>.
+ * Just calls struct DBMap#vensure().
+ *
+ * Get the data of the entry identified by the key. If the entry does
+ * not exist, an entry is added with the data returned by `create`.
+ *
* @param self Database
* @param key Key that identifies the entry
* @param create Function used to create the data if the entry doesn't exist
* @param ... Extra arguments for create
* @return Data of the entry
* @protected
- * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list)
+ * @see struct DBMap#vensure()
*/
- DBData* (*ensure)(DBMap* self, DBKey key, DBCreateData create, ...);
+ struct DBData *(*ensure)(struct DBMap *self, union DBKey key, DBCreateData create, ...);
/**
* Get the data of the entry identified by the key.
@@ -477,9 +481,9 @@ struct DBMap {
* @param args Extra arguments for create
* @return Data of the entry
* @protected
- * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...)
+ * @see struct DBMap#ensure()
*/
- DBData* (*vensure)(DBMap* self, DBKey key, DBCreateData create, va_list args);
+ struct DBData *(*vensure)(struct DBMap *self, union DBKey key, DBCreateData create, va_list args);
/**
* Put the data identified by the key in the database.
@@ -492,7 +496,7 @@ struct DBMap {
* @return 1 if if the entry already exists, 0 otherwise
* @protected
*/
- int (*put)(DBMap* self, DBKey key, DBData data, DBData *out_data);
+ int (*put)(struct DBMap *self, union DBKey key, struct DBData data, struct DBData *out_data);
/**
* Remove an entry from the database.
@@ -504,10 +508,11 @@ struct DBMap {
* @return 1 if if the entry already exists, 0 otherwise
* @protected
*/
- int (*remove)(DBMap* self, DBKey key, DBData *out_data);
+ int (*remove)(struct DBMap *self, union DBKey key, struct DBData *out_data);
/**
- * Just calls {@link DBMap#vforeach}.
+ * Just calls struct DBMap#vforeach().
+ *
* Apply <code>func</code> to every entry in the database.
* Returns the sum of values returned by func.
* @param self Database
@@ -515,9 +520,9 @@ struct DBMap {
* @param ... Extra arguments for func
* @return Sum of the values returned by func
* @protected
- * @see DBMap#vforeach(DBMap*,DBApply,va_list)
+ * @see struct DBMap#vforeach()
*/
- int (*foreach)(DBMap* self, DBApply func, ...);
+ int (*foreach)(struct DBMap *self, DBApply func, ...);
/**
* Apply <code>func</code> to every entry in the database.
@@ -527,12 +532,13 @@ struct DBMap {
* @param args Extra arguments for func
* @return Sum of the values returned by func
* @protected
- * @see DBMap#foreach(DBMap*,DBApply,...)
+ * @see struct DBMap#foreach()
*/
- int (*vforeach)(DBMap* self, DBApply func, va_list args);
+ int (*vforeach)(struct DBMap *self, DBApply func, va_list args);
/**
- * Just calls {@link DBMap#vclear}.
+ * Just calls struct DBMap#vclear().
+ *
* Removes all entries from the database.
* Before deleting an entry, func is applied to it.
* Releases the key and the data.
@@ -542,9 +548,9 @@ struct DBMap {
* @param ... Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vclear(DBMap*,DBApply,va_list)
+ * @see struct DBMap#vclear()
*/
- int (*clear)(DBMap* self, DBApply func, ...);
+ int (*clear)(struct DBMap *self, DBApply func, ...);
/**
* Removes all entries from the database.
@@ -556,12 +562,12 @@ struct DBMap {
* @param args Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#clear(DBMap*,DBApply,...)
+ * @see struct DBMap#clear()
*/
- int (*vclear)(DBMap* self, DBApply func, va_list args);
+ int (*vclear)(struct DBMap *self, DBApply func, va_list args);
/**
- * Just calls {@link DBMap#vdestroy}.
+ * Just calls DBMap#vdestroy().
* Finalize the database, feeing all the memory it uses.
* Before deleting an entry, func is applied to it.
* Releases the key and the data.
@@ -573,9 +579,9 @@ struct DBMap {
* @param ... Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#vdestroy(DBMap*,DBApply,va_list)
+ * @see struct DBMap#vdestroy()
*/
- int (*destroy)(DBMap* self, DBApply func, ...);
+ int (*destroy)(struct DBMap *self, DBApply func, ...);
/**
* Finalize the database, feeing all the memory it uses.
@@ -588,9 +594,9 @@ struct DBMap {
* @param args Extra arguments for func
* @return Sum of values returned by func
* @protected
- * @see DBMap#destroy(DBMap*,DBApply,...)
+ * @see struct DBMap#destroy()
*/
- int (*vdestroy)(DBMap* self, DBApply func, va_list args);
+ int (*vdestroy)(struct DBMap *self, DBApply func, va_list args);
/**
* Return the size of the database (number of items in the database).
@@ -598,7 +604,7 @@ struct DBMap {
* @return Size of the database
* @protected
*/
- unsigned int (*size)(DBMap* self);
+ unsigned int (*size)(struct DBMap *self);
/**
* Return the type of the database.
@@ -606,7 +612,7 @@ struct DBMap {
* @return Type of the database
* @protected
*/
- DBType (*type)(DBMap* self);
+ enum DBType (*type)(struct DBMap *self);
/**
* Return the options of the database.
@@ -614,7 +620,7 @@ struct DBMap {
* @return Options of the database
* @protected
*/
- DBOptions (*options)(DBMap* self);
+ enum DBOptions (*options)(struct DBMap *self);
};
@@ -712,7 +718,7 @@ struct DBMap {
#define dbi_exists(dbi) ( (dbi)->exists(dbi) )
#define dbi_destroy(dbi) ( (dbi)->destroy(dbi) )
-/*****************************************************************************\
+/*****************************************************************************
* (2) Section with public functions. *
* db_fix_options - Fix the options for a type of database. *
* db_default_cmp - Get the default comparator for a type of database. *
@@ -721,20 +727,20 @@ struct DBMap {
* with the fixed options. *
* db_custom_release - Get the releaser that behaves as specified. *
* db_alloc - Allocate a new database. *
- * db_i2key - Manual cast from 'int' to 'DBKey'. *
- * db_ui2key - Manual cast from 'unsigned int' to 'DBKey'. *
- * db_str2key - Manual cast from 'unsigned char *' to 'DBKey'. *
- * db_i642key - Manual cast from 'int64' to 'DBKey'. *
- * db_ui642key - Manual cast from 'uint64' to 'DBKey'. *
- * db_i2data - Manual cast from 'int' to 'DBData'. *
- * db_ui2data - Manual cast from 'unsigned int' to 'DBData'. *
- * db_ptr2data - Manual cast from 'void*' to 'DBData'. *
- * db_data2i - Gets 'int' value from 'DBData'. *
- * db_data2ui - Gets 'unsigned int' value from 'DBData'. *
- * db_data2ptr - Gets 'void*' value from 'DBData'. *
+ * db_i2key - Manual cast from `int` to `union DBKey`. *
+ * db_ui2key - Manual cast from `unsigned int` to `union DBKey`. *
+ * db_str2key - Manual cast from `unsigned char *` to `union DBKey`.*
+ * db_i642key - Manual cast from `int64` to `union DBKey`. *
+ * db_ui642key - Manual cast from `uint64` to `union DBKey`. *
+ * db_i2data - Manual cast from `int` to `struct DBData`. *
+ * db_ui2data - Manual cast from `unsigned int` to `struct DBData`. *
+ * db_ptr2data - Manual cast from `void*` to `struct DBData`. *
+ * db_data2i - Gets `int` value from `struct DBData`. *
+ * db_data2ui - Gets `unsigned int` value from `struct DBData`. *
+ * db_data2ptr - Gets `void*` value from `struct DBData`. *
* db_init - Initializes the database system. *
* db_final - Finalizes the database system. *
-\*****************************************************************************/
+ *****************************************************************************/
struct db_interface {
/**
@@ -745,66 +751,71 @@ struct db_interface {
* @param options Original options of the database
* @return Fixed options of the database
* @private
- * @see #DBType
- * @see #DBOptions
- * @see #db_default_release(DBType,DBOptions)
+ * @see enum DBType
+ * @see enum DBOptions
+ * @see #db_default_release()
*/
-DBOptions (*fix_options) (DBType type, DBOptions options);
+enum DBOptions (*fix_options) (enum DBType type, enum DBOptions options);
/**
* Returns the default comparator for the type of database.
* @param type Type of database
* @return Comparator for the type of database or NULL if unknown database
* @public
- * @see #DBType
+ * @see enum DBType
* @see #DBComparator
*/
-DBComparator (*default_cmp) (DBType type);
+DBComparator (*default_cmp) (enum DBType type);
/**
* Returns the default hasher for the specified type of database.
* @param type Type of database
* @return Hasher of the type of database or NULL if unknown database
* @public
- * @see #DBType
+ * @see enum DBType
* @see #DBHasher
*/
-DBHasher (*default_hash) (DBType type);
+DBHasher (*default_hash) (enum DBType type);
/**
* Returns the default releaser for the specified type of database with the
* specified options.
- * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)}
- * before choosing the releaser
+ *
+ * NOTE: the options are fixed by #db_fix_options() before choosing the
+ * releaser.
+ *
* @param type Type of database
* @param options Options of the database
* @return Default releaser for the type of database with the fixed options
* @public
- * @see #DBType
- * @see #DBOptions
+ * @see enum DBType
+ * @see enum DBOptions
* @see #DBReleaser
- * @see #db_fix_options(DBType,DBOptions)
- * @see #db_custom_release(DBRelease)
+ * @see #db_fix_options()
+ * @see #db_custom_release()
*/
-DBReleaser (*default_release) (DBType type, DBOptions options);
+DBReleaser (*default_release) (enum DBType type, enum DBOptions options);
/**
* Returns the releaser that behaves as <code>which</code> specifies.
* @param which Defines what the releaser releases
* @return Releaser for the specified release options
* @public
- * @see #DBRelease
+ * @see enum DBReleaseOption
* @see #DBReleaser
- * @see #db_default_release(DBType,DBOptions)
+ * @see #db_default_release()
*/
-DBReleaser (*custom_release) (DBRelease which);
+DBReleaser (*custom_release) (enum DBReleaseOption which);
/**
* Allocate a new database of the specified type.
+ *
* It uses the default comparator, hasher and releaser of the specified
* database type and fixed options.
- * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)}
- * before creating the database.
+ *
+ * NOTE: the options are fixed by #db_fix_options() before creating the
+ * database.
+ *
* @param file File where the database is being allocated
* @param line Line of the file where the database is being allocated
* @param type Type of database
@@ -813,14 +824,14 @@ DBReleaser (*custom_release) (DBRelease which);
* databases. If 0, the maximum number of maxlen is used (64K).
* @return The interface of the database
* @public
- * @see #DBType
- * @see #DBMap
- * @see #db_default_cmp(DBType)
- * @see #db_default_hash(DBType)
- * @see #db_default_release(DBType,DBOptions)
- * @see #db_fix_options(DBType,DBOptions)
+ * @see enum DBType
+ * @see struct DBMap
+ * @see #db_default_cmp()
+ * @see #db_default_hash()
+ * @see #db_default_release()
+ * @see #db_fix_options()
*/
-DBMap* (*alloc) (const char *file, const char *func, int line, DBType type, DBOptions options, unsigned short maxlen);
+struct DBMap *(*alloc) (const char *file, const char *func, int line, enum DBType type, enum DBOptions options, unsigned short maxlen);
/**
* Manual cast from 'int' to the union DBKey.
@@ -828,7 +839,7 @@ DBMap* (*alloc) (const char *file, const char *func, int line, DBType type, DBOp
* @return The key as a DBKey union
* @public
*/
-DBKey (*i2key) (int key);
+union DBKey (*i2key) (int key);
/**
* Manual cast from 'unsigned int' to the union DBKey.
@@ -836,7 +847,7 @@ DBKey (*i2key) (int key);
* @return The key as a DBKey union
* @public
*/
-DBKey (*ui2key) (unsigned int key);
+union DBKey (*ui2key) (unsigned int key);
/**
* Manual cast from 'unsigned char *' to the union DBKey.
@@ -844,7 +855,7 @@ DBKey (*ui2key) (unsigned int key);
* @return The key as a DBKey union
* @public
*/
-DBKey (*str2key) (const char *key);
+union DBKey (*str2key) (const char *key);
/**
* Manual cast from 'int64' to the union DBKey.
@@ -852,7 +863,7 @@ DBKey (*str2key) (const char *key);
* @return The key as a DBKey union
* @public
*/
-DBKey (*i642key) (int64 key);
+union DBKey (*i642key) (int64 key);
/**
* Manual cast from 'uint64' to the union DBKey.
@@ -860,7 +871,7 @@ DBKey (*i642key) (int64 key);
* @return The key as a DBKey union
* @public
*/
-DBKey (*ui642key) (uint64 key);
+union DBKey (*ui642key) (uint64 key);
/**
* Manual cast from 'int' to the struct DBData.
@@ -868,7 +879,7 @@ DBKey (*ui642key) (uint64 key);
* @return The data as a DBData struct
* @public
*/
-DBData (*i2data) (int data);
+struct DBData (*i2data) (int data);
/**
* Manual cast from 'unsigned int' to the struct DBData.
@@ -876,7 +887,7 @@ DBData (*i2data) (int data);
* @return The data as a DBData struct
* @public
*/
-DBData (*ui2data) (unsigned int data);
+struct DBData (*ui2data) (unsigned int data);
/**
* Manual cast from 'void *' to the struct DBData.
@@ -884,7 +895,7 @@ DBData (*ui2data) (unsigned int data);
* @return The data as a DBData struct
* @public
*/
-DBData (*ptr2data) (void *data);
+struct DBData (*ptr2data) (void *data);
/**
* Gets int type data from struct DBData.
@@ -893,7 +904,7 @@ DBData (*ptr2data) (void *data);
* @return Integer value of the data.
* @public
*/
-int (*data2i) (DBData *data);
+int (*data2i) (struct DBData *data);
/**
* Gets unsigned int type data from struct DBData.
@@ -902,7 +913,7 @@ int (*data2i) (DBData *data);
* @return Unsigned int value of the data.
* @public
*/
-unsigned int (*data2ui) (DBData *data);
+unsigned int (*data2ui) (struct DBData *data);
/**
* Gets void* type data from struct DBData.
@@ -911,7 +922,7 @@ unsigned int (*data2ui) (DBData *data);
* @return Void* value of the data.
* @public
*/
-void* (*data2ptr) (DBData *data);
+void* (*data2ptr) (struct DBData *data);
/**
* Initialize the database system.
@@ -1103,7 +1114,11 @@ HPShared struct db_interface *DB;
* @param _vec Vector.
*/
#define VECTOR_INIT(_vec) \
- memset(&(_vec), 0, sizeof(_vec))
+ do { \
+ VECTOR_DATA(_vec) = NULL; \
+ VECTOR_CAPACITY(_vec) = 0; \
+ VECTOR_LENGTH(_vec) = 0; \
+ } while(false)
/**
* Returns the internal array of values.
@@ -1209,12 +1224,11 @@ HPShared struct db_interface *DB;
*/
#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)); \
- } \
+ int _newcapacity_ = VECTOR_CAPACITY(_vec); \
+ while ((_n) + VECTOR_LENGTH(_vec) > _newcapacity_) \
+ _newcapacity_ += (_step); \
+ if (_newcapacity_ > VECTOR_CAPACITY(_vec)) \
+ VECTOR_RESIZE(_vec, _newcapacity_); \
} while(false)
/**
@@ -1384,6 +1398,16 @@ HPShared struct db_interface *DB;
} while(false)
/**
+ * Removes all values from the vector.
+ *
+ * Does not free the allocated data.
+ */
+#define VECTOR_TRUNCATE(_vec) \
+ do { \
+ VECTOR_LENGTH(_vec) = 0; \
+ } while (false)
+
+/**
* Clears the vector, freeing allocated data.
*
* @param _vec Vector.
diff --git a/src/common/des.c b/src/common/des.c
index ce64309f3..73297ab70 100644
--- a/src/common/des.c
+++ b/src/common/des.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,24 +23,25 @@
#include "des.h"
#include "common/cbasetypes.h"
+#include "common/nullpo.h"
-/// DES (Data Encryption Standard) algorithm, modified version.
-/// @see http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=5099.
-/// @see http://en.wikipedia.org/wiki/Data_Encryption_Standard
-/// @see http://en.wikipedia.org/wiki/DES_supplementary_material
+/** @file
+ * Implementation of the des interface.
+ */
+struct des_interface des_s;
+struct des_interface *des;
/// Bitmask for accessing individual bits of a byte.
static const uint8_t mask[8] = {
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};
-
-/// Initial permutation (IP).
-static void IP(BIT64* src)
+/**
+ * Initial permutation (IP).
+ */
+static void des_IP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t ip_table[64] = {
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
@@ -51,24 +52,24 @@ static void IP(BIT64* src)
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(ip_table); ++i )
- {
+ nullpo_retv(src);
+ for(i = 0; i < ARRAYLENGTH(ip_table); ++i) {
uint8_t j = ip_table[i] - 1;
- if( src->b[(j >> 3) & 7] & mask[j & 7] )
- tmp .b[(i >> 3) & 7] |= mask[i & 7];
+ if (src->b[(j >> 3) & 7] & mask[j & 7])
+ tmp.b[(i >> 3) & 7] |= mask[i & 7];
}
*src = tmp;
}
-
-/// Final permutation (IP^-1).
-static void FP(BIT64* src)
+/**
+ * Final permutation (IP^-1).
+ */
+static void des_FP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t fp_table[64] = {
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
@@ -79,24 +80,27 @@ static void FP(BIT64* src)
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(fp_table); ++i )
- {
+ nullpo_retv(src);
+ for (i = 0; i < ARRAYLENGTH(fp_table); ++i) {
uint8_t j = fp_table[i] - 1;
- if( src->b[(j >> 3) & 7] & mask[j & 7] )
- tmp .b[(i >> 3) & 7] |= mask[i & 7];
+ if (src->b[(j >> 3) & 7] & mask[j & 7])
+ tmp.b[(i >> 3) & 7] |= mask[i & 7];
}
*src = tmp;
}
-
-/// Expansion (E).
-/// Expands upper four 8-bits (32b) into eight 6-bits (48b).
-static void E(BIT64* src)
+/**
+ * Expansion (E).
+ *
+ * Expands upper four 8-bits (32b) into eight 6-bits (48b).
+ */
+static void des_E(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
+ struct des_bit64 tmp = {{0}};
#if 0
// original
@@ -110,15 +114,15 @@ static void E(BIT64* src)
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1,
};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(expand_table); ++i )
- {
+ for (i = 0; i < ARRAYLENGTH(expand_table); ++i) {
uint8_t j = expand_table[i] - 1;
- if( src->b[j / 8 + 4] & mask[j % 8] )
- tmp .b[i / 6 + 0] |= mask[i % 6];
+ if (src->b[j / 8 + 4] & mask[j % 8])
+ tmp.b[i / 6 + 0] |= mask[i % 6];
}
#endif
+ nullpo_retv(src);
// optimized
tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr
tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n
@@ -132,12 +136,11 @@ static void E(BIT64* src)
*src = tmp;
}
-
-/// Transposition (P-BOX).
-static void TP(BIT64* src)
+/**
+ * Transposition (P-BOX).
+ */
+static void des_TP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t tp_table[32] = {
16, 7, 20, 21,
29, 12, 28, 17,
@@ -148,25 +151,28 @@ static void TP(BIT64* src)
19, 13, 30, 6,
22, 11, 4, 25,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(tp_table); ++i )
- {
+ nullpo_retv(src);
+ for (i = 0; i < ARRAYLENGTH(tp_table); ++i) {
uint8_t j = tp_table[i] - 1;
- if( src->b[(j >> 3) + 0] & mask[j & 7] )
- tmp .b[(i >> 3) + 4] |= mask[i & 7];
+ if (src->b[(j >> 3) + 0] & mask[j & 7])
+ tmp.b[(i >> 3) + 4] |= mask[i & 7];
}
*src = tmp;
}
-/// Substitution boxes (S-boxes).
-/// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast).
-static void SBOX(BIT64* src)
+/**
+ * Substitution boxes (S-boxes).
+ *
+ * This implementation was optimized to process two nibbles in one step (twice
+ * as fast).
+ */
+static void des_SBOX(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t s_table[4][64] = {
{
0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e,
@@ -190,10 +196,11 @@ static void SBOX(BIT64* src)
0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb,
}
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(s_table); ++i )
- {
+ nullpo_retv(src);
+ for (i = 0; i < ARRAYLENGTH(s_table); ++i) {
tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0)
| (s_table[i][src->b[i*2+1]] & 0x0f);
}
@@ -201,36 +208,49 @@ static void SBOX(BIT64* src)
*src = tmp;
}
-
-/// DES round function.
-/// XORs src[0..3] with TP(SBOX(E(src[4..7]))).
-static void RoundFunction(BIT64* src)
+/**
+ * DES round function.
+ *
+ * XORs src[0..3] with TP(SBOX(E(src[4..7]))).
+ */
+static void des_RoundFunction(struct des_bit64 *src)
{
- BIT64 tmp = *src;
- E(&tmp);
- SBOX(&tmp);
- TP(&tmp);
+ struct des_bit64 tmp = *src;
+ des_E(&tmp);
+ des_SBOX(&tmp);
+ des_TP(&tmp);
+ nullpo_retv(src);
src->b[0] ^= tmp.b[4];
src->b[1] ^= tmp.b[5];
src->b[2] ^= tmp.b[6];
src->b[3] ^= tmp.b[7];
}
-
-void des_decrypt_block(BIT64* block)
+/// @copydoc des_interface::decrypt_block()
+void des_decrypt_block(struct des_bit64 *block)
{
- IP(block);
- RoundFunction(block);
- FP(block);
+ des_IP(block);
+ des_RoundFunction(block);
+ des_FP(block);
}
-
-void des_decrypt(unsigned char* data, size_t size)
+/// @copydoc des_interface::decrypt()
+void des_decrypt(unsigned char *data, size_t size)
{
- BIT64* p = (BIT64*)data;
+ struct des_bit64 *p = (struct des_bit64 *)data;
size_t i;
- for( i = 0; i*8 < size; i += 8 )
- des_decrypt_block(p);
+ for (i = 0; i*8 < size; i += 8)
+ des->decrypt_block(p);
+}
+
+/**
+ * Interface base initialization.
+ */
+void des_defaults(void)
+{
+ des = &des_s;
+ des->decrypt = des_decrypt;
+ des->decrypt_block = des_decrypt_block;
}
diff --git a/src/common/des.h b/src/common/des.h
index d62b5cc49..9924a044b 100644
--- a/src/common/des.h
+++ b/src/common/des.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,14 +21,49 @@
#ifndef COMMON_DES_H
#define COMMON_DES_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
+
+/**
+ * @file
+ *
+ * DES (Data Encryption Standard) algorithm, modified version.
+ *
+ * @see http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=5099
+ * @see http://en.wikipedia.org/wiki/Data_Encryption_Standard
+ * @see http://en.wikipedia.org/wiki/DES_supplementary_material
+ */
+
+/* Struct definitions */
/// One 64-bit block.
-typedef struct BIT64 { uint8_t b[8]; } BIT64;
+struct des_bit64 {
+ uint8_t b[8];
+};
+
+/* Interface */
+
+/// The des interface.
+struct des_interface {
+ /**
+ * Decrypts a block.
+ *
+ * @param[in,out] block The block to decrypt (in-place).
+ */
+ void (*decrypt_block) (struct des_bit64 *block);
+
+ /**
+ * Decrypts a buffer.
+ *
+ * @param [in,out] data The buffer to decrypt (in-place).
+ * @param [in] size The size of the data.
+ */
+ void (*decrypt) (unsigned char *data, size_t size);
+};
#ifdef HERCULES_CORE
-void des_decrypt_block(BIT64* block);
-void des_decrypt(unsigned char* data, size_t size);
+void des_defaults(void);
#endif // HERCULES_CORE
+HPShared struct des_interface *des; ///< Pointer to the des interface implementation.
+
#endif // COMMON_DES_H
diff --git a/src/common/ers.c b/src/common/ers.c
index 85e1fb759..f2256cf30 100644
--- a/src/common/ers.c
+++ b/src/common/ers.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -149,7 +149,8 @@ static struct ers_instance_t *InstanceList = NULL;
/**
* @param Options the options from the instance seeking a cache, we use it to give it a cache with matching configuration
**/
-static ers_cache_t *ers_find_cache(unsigned int size, enum ERSOptions Options) {
+static ers_cache_t *ers_find_cache(unsigned int size, enum ERSOptions Options)
+{
ers_cache_t *cache;
for (cache = CacheList; cache; cache = cache->Next)
@@ -187,6 +188,7 @@ static void ers_free_cache(ers_cache_t *cache, bool remove)
{
unsigned int i;
+ nullpo_retv(cache);
for (i = 0; i < cache->Used; i++)
aFree(cache->Blocks[i]);
@@ -288,7 +290,7 @@ static void ers_obj_destroy(ERS *self)
if (instance->Count > 0)
if (!(instance->Options & ERS_OPT_CLEAR))
- ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count);
+ ShowWarning("Memory leak detected at ERS '%s', %u objects not freed.\n", instance->Name, instance->Count);
if (--instance->Cache->ReferenceCount <= 0)
ers_free_cache(instance->Cache, true);
@@ -307,22 +309,24 @@ static void ers_obj_destroy(ERS *self)
aFree(instance);
}
-void ers_cache_size(ERS *self, unsigned int new_size) {
+void ers_cache_size(ERS *self, unsigned int new_size)
+{
struct ers_instance_t *instance = (struct ers_instance_t *)self;
nullpo_retv(instance);
if( !(instance->Cache->Options&ERS_OPT_FLEX_CHUNK) ) {
- ShowWarning("ers_cache_size: '%s' has adjusted its chunk size to '%d', however ERS_OPT_FLEX_CHUNK is missing!\n",instance->Name,new_size);
+ ShowWarning("ers_cache_size: '%s' has adjusted its chunk size to '%u', however ERS_OPT_FLEX_CHUNK is missing!\n", instance->Name, new_size);
}
instance->Cache->ChunkSize = new_size;
}
-
ERS *ers_new(uint32 size, char *name, enum ERSOptions options)
{
struct ers_instance_t *instance;
+
+ nullpo_retr(NULL, name);
CREATE(instance,struct ers_instance_t, 1);
size += sizeof(struct ers_list);
@@ -359,7 +363,8 @@ ERS *ers_new(uint32 size, char *name, enum ERSOptions options)
return &instance->VTable;
}
-void ers_report(void) {
+void ers_report(void)
+{
ers_cache_t *cache;
unsigned int cache_c = 0, blocks_u = 0, blocks_a = 0, memory_b = 0, memory_t = 0;
#ifdef DEBUG
@@ -382,7 +387,7 @@ void ers_report(void) {
for (cache = CacheList; cache; cache = cache->Next) {
cache_c++;
ShowMessage(CL_BOLD"[ERS Cache of size '"CL_NORMAL""CL_WHITE"%u"CL_NORMAL""CL_BOLD"' report]\n"CL_NORMAL, cache->ObjectSize);
- ShowMessage("\tinstances : %u\n", cache->ReferenceCount);
+ ShowMessage("\tinstances : %d\n", cache->ReferenceCount);
ShowMessage("\tblocks in use : %u/%u\n", cache->UsedObjs, cache->UsedObjs+cache->Free);
ShowMessage("\tblocks unused : %u\n", cache->Free);
ShowMessage("\tmemory in use : %.2f MB\n", cache->UsedObjs == 0 ? 0. : (double)((cache->UsedObjs * cache->ObjectSize)/1024)/1024);
@@ -403,7 +408,8 @@ void ers_report(void) {
/**
* Call on shutdown to clear remaining entries
**/
-void ers_final(void) {
+void ers_final(void)
+{
struct ers_instance_t *instance = InstanceList, *next;
while( instance ) {
diff --git a/src/common/ers.h b/src/common/ers.h
index 1689345dc..5f9516ad6 100644
--- a/src/common/ers.h
+++ b/src/common/ers.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/grfio.c b/src/common/grfio.c
index 678875c91..fba3dda86 100644
--- a/src/common/grfio.c
+++ b/src/common/grfio.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -35,10 +35,12 @@
#include <sys/stat.h>
#include <zlib.h>
-//----------------------------
-// file entry table struct
-//----------------------------
-typedef struct FILELIST {
+/** @file
+ * Implementation of the GRF I/O interface.
+ */
+
+/// File entry table struct.
+struct grf_filelist {
int srclen; ///< compressed size
int srclen_aligned;
int declen; ///< original size
@@ -48,11 +50,13 @@ typedef struct FILELIST {
char fn[128-4*5]; ///< file name
char *fnd; ///< if the file was cloned, contains name of original file
int8 gentry; ///< read grf file select
-} FILELIST;
+};
-#define FILELIST_TYPE_FILE 0x01 // entry is a file
-#define FILELIST_TYPE_ENCRYPT_MIXED 0x02 // encryption mode 0 (header DES + periodic DES/shuffle)
-#define FILELIST_TYPE_ENCRYPT_HEADER 0x04 // encryption mode 1 (header DES only)
+enum grf_filelist_type {
+ FILELIST_TYPE_FILE = 0x01, ///< entry is a file
+ FILELIST_TYPE_ENCRYPT_MIXED = 0x02, ///< encryption mode 0 (header DES + periodic DES/shuffle)
+ FILELIST_TYPE_ENCRYPT_HEADER = 0x04, ///< encryption mode 1 (header DES only)
+};
//gentry ... > 0 : data read from a grf file (gentry_table[gentry-1])
//gentry ... 0 : data read from a local file (data directory)
@@ -64,7 +68,7 @@ typedef struct FILELIST {
//#define GRFIO_LOCAL
// stores info about every loaded file
-FILELIST* filelist = NULL;
+struct grf_filelist *filelist = NULL;
int filelist_entrys = 0;
int filelist_maxentry = 0;
@@ -76,24 +80,32 @@ int gentry_maxentry = 0;
// the path to the data directory
char data_dir[1024] = "";
+struct grfio_interface grfio_s;
+struct grfio_interface *grfio;
+
// little endian char array to uint conversion
-static unsigned int getlong(unsigned char* p)
+static unsigned int getlong(unsigned char *p)
{
+ nullpo_ret(p);
return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24);
}
-static void NibbleSwap(unsigned char* src, int len)
+static void NibbleSwap(unsigned char *src, int len)
{
- while( len > 0 )
- {
+ nullpo_retv(src);
+ while (len > 0) {
*src = (*src >> 4) | (*src << 4);
++src;
--len;
}
}
-/// Substitutes some specific values for others, leaves rest intact. Obfuscation.
-/// NOTE: Operation is symmetric (calling it twice gives back the original input).
+/**
+ * (De)-obfuscates data.
+ *
+ * Substitutes some specific values for others, leaves rest intact.
+ * NOTE: Operation is symmetric (calling it twice gives back the original input).
+ */
static uint8_t grf_substitution(uint8_t in)
{
uint8_t out;
@@ -121,10 +133,11 @@ static uint8_t grf_substitution(uint8_t in)
}
#if 0 /* this is not used anywhere, is it ok to delete? */
-static void grf_shuffle_enc(BIT64* src)
+static void grf_shuffle_enc(struct des_bit64 *src)
{
- BIT64 out;
+ struct des_bit64 out;
+ nullpo_retv(src);
out.b[0] = src->b[3];
out.b[1] = src->b[4];
out.b[2] = src->b[5];
@@ -138,10 +151,11 @@ static void grf_shuffle_enc(BIT64* src)
}
#endif // 0
-static void grf_shuffle_dec(BIT64* src)
+static void grf_shuffle_dec(struct des_bit64 *src)
{
- BIT64 out;
+ struct des_bit64 out;
+ nullpo_retv(src);
out.b[0] = src->b[3];
out.b[1] = src->b[4];
out.b[2] = src->b[6];
@@ -154,29 +168,44 @@ static void grf_shuffle_dec(BIT64* src)
*src = out;
}
-static void grf_decode_header(unsigned char* buf, size_t len)
+/**
+ * Decodes header-encrypted grf data.
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data.
+ */
+static void grf_decode_header(unsigned char *buf, size_t len)
{
- BIT64* p = (BIT64*)buf;
- size_t nblocks = len / sizeof(BIT64);
+ struct des_bit64 *p = (struct des_bit64 *)buf;
+ size_t nblocks = len / sizeof(struct des_bit64);
size_t i;
+ nullpo_retv(buf);
// first 20 blocks are all des-encrypted
- for( i = 0; i < 20 && i < nblocks; ++i )
- des_decrypt_block(&p[i]);
+ for (i = 0; i < 20 && i < nblocks; ++i)
+ des->decrypt_block(&p[i]);
// the rest is plaintext, done.
}
-static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
+/**
+ * Decodes fully encrypted grf data
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data.
+ * @param[in] cycle The current decoding cycle.
+ */
+static void grf_decode_full(unsigned char *buf, size_t len, int cycle)
{
- BIT64* p = (BIT64*)buf;
- size_t nblocks = len / sizeof(BIT64);
+ struct des_bit64 *p = (struct des_bit64 *)buf;
+ size_t nblocks = len / sizeof(struct des_bit64);
int dcycle, scycle;
size_t i, j;
+ nullpo_retv(buf);
// first 20 blocks are all des-encrypted
- for( i = 0; i < 20 && i < nblocks; ++i )
- des_decrypt_block(&p[i]);
+ for (i = 0; i < 20 && i < nblocks; ++i)
+ des->decrypt_block(&p[i]);
// after that only one of every 'dcycle' blocks is des-encrypted
dcycle = cycle;
@@ -186,17 +215,16 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
// so decrypt/de-shuffle periodically
j = (size_t)-1; // 0, adjusted to fit the ++j step
- for( i = 20; i < nblocks; ++i )
- {
- if( i % dcycle == 0 )
- {// decrypt block
- des_decrypt_block(&p[i]);
+ for (i = 20; i < nblocks; ++i) {
+ if (i % dcycle == 0) {
+ // decrypt block
+ des->decrypt_block(&p[i]);
continue;
}
++j;
- if( j % scycle == 0 && j != 0 )
- {// de-shuffle block
+ if (j % scycle == 0 && j != 0) {
+ // de-shuffle block
grf_shuffle_dec(&p[i]);
continue;
}
@@ -205,22 +233,25 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
}
}
-/// Decodes grf data.
-/// @param buf data to decode (in-place)
-/// @param len length of the data
-/// @param entry_type flags associated with the data
-/// @param entry_len true (unaligned) length of the data
-static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len)
+/**
+ * Decodes grf data.
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data
+ * @param[in] entry_type Flags associated with the data.
+ * @param[in] entry_len True (unaligned) length of the data.
+ */
+static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len)
{
- if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED )
- {// fully encrypted
+ if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) {
+ // fully encrypted
int digits;
int cycle;
int i;
// compute number of digits of the entry length
digits = 1;
- for( i = 10; i <= entry_len; i *= 10 )
+ for (i = 10; i <= entry_len; i *= 10)
++digits;
// choose size of gap between two encrypted blocks
@@ -232,51 +263,47 @@ static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entr
: digits + 15;
grf_decode_full(buf, len, cycle);
- }
- else
- if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER )
- {// header encrypted
+ } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) {
+ // header encrypted
grf_decode_header(buf, len);
}
- else
- {// plaintext
- ;
- }
+ /* else plaintext */
}
-/******************************************************
- *** Zlib Subroutines ***
- ******************************************************/
+/* Zlib Subroutines */
-/// zlib crc32
-unsigned long grfio_crc32(const unsigned char* buf, unsigned int len)
+/// @copydoc grfio_interface::crc32()
+unsigned long grfio_crc32(const unsigned char *buf, unsigned int len)
{
return crc32(crc32(0L, Z_NULL, 0), buf, len);
}
-/// zlib uncompress
-int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen)
+/// @copydoc grfio_interface::decode_zip
+int grfio_decode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len)
{
- return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen);
+ return uncompress(dest, dest_len, source, source_len);
}
-/// zlib compress
-int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) {
- if( *destLen == 0 ) /* [Ind/Hercules] */
- *destLen = compressBound(sourceLen);
- if( dest == NULL ) { /* [Ind/Hercules] */
- CREATE(dest, unsigned char, *destLen);
+/// @copydoc grfio_interface::encode_zip
+int grfio_encode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len)
+{
+ if (*dest_len == 0) /* [Ind/Hercules] */
+ *dest_len = compressBound(source_len);
+ if (dest == NULL) {
+ /* [Ind/Hercules] */
+ CREATE(dest, unsigned char, *dest_len);
}
- return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen);
+ return compress(dest, dest_len, source, source_len);
}
-/***********************************************************
- *** File List Subroutines ***
- ***********************************************************/
-// file list hash table
+/* File List Subroutines */
+
+/// File list hash table
int filelist_hash[256];
-// initializes the table that holds the first elements of all hash chains
+/**
+ * Initializes the table that holds the first elements of all hash chains
+ */
static void hashinit(void)
{
int i;
@@ -284,26 +311,38 @@ static void hashinit(void)
filelist_hash[i] = -1;
}
-// hashes a filename string into a number from {0..255}
-static int filehash(const char* fname)
+/**
+ * Hashes a filename string into a number from {0..255}
+ *
+ * @param fname The filename to hash.
+ * @return The hash.
+ */
+static int grf_filehash(const char *fname)
{
- unsigned int hash = 0;
- while(*fname) {
+ uint32 hash = 0;
+ nullpo_ret(fname);
+ while (*fname != '\0') {
hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname);
fname++;
}
return hash & 255;
}
-// finds a FILELIST entry with the specified file name
-static FILELIST* filelist_find(const char* fname)
+/**
+ * Finds a grf_filelist entry with the specified file name
+ *
+ * @param fname The file to find.
+ * @return The file entry.
+ * @retval NULL if the file wasn't found.
+ */
+static struct grf_filelist *grfio_filelist_find(const char *fname)
{
int hash, index;
- if (!filelist)
+ if (filelist == NULL)
return NULL;
- hash = filelist_hash[filehash(fname)];
+ hash = filelist_hash[grf_filehash(fname)];
for (index = hash; index != -1; index = filelist[index].next)
if(!strcmpi(filelist[index].fn, fname))
break;
@@ -311,16 +350,23 @@ static FILELIST* filelist_find(const char* fname)
return (index >= 0) ? &filelist[index] : NULL;
}
-// returns the original file name
-char* grfio_find_file(const char* fname)
+/// @copydoc grfio_interface::find_file()
+const char *grfio_find_file(const char *fname)
{
- FILELIST *flist = filelist_find(fname);
- if (!flist) return NULL;
+ struct grf_filelist *flist = grfio_filelist_find(fname);
+ if (flist == NULL)
+ return NULL;
return (!flist->fnd ? flist->fn : flist->fnd);
}
-// adds a FILELIST entry into the list of loaded files
-static FILELIST* filelist_add(FILELIST* entry) {
+/**
+ * Adds a grf_filelist entry into the list of loaded files.
+ *
+ * @param entry The entry to add.
+ * @return A pointer to the added entry.
+ */
+static struct grf_filelist *grfio_filelist_add(struct grf_filelist *entry)
+{
int hash;
nullpo_ret(entry);
#ifdef __clang_analyzer__
@@ -331,16 +377,16 @@ static FILELIST* filelist_add(FILELIST* entry) {
#define FILELIST_ADDS 1024 // number increment of file lists `
if (filelist_entrys >= filelist_maxentry) {
- filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST));
- memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST));
+ filelist = aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(struct grf_filelist));
+ memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(struct grf_filelist));
filelist_maxentry += FILELIST_ADDS;
}
#undef FILELIST_ADDS
- memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST));
+ memcpy(&filelist[filelist_entrys], entry, sizeof(struct grf_filelist));
- hash = filehash(entry->fn);
+ hash = grf_filehash(entry->fn);
filelist[filelist_entrys].next = filelist_hash[hash];
filelist_hash[hash] = filelist_entrys;
@@ -349,73 +395,82 @@ static FILELIST* filelist_add(FILELIST* entry) {
return &filelist[filelist_entrys - 1];
}
-// adds a new FILELIST entry or overwrites an existing one
-static FILELIST* filelist_modify(FILELIST* entry)
+/**
+ * Adds a new grf_filelist entry or overwrites an existing one.
+ *
+ * @param entry The entry to add.
+ * @return A pointer to the added entry.
+ */
+static struct grf_filelist *grfio_filelist_modify(struct grf_filelist *entry)
{
- FILELIST* fentry = filelist_find(entry->fn);
+ struct grf_filelist *fentry;
+ nullpo_retr(NULL, entry);
+ fentry = grfio_filelist_find(entry->fn);
if (fentry != NULL) {
int tmp = fentry->next;
- memcpy(fentry, entry, sizeof(FILELIST));
+ memcpy(fentry, entry, sizeof(struct grf_filelist));
fentry->next = tmp;
} else {
- fentry = filelist_add(entry);
+ fentry = grfio_filelist_add(entry);
}
return fentry;
}
-// shrinks the file list array if too long
-static void filelist_compact(void)
+/// Shrinks the file list array if too long.
+static void grfio_filelist_compact(void)
{
if (filelist == NULL)
return;
if (filelist_entrys < filelist_maxentry) {
- filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST));
+ filelist = aRealloc(filelist, filelist_entrys * sizeof(struct grf_filelist));
filelist_maxentry = filelist_entrys;
}
}
-/***********************************************************
- *** Grfio Subroutines ***
- ***********************************************************/
+/* GRF I/O Subroutines */
-/// Combines are resource path with the data folder location to create local resource path.
-static void grfio_localpath_create(char* buffer, size_t size, const char* filename)
+/**
+ * Combines a resource path with the data folder location to create local
+ * resource path.
+ *
+ * @param[out] buffer The output buffer.
+ * @param[in] size The size of the output buffer.
+ * @param[in] filename Resource path.
+ */
+static void grfio_localpath_create(char *buffer, size_t size, const char *filename)
{
- unsigned int i;
+ int i;
size_t len;
+ nullpo_retv(buffer);
len = strlen(data_dir);
- if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' )
- {
+ if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\')
safesnprintf(buffer, size, "%s%s", data_dir, filename);
- }
else
- {
safesnprintf(buffer, size, "%s/%s", data_dir, filename);
- }
// normalize path
- for( i = 0; buffer[i] != '\0'; ++i )
- if( buffer[i] == '\\' )
+ for (i = 0; buffer[i] != '\0'; ++i)
+ if (buffer[i] == '\\')
buffer[i] = '/';
}
-/// Reads a file into a newly allocated buffer (from grf or data directory).
+/// @copydoc grfio_interface::reads()
void *grfio_reads(const char *fname, int *size)
{
- FILELIST* entry = filelist_find(fname);
+ struct grf_filelist *entry = grfio_filelist_find(fname);
if (entry == NULL || entry->gentry <= 0) {
// LocalFileCheck
char lfname[256];
FILE *in;
- unsigned char *buf = NULL;
grfio_localpath_create(lfname, sizeof(lfname), (entry && entry->fnd) ? entry->fnd : fname);
in = fopen(lfname, "rb");
if (in != NULL) {
int declen;
+ unsigned char *buf = NULL;
fseek(in,0,SEEK_END);
declen = (int)ftell(in);
if (declen == -1) {
@@ -424,7 +479,7 @@ void *grfio_reads(const char *fname, int *size)
return NULL;
}
fseek(in,0,SEEK_SET);
- buf = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination
+ buf = aMalloc(declen+1); // +1 for resnametable zero-termination
buf[declen] = '\0';
if (fread(buf, 1, declen, in) != (size_t)declen) {
ShowError("An error occurred in fread grfio_reads, fname=%s \n",fname);
@@ -454,7 +509,7 @@ void *grfio_reads(const char *fname, int *size)
if (in != NULL) {
int fsize = entry->srclen_aligned;
- unsigned char *buf = (unsigned char *)aMalloc(fsize);
+ unsigned char *buf = aMalloc(fsize);
unsigned char *buf2 = NULL;
if (fseek(in, entry->srcpos, SEEK_SET) != 0
|| fread(buf, 1, fsize, in) != (size_t)fsize) {
@@ -465,14 +520,14 @@ void *grfio_reads(const char *fname, int *size)
}
fclose(in);
- buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination
+ buf2 = aMalloc(entry->declen+1); // +1 for resnametable zero-termination
buf2[entry->declen] = '\0';
if (entry->type & FILELIST_TYPE_FILE) {
// file
uLongf len;
grf_decode(buf, fsize, entry->type, entry->srclen);
len = entry->declen;
- decode_zip(buf2, &len, buf, entry->srclen);
+ grfio->decode_zip(buf2, &len, buf, entry->srclen);
if (len != (uLong)entry->declen) {
ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen);
aFree(buf);
@@ -498,49 +553,69 @@ void *grfio_reads(const char *fname, int *size)
return NULL;
}
-/// Decodes encrypted filename from a version 01xx grf index.
-static char* decode_filename(unsigned char* buf, int len)
+/**
+ * Decodes encrypted filename from a version 01xx grf index.
+ *
+ * @param[in,out] buf The encrypted filename (decrypted in-place).
+ * @param[in] len The filename length.
+ * @return A pointer to the decrypted filename.
+ */
+static char *grfio_decode_filename(unsigned char *buf, int len)
{
- int lop;
- for(lop=0;lop<len;lop+=8) {
- NibbleSwap(&buf[lop],8);
- des_decrypt(&buf[lop],8);
+ int i;
+ nullpo_retr(NULL, buf);
+ for (i = 0; i < len; i += 8) {
+ NibbleSwap(&buf[i],8);
+ des->decrypt(&buf[i],8);
}
return (char*)buf;
}
-/// Compares file extension against known large file types.
-/// @return true if the file should undergo full mode 0 decryption, and true otherwise.
-static bool isFullEncrypt(const char* fname)
+/**
+ * Compares file extension against known large file types.
+ *
+ * @param fname The file name.
+ * @return true if the file should undergo full mode 0 decryption, and true otherwise.
+ */
+static bool grfio_is_full_encrypt(const char *fname)
{
- const char* ext = strrchr(fname, '.');
- if( ext != NULL ) {
- static const char extensions[4][5] = { ".gnd", ".gat", ".act", ".str" };
- size_t i;
- for( i = 0; i < ARRAYLENGTH(extensions); ++i )
- if( strcmpi(ext, extensions[i]) == 0 )
+ const char *ext;
+ nullpo_retr(false, fname);
+ ext = strrchr(fname, '.');
+ if (ext != NULL) {
+ static const char *extensions[] = { ".gnd", ".gat", ".act", ".str" };
+ int i;
+ for (i = 0; i < ARRAYLENGTH(extensions); ++i)
+ if (strcmpi(ext, extensions[i]) == 0)
return false;
}
return true;
}
-/// Loads all entries in the specified grf file into the filelist.
-/// @param gentry index of the grf file name in the gentry_table
+/**
+ * Loads all entries in the specified grf file into the filelist.
+ *
+ * @param grfname Name of the grf file.
+ * @param gentry Index of the grf file name in the gentry_table.
+ * @return Error code.
+ * @retval 0 in case of success.
+ */
static int grfio_entryread(const char *grfname, int gentry)
{
long grf_size;
unsigned char grf_header[0x2e] = { 0 };
int entry,entrys,ofs,grf_version;
unsigned char *grf_filelist;
+ FILE *fp;
- FILE *fp = fopen(grfname, "rb");
- if( fp == NULL ) {
- ShowWarning("GRF data file not found: '%s'\n",grfname);
+ nullpo_retr(1, grfname);
+ fp = fopen(grfname, "rb");
+ if (fp == NULL) {
+ ShowWarning("GRF data file not found: '%s'\n", grfname);
return 1; // 1:not found error
- } else {
- ShowInfo("GRF data file found: '%s'\n",grfname);
}
+ ShowInfo("GRF data file found: '%s'\n", grfname);
fseek(fp,0,SEEK_END);
grf_size = ftell(fp);
@@ -551,7 +626,7 @@ static int grfio_entryread(const char *grfname, int gentry)
fclose(fp);
return 2; // 2:file format error
}
- if (strcmp((const char*)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0) {
+ if (strcmp((const char*)grf_header, "Master of Magic") != 0 || fseek(fp, getlong(grf_header+0x1e), SEEK_CUR) != 0) {
fclose(fp);
ShowError("GRF %s read error\n", grfname);
return 2; // 2:file format error
@@ -561,9 +636,8 @@ static int grfio_entryread(const char *grfname, int gentry)
if (grf_version == 0x01) {
// ****** Grf version 01xx ******
- long list_size;
- list_size = grf_size - ftell(fp);
- grf_filelist = (unsigned char *)aMalloc(list_size);
+ long list_size = grf_size - ftell(fp);
+ grf_filelist = aMalloc(list_size);
if (fread(grf_filelist,1,list_size,fp) != (size_t)list_size) {
ShowError("Couldn't read all grf_filelist element of %s \n", grfname);
aFree(grf_filelist);
@@ -576,11 +650,11 @@ static int grfio_entryread(const char *grfname, int gentry)
// Get an entry
for (entry = 0, ofs = 0; entry < entrys; ++entry) {
- FILELIST aentry;
+ struct grf_filelist aentry = { 0 };
int ofs2 = ofs+getlong(grf_filelist+ofs)+4;
unsigned char type = grf_filelist[ofs2+12];
if (type&FILELIST_TYPE_FILE) {
- char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6);
+ char *fname = grfio_decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6);
int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715;
if (strlen(fname) > sizeof(aentry.fn) - 1) {
@@ -589,7 +663,7 @@ static int grfio_entryread(const char *grfname, int gentry)
return 5; // 5: file name too long
}
- type |= isFullEncrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER;
+ type |= grfio_is_full_encrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER;
aentry.srclen = srclen;
aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579;
@@ -603,7 +677,7 @@ static int grfio_entryread(const char *grfname, int gentry)
#else
aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck
#endif
- filelist_modify(&aentry);
+ grfio_filelist_modify(&aentry);
}
ofs = ofs2 + 17;
@@ -630,7 +704,7 @@ static int grfio_entryread(const char *grfname, int gentry)
return 4;
}
- rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size
+ rBuf = aMalloc(rSize); // Get a Read Size
if (fread(rBuf,1,rSize,fp) != rSize) {
ShowError("An error occurred in fread \n");
fclose(fp);
@@ -638,8 +712,8 @@ static int grfio_entryread(const char *grfname, int gentry)
return 4;
}
fclose(fp);
- grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size
- decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function
+ grf_filelist = aMalloc(eSize); // Get a Extend Size
+ grfio->decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function
aFree(rBuf);
entrys = getlong(grf_header+0x26) - 7;
@@ -647,7 +721,7 @@ static int grfio_entryread(const char *grfname, int gentry)
// Get an entry
for (entry = 0, ofs = 0; entry < entrys; ++entry) {
- FILELIST aentry;
+ struct grf_filelist aentry;
char *fname = (char*)(grf_filelist+ofs);
int ofs2 = ofs + (int)strlen(fname)+1;
int type = grf_filelist[ofs2+12];
@@ -672,84 +746,90 @@ static int grfio_entryread(const char *grfname, int gentry)
#else
aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck
#endif
- filelist_modify(&aentry);
+ grfio_filelist_modify(&aentry);
}
ofs = ofs2 + 17;
}
aFree(grf_filelist);
- } else {// ****** Grf Other version ******
+ } else {
+ // ****** Grf Other version ******
fclose(fp);
ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a));
return 4;
}
- filelist_compact(); // Unnecessary area release of filelist
+ grfio_filelist_compact(); // Unnecessary area release of filelist
return 0; // 0:no error
}
-static bool grfio_parse_restable_row(const char* row)
+/**
+ * Parses a Resource file table row.
+ *
+ * @param row The row data.
+ * @return success state.
+ * @retval true in case of success.
+ */
+static bool grfio_parse_restable_row(const char *row)
{
char w1[256], w2[256];
char src[256], dst[256];
char local[256];
- FILELIST* entry;
+ struct grf_filelist *entry = NULL;
+ nullpo_retr(false, row);
if (sscanf(row, "%255[^#\r\n]#%255[^#\r\n]#", w1, w2) != 2)
return false;
- if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL )
+ if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL)
return false; // we only need the maps' GAT and RSW files
sprintf(src, "data\\%s", w1);
sprintf(dst, "data\\%s", w2);
- entry = filelist_find(dst);
- if( entry != NULL )
- {// alias for GRF resource
- FILELIST fentry;
- memcpy(&fentry, entry, sizeof(FILELIST));
+ entry = grfio_filelist_find(dst);
+ if (entry != NULL) {
+ // alias for GRF resource
+ struct grf_filelist fentry = *entry;
safestrncpy(fentry.fn, src, sizeof(fentry.fn));
fentry.fnd = aStrdup(dst);
- filelist_modify(&fentry);
+ grfio_filelist_modify(&fentry);
return true;
}
grfio_localpath_create(local, sizeof(local), dst);
- if( exists(local) )
- {// alias for local resource
- FILELIST fentry;
- memset(&fentry, 0, sizeof(fentry));
+ if (exists(local)) {
+ // alias for local resource
+ struct grf_filelist fentry = { 0 };
safestrncpy(fentry.fn, src, sizeof(fentry.fn));
fentry.fnd = aStrdup(dst);
- filelist_modify(&fentry);
+ grfio_filelist_modify(&fentry);
return true;
}
return false;
}
-/// Grfio Resource file check.
+/**
+ * Grfio Resource file check.
+ */
static void grfio_resourcecheck(void)
{
char restable[256];
- char *buf;
- int size;
- FILE* fp;
- int i = 0;
+ char *buf = NULL;
+ FILE *fp = NULL;
+ int size = 0, i = 0;
// read resnametable from data directory and return if successful
grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt");
fp = fopen(restable, "rb");
- if( fp != NULL )
- {
+ if (fp != NULL) {
char line[256];
- while( fgets(line, sizeof(line), fp) )
- {
- if( grfio_parse_restable_row(line) )
+ while (fgets(line, sizeof(line), fp)) {
+ if (grfio_parse_restable_row(line))
++i;
}
@@ -759,20 +839,19 @@ static void grfio_resourcecheck(void)
}
// read resnametable from loaded GRF's, only if it cannot be loaded from the data directory
- buf = (char *)grfio_reads("data\\resnametable.txt", &size);
- if( buf != NULL )
- {
- char *ptr;
+ buf = grfio->reads("data\\resnametable.txt", &size);
+ if (buf != NULL) {
+ char *ptr = NULL;
buf[size] = '\0';
ptr = buf;
- while( ptr - buf < size )
- {
- if( grfio_parse_restable_row(ptr) )
+ while (ptr - buf < size) {
+ if (grfio_parse_restable_row(ptr))
++i;
ptr = strchr(ptr, '\n');
- if( ptr == NULL ) break;
+ if (ptr == NULL)
+ break;
ptr++;
}
@@ -782,13 +861,20 @@ static void grfio_resourcecheck(void)
}
}
-/// Reads a grf file and adds it to the list.
-static int grfio_add(const char* fname)
+/**
+ * Reads a grf file and adds it to the list.
+ *
+ * @param fname The file name to read.
+ * @return Error code.
+ * @retval 0 in case of success.
+ */
+static int grfio_add(const char *fname)
{
+ nullpo_retr(1, fname);
if (gentry_entrys >= gentry_maxentry) {
#define GENTRY_ADDS 4 // The number increment of gentry_table entries
gentry_maxentry += GENTRY_ADDS;
- gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*));
+ gentry_table = aRealloc(gentry_table, gentry_maxentry * sizeof(char*));
memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS);
#undef GENTRY_ADDS
}
@@ -798,7 +884,7 @@ static int grfio_add(const char* fname)
return grfio_entryread(fname, gentry_entrys - 1);
}
-/// Finalizes grfio.
+/// @copydoc grfio_interface::final()
void grfio_final(void)
{
if (filelist != NULL) {
@@ -824,36 +910,34 @@ void grfio_final(void)
gentry_entrys = gentry_maxentry = 0;
}
-/// Initializes grfio.
-void grfio_init(const char* fname)
+/// @copydoc grfio_interface::init()
+void grfio_init(const char *fname)
{
- FILE* data_conf;
+ FILE *data_conf;
int grf_num = 0;
+ nullpo_retv(fname);
hashinit(); // hash table initialization
data_conf = fopen(fname, "r");
- if( data_conf != NULL )
- {
+ if (data_conf != NULL) {
char line[1024];
- while( fgets(line, sizeof(line), data_conf) )
- {
+ while (fgets(line, sizeof(line), data_conf)) {
char w1[1024], w2[1024];
- if( line[0] == '/' && line[1] == '/' )
+ if (line[0] == '/' && line[1] == '/')
continue; // skip comments
if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
continue; // skip unrecognized lines
// Entry table reading
- if( strcmp(w1, "grf") == 0 ) // GRF file
- {
- if( grfio_add(w2) == 0 )
+ if (strcmp(w1, "grf") == 0) {
+ // GRF file
+ if (grfio_add(w2) == 0)
++grf_num;
- }
- else if( strcmp(w1,"data_dir") == 0 ) // Data directory
- {
+ } else if (strcmp(w1,"data_dir") == 0) {
+ // Data directory
safestrncpy(data_dir, w2, sizeof(data_dir));
}
}
@@ -862,12 +946,25 @@ void grfio_init(const char* fname)
ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname);
}
- if( grf_num == 0 )
+ if (grf_num == 0)
ShowInfo("No GRF loaded, using default data directory\n");
// Unnecessary area release of filelist
- filelist_compact();
+ grfio_filelist_compact();
// Resource check
grfio_resourcecheck();
}
+
+/// Interface base initialization.
+void grfio_defaults(void)
+{
+ grfio = &grfio_s;
+ grfio->init = grfio_init;
+ grfio->final = grfio_final;
+ grfio->reads = grfio_reads;
+ grfio->find_file = grfio_find_file;
+ grfio->crc32 = grfio_crc32;
+ grfio->decode_zip = grfio_decode_zip;
+ grfio->encode_zip = grfio_encode_zip;
+}
diff --git a/src/common/grfio.h b/src/common/grfio.h
index 36ed8fb39..857bc507e 100644
--- a/src/common/grfio.h
+++ b/src/common/grfio.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,16 +21,104 @@
#ifndef COMMON_GRFIO_H
#define COMMON_GRFIO_H
+#include "common/hercules.h"
+
+/** @file
+ * GRF I/O library.
+ */
+
+/// The GRF I/O interface.
+struct grfio_interface {
+ /**
+ * Interface initialization.
+ *
+ * @param fname Name of the configuration file.
+ */
+ void (*init) (const char *fname);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Reads a file into a newly allocated buffer (from grf or data directory).
+ *
+ * @param[in] fname Name of the file to read.
+ * @param[out] size Buffer to return the size of the read file (optional).
+ * @return The file data.
+ * @retval NULL in case of error.
+ */
+ void *(*reads) (const char *fname, int *size);
+
+ /**
+ * Finds a file in the grf or data directory
+ *
+ * @param fname The file to find.
+ * @return The original file name.
+ * @retval NULL if the file wasn't found.
+ */
+ const char *(*find_file) (const char *fname);
+
+ /**
+ * Calculates a CRC32 hash.
+ *
+ * @param buf The data to hash.
+ * @param len Data length.
+ *
+ * @return The CRC32 hash.
+ */
+ unsigned long (*crc32) (const unsigned char *buf, unsigned int len);
+
+ /**
+ * Decompresses ZIP data.
+ *
+ * Decompresses the source buffer into the destination buffer.
+ * source_len is the byte length of the source buffer. Upon entry,
+ * dest_len is the total size of the destination buffer, which must be
+ * large enough to hold the entire uncompressed data. (The size of the
+ * uncompressed data must have been saved previously by the compressor
+ * and transmitted to the decompressor by some mechanism outside the
+ * scope of this compression library.) Upon exit, dest_len is the
+ * actual size of the uncompressed buffer.
+ *
+ * @param[in,out] dest The destination (uncompressed) buffer.
+ * @param[in,out] dest_len Max length of the destination buffer, returns length of the decompressed data.
+ * @param[in] source The source (compressed) buffer.
+ * @param[in] source_len Source data length.
+ * @return error code.
+ * @retval Z_OK in case of success.
+ */
+ int (*decode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len);
+
+ /**
+ * Compresses data to ZIP format.
+ *
+ * Compresses the source buffer into the destination buffer.
+ * source_len is the byte length of the source buffer. Upon entry,
+ * dest_len is the total size of the destination buffer, which must be
+ * at least the value returned by compressBound(source_len). Upon
+ * exit, dest_len is the actual size of the compressed buffer.
+ *
+ * @param[in,out] dest The destination (compressed) buffer (if NULL, a new buffer will be created).
+ * @param[in,out] dest_len Max length of the destination buffer (if 0, it will be calculated).
+ * @param[in] source The source (uncompressed) buffer.
+ * @param[in] source_len Source data length.
+ */
+ int (*encode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len);
+};
+
+/**
+ * Reads a file into a newly allocated buffer (from grf or data directory)
+ *
+ * @param fn The filename to read.
+ *
+ * @see grfio_interface::reads()
+ * @related grfio_interface
+ */
+#define grfio_read(fn) grfio->reads((fn), NULL)
+
#ifdef HERCULES_CORE
-void grfio_init(const char* fname);
-void grfio_final(void);
-void* grfio_reads(const char* fname, int* size);
-char* grfio_find_file(const char* fname);
-#define grfio_read(fn) grfio_reads((fn), NULL)
-
-unsigned long grfio_crc32(const unsigned char *buf, unsigned int len);
-int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
-int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
+void grfio_defaults(void);
#endif // HERCULES_CORE
+HPShared struct grfio_interface *grfio; ///< Pointer to the grfio interface.
#endif /* COMMON_GRFIO_H */
diff --git a/src/common/mapindex.c b/src/common/mapindex.c
index 5b0f6169b..e16eb4216 100644
--- a/src/common/mapindex.c
+++ b/src/common/mapindex.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "common/cbasetypes.h"
#include "common/db.h"
#include "common/mmo.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
@@ -37,11 +38,14 @@ struct mapindex_interface *mapindex;
/// Retrieves the map name from 'string' (removing .gat extension if present).
/// Result gets placed either into 'buf' or in a static local buffer.
-const char* mapindex_getmapname(const char* string, char* output) {
+const char* mapindex_getmapname(const char* string, char* output)
+{
static char buf[MAP_NAME_LENGTH];
char* dest = (output != NULL) ? output : buf;
- size_t len = strnlen(string, MAP_NAME_LENGTH_EXT);
+ size_t len;
+ nullpo_retr(buf, string);
+ len = strnlen(string, MAP_NAME_LENGTH_EXT);
if (len == MAP_NAME_LENGTH_EXT) {
ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string);
len--;
@@ -58,12 +62,15 @@ const char* mapindex_getmapname(const char* string, char* output) {
/// Retrieves the map name from 'string' (adding .gat extension if not already present).
/// Result gets placed either into 'buf' or in a static local buffer.
-const char* mapindex_getmapname_ext(const char* string, char* output) {
+const char* mapindex_getmapname_ext(const char* string, char* output)
+{
static char buf[MAP_NAME_LENGTH_EXT];
char* dest = (output != NULL) ? output : buf;
size_t len;
+ nullpo_retr(buf, string);
+
safestrncpy(buf,string, sizeof(buf));
sscanf(string, "%*[^#]%*[#]%15s", buf);
@@ -87,7 +94,8 @@ const char* mapindex_getmapname_ext(const char* string, char* output) {
/// Adds a map to the specified index
/// Returns 1 if successful, 0 otherwise
-int mapindex_addmap(int index, const char* name) {
+int mapindex_addmap(int index, const char* name)
+{
char map_name[MAP_NAME_LENGTH];
if (index == -1){
@@ -128,7 +136,8 @@ int mapindex_addmap(int index, const char* name) {
return index;
}
-unsigned short mapindex_name2id(const char* name) {
+unsigned short mapindex_name2id(const char* name)
+{
int i;
char map_name[MAP_NAME_LENGTH];
@@ -141,7 +150,8 @@ unsigned short mapindex_name2id(const char* name) {
return 0;
}
-const char *mapindex_id2name_sub(uint16 id, const char *file, int line, const char *func) {
+const char *mapindex_id2name_sub(uint16 id, const char *file, int line, const char *func)
+{
if (id >= MAX_MAPINDEX || !mapindex_exists(id)) {
ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache. %s:%s:%d\n", id,file,func,line);
return mapindex->list[0].name; // dummy empty string so that the callee doesn't crash
@@ -149,7 +159,8 @@ const char *mapindex_id2name_sub(uint16 id, const char *file, int line, const ch
return mapindex->list[id].name;
}
-int mapindex_init(void) {
+int mapindex_init(void)
+{
FILE *fp;
char line[1024];
int last_index = -1;
@@ -196,16 +207,20 @@ bool mapindex_check_default(void)
return true;
}
-void mapindex_removemap(int index){
+void mapindex_removemap(int index)
+{
+ Assert_retv(index < MAX_MAPINDEX);
strdb_remove(mapindex->db, mapindex->list[index].name);
mapindex->list[index].name[0] = '\0';
}
-void mapindex_final(void) {
+void mapindex_final(void)
+{
db_destroy(mapindex->db);
}
-void mapindex_defaults(void) {
+void mapindex_defaults(void)
+{
mapindex = &mapindex_s;
/* TODO: place it in inter-server.conf? */
diff --git a/src/common/mapindex.h b/src/common/mapindex.h
index 3fb170c1f..91f59aeaf 100644
--- a/src/common/mapindex.h
+++ b/src/common/mapindex.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -22,9 +22,11 @@
#define COMMON_MAPINDEX_H
#include "common/hercules.h"
-#include "common/db.h"
#include "common/mmo.h"
+/* Forward Declarations */
+struct DBMap; // common/db.h
+
#define MAX_MAPINDEX 2000
/* wohoo, someone look at all those |: map_default could (or *should*) be a char-server.conf */
@@ -82,7 +84,7 @@
struct mapindex_interface {
char config_file[80];
/* mapname (str) -> index (int) */
- DBMap *db;
+ struct DBMap *db;
/* number of entries in the index table */
int num;
/* default map name */
diff --git a/src/common/md5calc.c b/src/common/md5calc.c
index 44f912992..d2fc32371 100644
--- a/src/common/md5calc.c
+++ b/src/common/md5calc.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -20,27 +20,27 @@
*/
#define HERCULES_CORE
-/***********************************************************
- * md5 calculation algorithm
- *
- * The source code referred to the following URL.
- * http://www.geocities.co.jp/SiliconValley-Oakland/8878/lab17/lab17.html
- *
- ***********************************************************/
-
#include "md5calc.h"
#include "common/cbasetypes.h"
+#include "common/nullpo.h"
#include "common/random.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-// Global variable
+/** @file
+ * Implementation of the md5 interface.
+ */
+
+struct md5_interface md5_s;
+struct md5_interface *md5;
+
+/// Global variable
static unsigned int *pX;
-// String Table
+/// String Table
static const unsigned int T[] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4
@@ -60,99 +60,102 @@ static const unsigned int T[] = {
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60
};
-// ROTATE_LEFT The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC.
+/// The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// The function used for other calculation
-static unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)
+static unsigned int md5_F(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Y) | (~X & Z);
}
-static unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_G(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Z) | (Y & ~Z);
}
-static unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_H(unsigned int X, unsigned int Y, unsigned int Z)
{
return X ^ Y ^ Z;
}
-static unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_I(unsigned int X, unsigned int Y, unsigned int Z)
{
return Y ^ (X | ~Z);
}
-static unsigned int Round(unsigned int a, unsigned int b, unsigned int FGHI,
+static unsigned int md5_Round(unsigned int a, unsigned int b, unsigned int FGHI,
unsigned int k, unsigned int s, unsigned int i)
{
return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s);
}
-static void Round1(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round1(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, F(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_F(b,c,d), k, s, i);
}
-static void Round2(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round2(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, G(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_G(b,c,d), k, s, i);
}
-static void Round3(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round3(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, H(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_H(b,c,d), k, s, i);
}
-static void Round4(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round4(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, I(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_I(b,c,d), k, s, i);
}
-static void MD5_Round_Calculate(const unsigned char *block,
+static void md5_Round_Calculate(const unsigned char *block,
unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2)
{
//create X It is since it is required.
unsigned int X[16]; //512bit 64byte
- int j,k;
+ int j, k;
//Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D)
- unsigned int A=*A2, B=*B2, C=*C2, D=*D2;
- unsigned int AA = A,BB = B,CC = C,DD = D;
+ unsigned int A = *A2, B = *B2, C = *C2, D = *D2;
+ unsigned int AA = A, BB = B, CC = C, DD = D;
//It is a large region variable reluctantly because of calculation of a round. . . for Round1...4
pX = X;
//Copy block(padding_message) i into X
- for (j=0,k=0; j<64; j+=4,k++)
- X[k] = ( (unsigned int )block[j] ) // 8byte*4 -> 32byte conversion
- | ( ((unsigned int )block[j+1]) << 8 ) // A function called Decode as used in the field of RFC
- | ( ((unsigned int )block[j+2]) << 16 )
- | ( ((unsigned int )block[j+3]) << 24 );
-
+ for (j = 0, k = 0; j < 64; j += 4, k++) {
+ X[k] = ((unsigned int)block[j]) // 8byte*4 -> 32byte conversion
+ | (((unsigned int)block[j+1]) << 8) // A function called Decode as used in the field of RFC
+ | (((unsigned int)block[j+2]) << 16)
+ | (((unsigned int)block[j+3]) << 24);
+ }
//Round 1
- Round1(&A,B,C,D, 0, 7, 0); Round1(&D,A,B,C, 1, 12, 1); Round1(&C,D,A,B, 2, 17, 2); Round1(&B,C,D,A, 3, 22, 3);
- Round1(&A,B,C,D, 4, 7, 4); Round1(&D,A,B,C, 5, 12, 5); Round1(&C,D,A,B, 6, 17, 6); Round1(&B,C,D,A, 7, 22, 7);
- Round1(&A,B,C,D, 8, 7, 8); Round1(&D,A,B,C, 9, 12, 9); Round1(&C,D,A,B, 10, 17, 10); Round1(&B,C,D,A, 11, 22, 11);
- Round1(&A,B,C,D, 12, 7, 12); Round1(&D,A,B,C, 13, 12, 13); Round1(&C,D,A,B, 14, 17, 14); Round1(&B,C,D,A, 15, 22, 15);
+ md5_Round1(&A,B,C,D, 0, 7, 0); md5_Round1(&D,A,B,C, 1, 12, 1); md5_Round1(&C,D,A,B, 2, 17, 2); md5_Round1(&B,C,D,A, 3, 22, 3);
+ md5_Round1(&A,B,C,D, 4, 7, 4); md5_Round1(&D,A,B,C, 5, 12, 5); md5_Round1(&C,D,A,B, 6, 17, 6); md5_Round1(&B,C,D,A, 7, 22, 7);
+ md5_Round1(&A,B,C,D, 8, 7, 8); md5_Round1(&D,A,B,C, 9, 12, 9); md5_Round1(&C,D,A,B, 10, 17, 10); md5_Round1(&B,C,D,A, 11, 22, 11);
+ md5_Round1(&A,B,C,D, 12, 7, 12); md5_Round1(&D,A,B,C, 13, 12, 13); md5_Round1(&C,D,A,B, 14, 17, 14); md5_Round1(&B,C,D,A, 15, 22, 15);
//Round 2
- Round2(&A,B,C,D, 1, 5, 16); Round2(&D,A,B,C, 6, 9, 17); Round2(&C,D,A,B, 11, 14, 18); Round2(&B,C,D,A, 0, 20, 19);
- Round2(&A,B,C,D, 5, 5, 20); Round2(&D,A,B,C, 10, 9, 21); Round2(&C,D,A,B, 15, 14, 22); Round2(&B,C,D,A, 4, 20, 23);
- Round2(&A,B,C,D, 9, 5, 24); Round2(&D,A,B,C, 14, 9, 25); Round2(&C,D,A,B, 3, 14, 26); Round2(&B,C,D,A, 8, 20, 27);
- Round2(&A,B,C,D, 13, 5, 28); Round2(&D,A,B,C, 2, 9, 29); Round2(&C,D,A,B, 7, 14, 30); Round2(&B,C,D,A, 12, 20, 31);
+ md5_Round2(&A,B,C,D, 1, 5, 16); md5_Round2(&D,A,B,C, 6, 9, 17); md5_Round2(&C,D,A,B, 11, 14, 18); md5_Round2(&B,C,D,A, 0, 20, 19);
+ md5_Round2(&A,B,C,D, 5, 5, 20); md5_Round2(&D,A,B,C, 10, 9, 21); md5_Round2(&C,D,A,B, 15, 14, 22); md5_Round2(&B,C,D,A, 4, 20, 23);
+ md5_Round2(&A,B,C,D, 9, 5, 24); md5_Round2(&D,A,B,C, 14, 9, 25); md5_Round2(&C,D,A,B, 3, 14, 26); md5_Round2(&B,C,D,A, 8, 20, 27);
+ md5_Round2(&A,B,C,D, 13, 5, 28); md5_Round2(&D,A,B,C, 2, 9, 29); md5_Round2(&C,D,A,B, 7, 14, 30); md5_Round2(&B,C,D,A, 12, 20, 31);
//Round 3
- Round3(&A,B,C,D, 5, 4, 32); Round3(&D,A,B,C, 8, 11, 33); Round3(&C,D,A,B, 11, 16, 34); Round3(&B,C,D,A, 14, 23, 35);
- Round3(&A,B,C,D, 1, 4, 36); Round3(&D,A,B,C, 4, 11, 37); Round3(&C,D,A,B, 7, 16, 38); Round3(&B,C,D,A, 10, 23, 39);
- Round3(&A,B,C,D, 13, 4, 40); Round3(&D,A,B,C, 0, 11, 41); Round3(&C,D,A,B, 3, 16, 42); Round3(&B,C,D,A, 6, 23, 43);
- Round3(&A,B,C,D, 9, 4, 44); Round3(&D,A,B,C, 12, 11, 45); Round3(&C,D,A,B, 15, 16, 46); Round3(&B,C,D,A, 2, 23, 47);
+ md5_Round3(&A,B,C,D, 5, 4, 32); md5_Round3(&D,A,B,C, 8, 11, 33); md5_Round3(&C,D,A,B, 11, 16, 34); md5_Round3(&B,C,D,A, 14, 23, 35);
+ md5_Round3(&A,B,C,D, 1, 4, 36); md5_Round3(&D,A,B,C, 4, 11, 37); md5_Round3(&C,D,A,B, 7, 16, 38); md5_Round3(&B,C,D,A, 10, 23, 39);
+ md5_Round3(&A,B,C,D, 13, 4, 40); md5_Round3(&D,A,B,C, 0, 11, 41); md5_Round3(&C,D,A,B, 3, 16, 42); md5_Round3(&B,C,D,A, 6, 23, 43);
+ md5_Round3(&A,B,C,D, 9, 4, 44); md5_Round3(&D,A,B,C, 12, 11, 45); md5_Round3(&C,D,A,B, 15, 16, 46); md5_Round3(&B,C,D,A, 2, 23, 47);
//Round 4
- Round4(&A,B,C,D, 0, 6, 48); Round4(&D,A,B,C, 7, 10, 49); Round4(&C,D,A,B, 14, 15, 50); Round4(&B,C,D,A, 5, 21, 51);
- Round4(&A,B,C,D, 12, 6, 52); Round4(&D,A,B,C, 3, 10, 53); Round4(&C,D,A,B, 10, 15, 54); Round4(&B,C,D,A, 1, 21, 55);
- Round4(&A,B,C,D, 8, 6, 56); Round4(&D,A,B,C, 15, 10, 57); Round4(&C,D,A,B, 6, 15, 58); Round4(&B,C,D,A, 13, 21, 59);
- Round4(&A,B,C,D, 4, 6, 60); Round4(&D,A,B,C, 11, 10, 61); Round4(&C,D,A,B, 2, 15, 62); Round4(&B,C,D,A, 9, 21, 63);
+ md5_Round4(&A,B,C,D, 0, 6, 48); md5_Round4(&D,A,B,C, 7, 10, 49); md5_Round4(&C,D,A,B, 14, 15, 50); md5_Round4(&B,C,D,A, 5, 21, 51);
+ md5_Round4(&A,B,C,D, 12, 6, 52); md5_Round4(&D,A,B,C, 3, 10, 53); md5_Round4(&C,D,A,B, 10, 15, 54); md5_Round4(&B,C,D,A, 1, 21, 55);
+ md5_Round4(&A,B,C,D, 8, 6, 56); md5_Round4(&D,A,B,C, 15, 10, 57); md5_Round4(&C,D,A,B, 6, 15, 58); md5_Round4(&B,C,D,A, 13, 21, 59);
+ md5_Round4(&A,B,C,D, 4, 6, 60); md5_Round4(&D,A,B,C, 11, 10, 61); md5_Round4(&C,D,A,B, 2, 15, 62); md5_Round4(&B,C,D,A, 9, 21, 63);
// Then perform the following additions. (let's add)
*A2 = A + AA;
@@ -164,16 +167,16 @@ static void MD5_Round_Calculate(const unsigned char *block,
memset(pX, 0, sizeof(X));
}
-static void MD5_String2binary(const char * string, unsigned char * output)
+/// @copydoc md5_interface::binary()
+static void md5_buf2binary(const uint8 *buf, const int buf_size, uint8 *output)
{
//var
/*8bit*/
unsigned char padding_message[64]; //Extended message 512bit 64byte
- unsigned char *pstring; //The position of string in the present scanning notes is held.
+ const uint8 *pbuf; // The position of string in the present scanning notes is held.
/*32bit*/
- unsigned int string_byte_len, //The byte chief of string is held.
- string_bit_len, //The bit length of string is held.
+ unsigned int buf_bit_len, //The bit length of string is held.
copy_len, //The number of bytes which is used by 1-3 and which remained
msg_digest[4]; //Message digest 128bit 4byte
unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference)
@@ -191,59 +194,53 @@ static void MD5_String2binary(const char * string, unsigned char * output)
//Step 1.Append Padding Bits (extension of a mark bit)
//1-1
- string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired.
- pstring = (unsigned char *)string; //The position of the present character sequence is set.
+ pbuf = buf; // The position of the present character sequence is set.
//1-2 Repeat calculation until length becomes less than 64 bytes.
- for (i=string_byte_len; 64<=i; i-=64,pstring+=64)
- MD5_Round_Calculate(pstring, A,B,C,D);
+ for (i=buf_size; 64<=i; i-=64,pbuf+=64)
+ md5_Round_Calculate(pbuf, A,B,C,D);
//1-3
- copy_len = string_byte_len % 64; //The number of bytes which remained is computed.
- strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence.
+ copy_len = buf_size % 64; //The number of bytes which remained is computed.
+ strncpy((char *)padding_message, (const char *)pbuf, copy_len); // A message is copied to an extended bit sequence.
memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length.
padding_message[copy_len] |= 0x80; //The next of a message is 1.
//1-4
//If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes.
if (56 <= copy_len) {
- MD5_Round_Calculate(padding_message, A,B,C,D);
+ md5_Round_Calculate(padding_message, A,B,C,D);
memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0.
}
//Step 2.Append Length (the information on length is added)
- string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank)
- memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set.
+ buf_bit_len = buf_size * 8; //From the byte chief to bit length (32 bytes of low rank)
+ memcpy(&padding_message[56], &buf_bit_len, 4); //32 bytes of low rank is set.
//When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank.
- if (UINT_MAX / 8 < string_byte_len) {
- unsigned int high = (string_byte_len - UINT_MAX / 8) * 8;
+ if (UINT_MAX / 8 < (unsigned int)buf_size) {
+ unsigned int high = (buf_size - UINT_MAX / 8) * 8;
memcpy(&padding_message[60], &high, 4);
- } else
+ } else {
memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0.
+ }
//Step 4.Process Message in 16-Word Blocks (calculation of MD5)
- MD5_Round_Calculate(padding_message, A,B,C,D);
+ md5_Round_Calculate(padding_message, A,B,C,D);
//Step 5.Output (output)
memcpy(output,msg_digest,16);
}
-//-------------------------------------------------------------------
-// The function for the exteriors
-
-/** output is the coded binary in the character sequence which wants to code string. */
-void MD5_Binary(const char * string, unsigned char * output)
+/// @copydoc md5_interface::string()
+void md5_string(const char *string, char *output)
{
- MD5_String2binary(string,output);
-}
+ uint8 digest[16];
-/** output is the coded character sequence in the character sequence which wants to code string. */
-void MD5_String(const char *string, char *output)
-{
- unsigned char digest[16];
+ nullpo_retv(string);
+ nullpo_retv(output);
- MD5_String2binary(string,digest);
+ md5->binary((const uint8 *)string, (int)strlen(string), digest);
snprintf(output, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[ 0], digest[ 1], digest[ 2], digest[ 3],
digest[ 4], digest[ 5], digest[ 6], digest[ 7],
@@ -251,11 +248,24 @@ void MD5_String(const char *string, char *output)
digest[12], digest[13], digest[14], digest[15]);
}
-/** output is a sequence of non-zero characters to be used as password salt. */
-void MD5_Salt(unsigned int len, char * output)
+/// @copydoc md5_interface::salt();
+void md5_salt(int len, char *output)
{
- unsigned int i;
- for( i = 0; i < len; ++i )
+ int i;
+ Assert_retv(len > 0);
+
+ for (i = 0; i < len; ++i)
output[i] = (char)(1 + rnd() % 255);
}
+
+/**
+ * Interface base initialization.
+ */
+void md5_defaults(void)
+{
+ md5 = &md5_s;
+ md5->binary = md5_buf2binary;
+ md5->string = md5_string;
+ md5->salt = md5_salt;
+}
diff --git a/src/common/md5calc.h b/src/common/md5calc.h
index 0294c3ca1..f55ebe312 100644
--- a/src/common/md5calc.h
+++ b/src/common/md5calc.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,10 +21,46 @@
#ifndef COMMON_MD5CALC_H
#define COMMON_MD5CALC_H
+#include "common/hercules.h"
+
+/** @file
+ * md5 calculation algorithm.
+ *
+ * The source code referred to the following URL.
+ * http://www.geocities.co.jp/SiliconValley-Oakland/8878/lab17/lab17.html
+ */
+
+/// The md5 interface
+struct md5_interface {
+ /**
+ * Hashes a string, returning the hash in string format.
+ *
+ * @param[in] string The source string (NUL terminated).
+ * @param[out] output Output buffer (at least 33 bytes available).
+ */
+ void (*string) (const char *string, char *output);
+
+ /**
+ * Hashes a string, returning the buffer in binary format.
+ *
+ * @param[in] string The source string.
+ * @param[out] output Output buffer (at least 16 bytes available).
+ */
+ void (*binary) (const uint8 *buf, const int buf_size, uint8 *output);
+
+ /**
+ * Generates a random salt.
+ *
+ * @param[in] len The desired salt length.
+ * @param[out] output The output buffer (at least len bytes available).
+ */
+ void (*salt) (int len, char *output);
+};
+
#ifdef HERCULES_CORE
-void MD5_String(const char * string, char * output);
-void MD5_Binary(const char * string, unsigned char * output);
-void MD5_Salt(unsigned int len, char * output);
+void md5_defaults(void);
#endif // HERCULES_CORE
+HPShared struct md5_interface *md5; ///< Pointer to the md5 interface.
+
#endif /* COMMON_MD5CALC_H */
diff --git a/src/common/memmgr.c b/src/common/memmgr.c
index 93c23ff18..b80b4d4e9 100644
--- a/src/common/memmgr.c
+++ b/src/common/memmgr.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -97,10 +97,10 @@ struct malloc_interface *iMalloc;
#ifndef USE_MEMMGR
-#ifdef __APPLE__
+#if defined __APPLE__
#include <malloc/malloc.h>
#define BUFFER_SIZE(ptr) malloc_size(ptr)
-#elif __FreeBSD__
+#elif defined __FreeBSD__
#include <malloc_np.h>
#define BUFFER_SIZE(ptr) malloc_usable_size(ptr)
#elif defined __linux__ || defined __linux || defined CYGWIN
@@ -149,25 +149,25 @@ void* aRealloc_(void *p, size_t size, const char *file, int line, const char *fu
void* aReallocz_(void *p, size_t size, const char *file, int line, const char *func)
{
- void *ret;
+ unsigned char *ret = NULL;
// ShowMessage("%s:%d: in func %s: aReallocz %p %ld\n",file,line,func,p,size);
#ifdef USE_MEMMGR
ret = REALLOC(p, size, file, line, func);
#else
- size_t newSize;
- if (p) {
+ if (p != NULL) {
+ size_t newSize;
size_t oldSize = BUFFER_SIZE(p);
ret = REALLOC(p, size, file, line, func);
newSize = BUFFER_SIZE(ret);
- if (ret && newSize > oldSize)
+ if (ret != NULL && newSize > oldSize)
memset(ret + oldSize, 0, newSize - oldSize);
} else {
ret = REALLOC(p, size, file, line, func);
- if (ret)
+ if (ret != NULL)
memset(ret, 0, BUFFER_SIZE(ret));
}
#endif
- if (ret == NULL){
+ if (ret == NULL) {
ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func);
exit(EXIT_FAILURE);
}
@@ -184,6 +184,36 @@ char* aStrdup_(const char *p, const char *file, int line, const char *func)
}
return ret;
}
+
+/**
+ * Copies a string to a newly allocated buffer, setting a maximum length.
+ *
+ * The string is always NULL-terminated. If the string is longer than `size`,
+ * then `size` bytes are copied, not including the appended NULL terminator.
+ *
+ * @warning
+ * If malloc is out of memory, throws a fatal error and aborts the program.
+ *
+ * @param p the source string to copy.
+ * @param size The maximum string length to copy.
+ * @param file @see ALC_MARK.
+ * @param line @see ALC_MARK.
+ * @param func @see ALC_MARK.
+ * @return the copied string.
+ */
+char *aStrndup_(const char *p, size_t size, const char *file, int line, const char *func)
+{
+ size_t len = strnlen(p, size);
+ char *ret = MALLOC(len + 1, file, line, func);
+ if (ret == NULL) {
+ ShowFatalError("%s:%d: in func %s: aStrndup error out of memory!\n", file, line, func);
+ exit(EXIT_FAILURE);
+ }
+ memcpy(ret, p, len);
+ ret[len] = '\0';
+ return ret;
+}
+
void aFree_(void *p, const char *file, int line, const char *func)
{
// ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p);
@@ -305,7 +335,7 @@ void *mmalloc_(size_t size, const char *file, int line, const char *func) {
struct unit_head *head;
if (((long) size) < 0) {
- ShowError("mmalloc_: %"PRIdS"\n", size);
+ ShowError("mmalloc_: %"PRIuS"\n", size);
return NULL;
}
@@ -478,6 +508,37 @@ char *mstrdup_(const char *p, const char *file, int line, const char *func) {
}
}
+/**
+ * Copies a string to a newly allocated buffer, setting a maximum length.
+ *
+ * The string is always NULL-terminated. If the string is longer than `size`,
+ * then `size` bytes are copied, not including the appended NULL terminator.
+ *
+ * @warning
+ * If malloc is out of memory, throws a fatal error and aborts the program.
+ *
+ * @param p the source string to copy.
+ * @param size The maximum string length to copy.
+ * @param file @see ALC_MARK.
+ * @param line @see ALC_MARK.
+ * @param func @see ALC_MARK.
+ * @return the copied string.
+ * @retval NULL if the source string is NULL or in case of error.
+ */
+char *mstrndup_(const char *p, size_t size, const char *file, int line, const char *func)
+{
+ if (p == NULL) {
+ return NULL;
+ } else {
+ size_t len = strnlen(p, size);
+ char *string = iMalloc->malloc(len + 1, file, line, func);
+ memcpy(string, p, len);
+ string[len] = '\0';
+ return string;
+ }
+}
+
+
void mfree_(void *ptr, const char *file, int line, const char *func) {
struct unit_head *head;
@@ -820,7 +881,7 @@ void memmgr_report (int extra) {
}
for( j = 0; j < 100; j++ ) {
if( data[j].size != 0 ) {
- ShowMessage("[malloc] : "CL_WHITE"%s"CL_RESET":"CL_WHITE"%d"CL_RESET" %d instances => %.2f MB\n",data[j].file,data[j].line,data[j].count,(double)((data[j].size)/1024)/1024);
+ ShowMessage("[malloc] : "CL_WHITE"%s"CL_RESET":"CL_WHITE"%d"CL_RESET" %u instances => %.2f MB\n",data[j].file,data[j].line,data[j].count,(double)((data[j].size)/1024)/1024);
}
}
ShowMessage("[malloc] : reporting %u instances | %.2f MB\n",count,(double)((size)/1024)/1024);
@@ -947,6 +1008,7 @@ void malloc_defaults(void) {
iMalloc->realloc = mrealloc_;
iMalloc->reallocz = mreallocz_;
iMalloc->astrdup = mstrdup_;
+ iMalloc->astrndup = mstrndup_;
iMalloc->free = mfree_;
#else
iMalloc->malloc = aMalloc_;
@@ -954,6 +1016,7 @@ void malloc_defaults(void) {
iMalloc->realloc = aRealloc_;
iMalloc->reallocz = aReallocz_;/* not using memory manager huhum o.o perhaps we could still do something about */
iMalloc->astrdup = aStrdup_;
+ iMalloc->astrndup = aStrndup_;
iMalloc->free = aFree_;
#endif
iMalloc->post_shutdown = NULL;
diff --git a/src/common/memmgr.h b/src/common/memmgr.h
index 5975f55c4..6381c5bfa 100644
--- a/src/common/memmgr.h
+++ b/src/common/memmgr.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -52,6 +52,7 @@
# define aRealloc(p,n) (iMalloc->realloc((p),(n),ALC_MARK))
# define aReallocz(p,n) (iMalloc->reallocz((p),(n),ALC_MARK))
# define aStrdup(p) (iMalloc->astrdup((p),ALC_MARK))
+# define aStrndup(p,n) (iMalloc->astrndup((p),(n),ALC_MARK))
# define aFree(p) (iMalloc->free((p),ALC_MARK))
/////////////// Buffer Creation /////////////////
@@ -85,6 +86,7 @@ struct malloc_interface {
void* (*realloc)(void *p, size_t size, const char *file, int line, const char *func);
void* (*reallocz)(void *p, size_t size, const char *file, int line, const char *func);
char* (*astrdup)(const char *p, const char *file, int line, const char *func);
+ char *(*astrndup)(const char *p, size_t size, const char *file, int line, const char *func);
void (*free)(void *p, const char *file, int line, const char *func);
/* */
void (*memory_check)(void);
@@ -99,8 +101,10 @@ struct malloc_interface {
void malloc_defaults(void);
void memmgr_report(int extra);
-#endif // HERCULES_CORE
HPShared struct malloc_interface *iMalloc;
+#else
+#define iMalloc HPMi->memmgr
+#endif // HERCULES_CORE
#endif /* COMMON_MEMMGR_H */
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 981c1b30b..276e0eb08 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
#include "config/core.h"
#include "common/cbasetypes.h"
+#include "common/db.h" // VECTORS
// server->client protocol version
// 0 - pre-?
@@ -114,40 +115,85 @@
#define MAX_INVENTORY 100
//Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
-#define MAX_CHARS 9
+#if PACKETVER >= 20100413
+#ifndef MAX_CHARS
+ #define MAX_CHARS 12
+#endif
+#else
+#ifndef MAX_CHARS
+ #define MAX_CHARS 9
+#endif
+#endif
//Number of slots carded equipment can have. Never set to less than 4 as they are also used to keep the data of forged items/equipment. [Skotlex]
//Note: The client seems unable to receive data for more than 4 slots due to all related packets having a fixed size.
#define MAX_SLOTS 4
//Max amount of a single stacked item
#define MAX_AMOUNT 30000
-#define MAX_ZENY 1000000000
+#define MAX_ZENY INT_MAX
//Official Limit: 2.1b ( the var that stores the money doesn't go much higher than this by default )
#define MAX_BANK_ZENY INT_MAX
+#ifndef MAX_LEVEL
#define MAX_LEVEL 175
+#endif
#define MAX_FAME 1000000000
#define MAX_CART 100
-#define MAX_SKILL 1478
+#ifndef MAX_SKILL
+#define MAX_SKILL 1510
+#endif
+#ifndef MAX_SKILL_ID
#define MAX_SKILL_ID 10015 // [Ind/Hercules] max used skill ID
+#endif
+#ifndef MAX_SKILL_TREE
// Update this max as necessary. 86 is the value needed for Expanded Super Novice.
#define MAX_SKILL_TREE 86
+#endif
+#ifndef DEFAULT_WALK_SPEED
#define DEFAULT_WALK_SPEED 150
+#endif
+#ifndef MIN_WALK_SPEED
#define MIN_WALK_SPEED 20 /* below 20 clips animation */
+#endif
+#ifndef MAX_WALK_SPEED
#define MAX_WALK_SPEED 1000
+#endif
+#ifndef MAX_STORAGE
#define MAX_STORAGE 600
+#endif
+#ifndef MAX_GUILD_STORAGE
#define MAX_GUILD_STORAGE 600
+#endif
+#ifndef MAX_PARTY
#define MAX_PARTY 12
+#endif
+#ifndef BASE_GUILD_SIZE
#define BASE_GUILD_SIZE 16 // Base guild members (without GD_EXTENSION)
+#endif
+#ifndef MAX_GUILD
#define MAX_GUILD (BASE_GUILD_SIZE+10*6) // Increased max guild members +6 per 1 extension levels [Lupus]
+#endif
+#ifndef MAX_GUILDPOSITION
#define MAX_GUILDPOSITION 20 // Increased max guild positions to accomodate for all members [Valaris] (removed) [PoW]
+#endif
+#ifndef MAX_GUILDEXPULSION
#define MAX_GUILDEXPULSION 32
+#endif
+#ifndef MAX_GUILDALLIANCE
#define MAX_GUILDALLIANCE 16
+#endif
+#ifndef MAX_GUILDSKILL
#define MAX_GUILDSKILL 15 // Increased max guild skills because of new skills [Sara-chan]
+#endif
+#ifndef MAX_GUILDLEVEL
#define MAX_GUILDLEVEL 50
+#endif
+#ifndef MAX_GUARDIANS
#define MAX_GUARDIANS 8 // Local max per castle. [Skotlex]
+#endif
+#ifndef MAX_QUEST_OBJECTIVES
#define MAX_QUEST_OBJECTIVES 3 // Max quest objectives for a quest
-#define MAX_START_ITEMS 32 // Max number of items allowed to be given to a char whenever it's created. [mkbu95]
+#endif
// for produce
#define MIN_ATTRIBUTE 0
@@ -170,7 +216,9 @@
#define MAP_NAME_LENGTH (11 + 1)
#define MAP_NAME_LENGTH_EXT (MAP_NAME_LENGTH + 4)
+#ifndef MAX_FRIENDS
#define MAX_FRIENDS 40
+#endif
#define MAX_MEMOPOINTS 3
// Size of the fame list arrays.
@@ -186,8 +234,12 @@
#define MAX_GUILDMES2 120
// Base Homun skill.
+#ifndef HM_SKILLBASE
#define HM_SKILLBASE 8001
+#endif
+#ifndef MAX_HOMUNSKILL
#define MAX_HOMUNSKILL 43
+#endif
// Mail System
#define MAIL_MAX_INBOX 30
@@ -195,31 +247,44 @@
#define MAIL_BODY_LENGTH 200
// Mercenary System
+#ifndef MC_SKILLBASE
#define MC_SKILLBASE 8201
+#endif
+#ifndef MAX_MERCSKILL
#define MAX_MERCSKILL 40
+#endif
// Elemental System
+#ifndef MAX_ELEMENTALSKILL
#define MAX_ELEMENTALSKILL 42
+#endif
+#ifndef EL_SKILLBASE
#define EL_SKILLBASE 8401
+#endif
+#ifndef MAX_ELESKILLTREE
#define MAX_ELESKILLTREE 3
+#endif
+
+// Maximum item options [Smokexyz]
+#ifndef MAX_ITEM_OPTIONS
+#define MAX_ITEM_OPTIONS 5
+#endif
+STATIC_ASSERT(MAX_ITEM_OPTIONS <= 5, "This value is limited by the client and database layout and should only be increased if you know the consequences.");
// The following system marks a different job ID system used by the map server,
// which makes a lot more sense than the normal one. [Skotlex]
// These marks the "level" of the job.
-#define JOBL_2_1 0x100 //256
-#define JOBL_2_2 0x200 //512
-#define JOBL_2 0x300
-#define JOBL_UPPER 0x1000 //4096
-#define JOBL_BABY 0x2000 //8192
-#define JOBL_THIRD 0x4000 //16384
-
-//Packet DB
-#define MIN_PACKET_DB 0x0064 //what's the point of minimum packet id ? [hemagx]
-#define MAX_PACKET_DB 0x0F00
-#define MAX_PACKET_POS 20
+#define JOBL_2_1 0x0100
+#define JOBL_2_2 0x0200
+#define JOBL_2 0x0300 // JOBL_2_1 | JOBL_2_2
+#define JOBL_UPPER 0x1000
+#define JOBL_BABY 0x2000
+#define JOBL_THIRD 0x4000
#define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable
+#define INFINITE_DURATION (-1) // Infinite duration for status changes
+
struct hplugin_data_store;
enum item_types {
@@ -236,7 +301,9 @@ enum item_types {
IT_AMMO, //10
IT_DELAYCONSUME,//11
IT_CASH = 18,
+#ifndef IT_MAX
IT_MAX
+#endif
};
#define INDEX_NOT_FOUND (-1) ///< Used as invalid/failure value in various functions that return an index
@@ -256,6 +323,11 @@ struct quest {
enum quest_state state; ///< Current quest state
};
+enum attribute_flag {
+ ATTR_NONE = 0,
+ ATTR_BROKEN = 1,
+};
+
struct item {
int id;
short nameid;
@@ -269,6 +341,12 @@ struct item {
char favorite;
unsigned char bound;
uint64 unique_id;
+
+ struct {
+ int16 index;
+ int16 value;
+ uint8 param;
+ } option[MAX_ITEM_OPTIONS];
};
//Equip position constants
@@ -300,7 +378,7 @@ enum equip_pos {
struct point {
unsigned short map;
- short x,y;
+ int16 x, y;
};
enum e_skill_flag
@@ -328,7 +406,9 @@ enum e_item_bound_type {
IBT_GUILD = 0x2,
IBT_PARTY = 0x3,
IBT_CHARACTER = 0x4,
+#ifndef IBT_MAX
IBT_MAX = 0x4,
+#endif
};
enum {
@@ -357,6 +437,7 @@ enum {
OPTION_DRAGON5 = 0x04000000,
OPTION_HANBOK = 0x08000000,
OPTION_OKTOBERFEST = 0x10000000,
+ OPTION_SUMMER2 = 0x20000000,
#ifndef NEW_CARTS
OPTION_CART1 = 0x00000008,
OPTION_CART2 = 0x00000080,
@@ -368,7 +449,7 @@ enum {
#endif
// compound constants
OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5,
- OPTION_COSTUME = OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST,
+ OPTION_COSTUME = OPTION_WEDDING | OPTION_XMAS | OPTION_SUMMER | OPTION_HANBOK | OPTION_OKTOBERFEST | OPTION_SUMMER2,
};
struct s_skill {
@@ -392,16 +473,18 @@ struct script_reg_str {
char *value;
};
-// For saving status changes across sessions. [Skotlex]
+/// For saving status changes across sessions. [Skotlex]
struct status_change_data {
- unsigned short type; //SC_type
- int val1, val2, val3, val4;
- unsigned int tick; //Remaining duration.
+ unsigned short type; ///< Status change type (@see enum sc_type)
+ int val1, val2, val3, val4; ///< Parameters (meaning depends on type).
+ int tick; ///< Remaining duration.
};
struct storage_data {
- int storage_amount;
- struct item items[MAX_STORAGE];
+ bool save; ///< save flag.
+ bool received; ///< received flag.
+ int aggregate; ///< total item count.
+ VECTOR_DECL(struct item) item; ///< item vector.
};
struct guild_storage {
@@ -473,7 +556,7 @@ struct s_elemental {
int elemental_id;
int char_id;
short class_;
- int mode;
+ uint32 mode;
int hp, sp, max_hp, max_sp, matk, atk, atk2;
short hit, flee, amotion, def, mdef;
int life_time;
@@ -507,8 +590,8 @@ struct mmo_charstatus {
int zeny;
int bank_vault;
- short class_;
- unsigned int status_point,skill_point;
+ int16 class;
+ int status_point, skill_point;
int hp,max_hp,sp,max_sp;
unsigned int option;
short manner; // Defines how many minutes a char will be muted, each negative point is equivalent to a minute.
@@ -528,7 +611,7 @@ struct mmo_charstatus {
short robe;
char name[NAME_LENGTH];
- unsigned int base_level,job_level;
+ int base_level, job_level;
short str,agi,vit,int_,dex,luk;
unsigned char slot,sex;
@@ -537,7 +620,6 @@ struct mmo_charstatus {
struct point last_point,save_point,memo_point[MAX_MEMOPOINTS];
struct item inventory[MAX_INVENTORY],cart[MAX_CART];
- struct storage_data storage;
struct s_skill skill[MAX_SKILL];
struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex]
@@ -611,7 +693,7 @@ struct party_member {
int account_id;
int char_id;
char name[NAME_LENGTH];
- unsigned short class_;
+ int16 class;
unsigned short map;
unsigned short lv;
unsigned leader : 1,
@@ -630,7 +712,9 @@ struct party {
struct map_session_data;
struct guild_member {
int account_id, char_id;
- short hair,hair_color,gender,class_,lv;
+ short hair,hair_color,gender;
+ int16 class;
+ short lv;
uint64 exp;
int exp_payper;
short online,position;
@@ -718,6 +802,7 @@ struct fame_list {
};
enum fame_list_type {
+ RANKTYPE_UNKNOWN = -1,
RANKTYPE_BLACKSMITH = 0,
RANKTYPE_ALCHEMIST = 1,
RANKTYPE_TAEKWON = 2,
@@ -775,7 +860,9 @@ enum {
GD_RESTORE=10012,
GD_EMERGENCYCALL=10013,
GD_DEVELOPMENT=10014,
+#ifndef GD_MAX
GD_MAX,
+#endif
};
//These mark the ID of the jobs, as expected by the client. [Skotlex]
@@ -932,7 +1019,11 @@ enum {
JOB_OBORO,
JOB_REBELLION = 4215,
+ JOB_SUMMONER = 4218,
+
+#ifndef JOB_MAX
JOB_MAX,
+#endif
};
//Total number of classes (for data storage)
@@ -969,7 +1060,9 @@ enum weapon_type {
W_GRENADE, //21
W_HUUMA, //22
W_2HSTAFF, //23
- MAX_WEAPON_TYPE,
+#ifndef MAX_SINGLE_WEAPON_TYPE
+ MAX_SINGLE_WEAPON_TYPE,
+#endif
// dual-wield constants
W_DOUBLE_DD, ///< 2 daggers
W_DOUBLE_SS, ///< 2 swords
@@ -977,6 +1070,9 @@ enum weapon_type {
W_DOUBLE_DS, ///< dagger + sword
W_DOUBLE_DA, ///< dagger + axe
W_DOUBLE_SA, ///< sword + axe
+#ifndef MAX_WEAPON_TYPE
+ MAX_WEAPON_TYPE,
+#endif
};
enum ammo_type {
@@ -997,6 +1093,7 @@ enum e_char_server_type {
CST_OVER18 = 2,
CST_PAYING = 3,
CST_F2P = 4,
+ CST_MAX,
};
enum e_pc_reg_loading {
@@ -1045,4 +1142,8 @@ enum hz_char_ask_name_answer {
#error MAX_ZENY is too big
#endif
+#if MAX_SLOTS < 4
+#error MAX_SLOTS it too small
+#endif
+
#endif /* COMMON_MMO_H */
diff --git a/src/common/mutex.c b/src/common/mutex.c
index 0f02b153f..464a54161 100644
--- a/src/common/mutex.c
+++ b/src/common/mutex.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "common/cbasetypes.h" // for WIN32
#include "common/memmgr.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/timer.h"
@@ -34,7 +35,14 @@
#include <sys/time.h>
#endif
-struct ramutex{
+/** @file
+ * Implementation of the mutex interface.
+ */
+
+struct mutex_interface mutex_s;
+struct mutex_interface *mutex;
+
+struct mutex_data {
#ifdef WIN32
CRITICAL_SECTION hMutex;
#else
@@ -42,32 +50,26 @@ struct ramutex{
#endif
};
-struct racond{
+struct cond_data {
#ifdef WIN32
HANDLE events[2];
ra_align(8) volatile LONG nWaiters;
CRITICAL_SECTION waiters_lock;
-
#define EVENT_COND_SIGNAL 0
#define EVENT_COND_BROADCAST 1
-
#else
pthread_cond_t hCond;
#endif
};
-////////////////////
-// Mutex
-//
-// Implementation:
-//
+/* Mutex */
-ramutex *ramutex_create(void) {
- struct ramutex *m;
-
- m = (struct ramutex*)aMalloc( sizeof(struct ramutex) );
+/// @copydoc mutex_interface::create()
+struct mutex_data *mutex_create(void)
+{
+ struct mutex_data *m = aMalloc(sizeof(struct mutex_data));
if (m == NULL) {
- ShowFatalError("ramutex_create: OOM while allocating %"PRIuS" bytes.\n", sizeof(struct ramutex));
+ ShowFatalError("ramutex_create: OOM while allocating %"PRIuS" bytes.\n", sizeof(struct mutex_data));
return NULL;
}
@@ -78,10 +80,12 @@ ramutex *ramutex_create(void) {
#endif
return m;
-}//end: ramutex_create()
-
-void ramutex_destroy(ramutex *m) {
+}
+/// @copydoc mutex_interface::destroy()
+void mutex_destroy(struct mutex_data *m)
+{
+ nullpo_retv(m);
#ifdef WIN32
DeleteCriticalSection(&m->hMutex);
#else
@@ -89,53 +93,52 @@ void ramutex_destroy(ramutex *m) {
#endif
aFree(m);
+}
-}//end: ramutex_destroy()
-
-void ramutex_lock(ramutex *m) {
-
+/// @copydoc mutex_interface::lock()
+void mutex_lock(struct mutex_data *m)
+{
+ nullpo_retv(m);
#ifdef WIN32
EnterCriticalSection(&m->hMutex);
#else
pthread_mutex_lock(&m->hMutex);
#endif
-}//end: ramutex_lock
+}
-bool ramutex_trylock(ramutex *m) {
+/// @copydoc mutex_interface::trylock()
+bool mutex_trylock(struct mutex_data *m)
+{
+ nullpo_retr(false, m);
#ifdef WIN32
- if(TryEnterCriticalSection(&m->hMutex) != FALSE)
+ if (TryEnterCriticalSection(&m->hMutex) != FALSE)
return true;
-
- return false;
#else
- if(pthread_mutex_trylock(&m->hMutex) == 0)
+ if (pthread_mutex_trylock(&m->hMutex) == 0)
return true;
-
- return false;
#endif
-}//end: ramutex_trylock()
+ return false;
+}
-void ramutex_unlock(ramutex *m) {
+/// @copydoc mutex_interface::unlock()
+void mutex_unlock(struct mutex_data *m)
+{
+ nullpo_retv(m);
#ifdef WIN32
LeaveCriticalSection(&m->hMutex);
#else
pthread_mutex_unlock(&m->hMutex);
#endif
+}
-}//end: ramutex_unlock()
-
-///////////////
-// Condition Variables
-//
-// Implementation:
-//
+/* Conditional variable */
-racond *racond_create(void) {
- struct racond *c;
-
- c = (struct racond*)aMalloc( sizeof(struct racond) );
+/// @copydoc mutex_interface::cond_create()
+struct cond_data *cond_create(void)
+{
+ struct cond_data *c = aMalloc(sizeof(struct cond_data));
if (c == NULL) {
- ShowFatalError("racond_create: OOM while allocating %"PRIuS" bytes\n", sizeof(struct racond));
+ ShowFatalError("racond_create: OOM while allocating %"PRIuS" bytes\n", sizeof(struct cond_data));
return NULL;
}
@@ -149,31 +152,37 @@ racond *racond_create(void) {
#endif
return c;
-}//end: racond_create()
+}
-void racond_destroy(racond *c) {
+/// @copydoc mutex_interface::cond_destroy()
+void cond_destroy(struct cond_data *c)
+{
+ nullpo_retv(c);
#ifdef WIN32
- CloseHandle( c->events[ EVENT_COND_SIGNAL ] );
- CloseHandle( c->events[ EVENT_COND_BROADCAST ] );
- DeleteCriticalSection( &c->waiters_lock );
+ CloseHandle(c->events[EVENT_COND_SIGNAL]);
+ CloseHandle(c->events[EVENT_COND_BROADCAST]);
+ DeleteCriticalSection(&c->waiters_lock);
#else
pthread_cond_destroy(&c->hCond);
#endif
aFree(c);
-}//end: racond_destroy()
+}
-void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
+/// @copydoc mutex_interface::cond_wait()
+void cond_wait(struct cond_data *c, struct mutex_data *m, sysint timeout_ticks)
+{
#ifdef WIN32
register DWORD ms;
int result;
bool is_last = false;
+ nullpo_retv(c);
EnterCriticalSection(&c->waiters_lock);
c->nWaiters++;
LeaveCriticalSection(&c->waiters_lock);
- if(timeout_ticks < 0)
+ if (timeout_ticks < 0)
ms = INFINITE;
else
ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks;
@@ -181,27 +190,28 @@ void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
// we can release the mutex (m) here, cause win's
// manual reset events maintain state when used with
// SetEvent()
- ramutex_unlock(m);
+ mutex->unlock(m);
result = WaitForMultipleObjects(2, c->events, FALSE, ms);
EnterCriticalSection(&c->waiters_lock);
c->nWaiters--;
- if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) )
+ if ((result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0))
is_last = true; // Broadcast called!
LeaveCriticalSection(&c->waiters_lock);
// we are the last waiter that has to be notified, or to stop waiting
// so we have to do a manual reset
- if(is_last == true)
+ if (is_last == true)
ResetEvent( c->events[EVENT_COND_BROADCAST] );
- ramutex_lock(m);
+ mutex->lock(m);
#else
- if(timeout_ticks < 0){
- pthread_cond_wait( &c->hCond, &m->hMutex );
- }else{
+ nullpo_retv(m);
+ if (timeout_ticks < 0) {
+ pthread_cond_wait(&c->hCond, &m->hMutex);
+ } else {
struct timespec wtime;
int64 exact_timeout = timer->gettick() + timeout_ticks;
@@ -210,14 +220,16 @@ void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime);
}
-
#endif
-}//end: racond_wait()
+}
-void racond_signal(racond *c) {
+/// @copydoc mutex_interface::cond_signal()
+void cond_signal(struct cond_data *c)
+{
#ifdef WIN32
# if 0
bool has_waiters = false;
+ nullpo_retv(c);
EnterCriticalSection(&c->waiters_lock);
if(c->nWaiters > 0)
has_waiters = true;
@@ -225,16 +237,20 @@ void racond_signal(racond *c) {
if(has_waiters == true)
# endif // 0
- SetEvent( c->events[ EVENT_COND_SIGNAL ] );
+ SetEvent(c->events[EVENT_COND_SIGNAL]);
#else
+ nullpo_retv(c);
pthread_cond_signal(&c->hCond);
#endif
-}//end: racond_signal()
+}
-void racond_broadcast(racond *c) {
+/// @copydoc mutex_interface::cond_broadcast()
+void cond_broadcast(struct cond_data *c)
+{
#ifdef WIN32
# if 0
bool has_waiters = false;
+ nullpo_retv(c);
EnterCriticalSection(&c->waiters_lock);
if(c->nWaiters > 0)
has_waiters = true;
@@ -242,8 +258,28 @@ void racond_broadcast(racond *c) {
if(has_waiters == true)
# endif // 0
- SetEvent( c->events[ EVENT_COND_BROADCAST ] );
+ SetEvent(c->events[EVENT_COND_BROADCAST]);
#else
+ nullpo_retv(c);
pthread_cond_broadcast(&c->hCond);
#endif
-}//end: racond_broadcast()
+}
+
+/**
+ * Interface base initialization.
+ */
+void mutex_defaults(void)
+{
+ mutex = &mutex_s;
+ mutex->create = mutex_create;
+ mutex->destroy = mutex_destroy;
+ mutex->lock = mutex_lock;
+ mutex->trylock = mutex_trylock;
+ mutex->unlock = mutex_unlock;
+
+ mutex->cond_create = cond_create;
+ mutex->cond_destroy = cond_destroy;
+ mutex->cond_wait = cond_wait;
+ mutex->cond_signal = cond_signal;
+ mutex->cond_broadcast = cond_broadcast;
+}
diff --git a/src/common/mutex.h b/src/common/mutex.h
index e49791493..0569fb0da 100644
--- a/src/common/mutex.h
+++ b/src/common/mutex.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,91 +21,111 @@
#ifndef COMMON_MUTEX_H
#define COMMON_MUTEX_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
-typedef struct ramutex ramutex; // Mutex
-typedef struct racond racond; // Condition Var
-
-#ifdef HERCULES_CORE
-/**
- * Creates a Mutex
- *
- * @return not NULL
+/** @file
+ * Mutex and conditional variables implementation for Hercules.
*/
-ramutex *ramutex_create(void);
-/**
- * Destroys a Mutex
- *
- * @param m - the mutex to destroy
- */
-void ramutex_destroy(ramutex *m);
+/* Opaque types */
-/**
- * Gets a lock
- *
- * @param m - the mutex to lock
- */
-void ramutex_lock(ramutex *m);
+struct mutex_data; ///< Mutex
+struct cond_data; ///< Conditional variable
-/**
- * Trys to get the Lock
- *
- * @param m - the mutex try to lock
- *
- * @return boolean (true = got the lock)
- */
-bool ramutex_trylock(ramutex *m);
+/* Interface */
-/**
- * Unlocks a mutex
- *
- * @param m - the mutex to unlock
- */
-void ramutex_unlock(ramutex *m);
+/// The mutex interface.
+struct mutex_interface {
+ /**
+ * Creates a mutex.
+ *
+ * @return The created mutex.
+ */
+ struct mutex_data *(*create) (void);
+ /**
+ * Destroys a mutex.
+ *
+ * @param m the mutex to destroy.
+ */
+ void (*destroy) (struct mutex_data *m);
-/**
- * Creates a Condition variable
- *
- * @return not NULL
- */
-racond *racond_create(void);
+ /**
+ * Gets a lock.
+ *
+ * This function blocks until the lock can be acquired.
+ *
+ * @param m The mutex to lock.
+ */
+ void (*lock) (struct mutex_data *m);
-/**
- * Destroy a Condition variable
- *
- * @param c - the condition variable to destroy
- */
-void racond_destroy(racond *c);
+ /**
+ * Tries to get a lock.
+ *
+ * This function returns immediately.
+ *
+ * @param m The mutex to try to lock.
+ * @return success status.
+ * @retval true if the lock was acquired.
+ * @retval false if the mutex couldn't be locked.
+ */
+ bool (*trylock) (struct mutex_data *m);
-/**
- * Waits Until state is signaled
- *
- * @param c - the condition var to wait for signaled state
- * @param m - the mutex used for synchronization
- * @param timeout_ticks - timeout in ticks ( -1 = INFINITE )
- */
-void racond_wait(racond *c, ramutex *m, sysint timeout_ticks);
+ /**
+ * Unlocks a mutex.
+ *
+ * @param m The mutex to unlock.
+ */
+ void (*unlock) (struct mutex_data *m);
-/**
- * Sets the given condition var to signaled state
- *
- * @param c - condition var to set in signaled state.
- *
- * @note:
- * Only one waiter gets notified.
- */
-void racond_signal(racond *c);
+ /**
+ * Creates a conditional variable.
+ *
+ * @return the created conditional variable.
+ */
+ struct cond_data *(*cond_create) (void);
-/**
- * Sets notifies all waiting threads thats signaled.
- * @param c - condition var to set in signaled state
- *
- * @note:
- * All Waiters getting notified.
- */
-void racond_broadcast(racond *c);
+ /**
+ * Destroys a conditional variable.
+ *
+ * @param c the conditional variable to destroy.
+ */
+ void (*cond_destroy) (struct cond_data *c);
+
+ /**
+ * Waits Until state is signaled.
+ *
+ * @param c The condition var to wait for signaled state.
+ * @param m The mutex used for synchronization.
+ * @param timeout_ticks Timeout in ticks (-1 = INFINITE)
+ */
+ void (*cond_wait) (struct cond_data *c, struct mutex_data *m, sysint timeout_ticks);
+
+ /**
+ * Sets the given condition var to signaled state.
+ *
+ * @remark
+ * Only one waiter gets notified.
+ *
+ * @param c Condition var to set in signaled state.
+ */
+ void (*cond_signal) (struct cond_data *c);
+
+ /**
+ * Sets notifies all waiting threads thats signaled.
+ *
+ * @remark
+ * All Waiters getting notified.
+ *
+ * @param c Condition var to set in signaled state.
+ */
+ void (*cond_broadcast) (struct cond_data *c);
+};
+
+#ifdef HERCULES_CORE
+void mutex_defaults(void);
#endif // HERCULES_CORE
+HPShared struct mutex_interface *mutex; ///< Pointer to the mutex interface.
+
#endif /* COMMON_MUTEX_H */
diff --git a/src/common/nullpo.c b/src/common/nullpo.c
index 5b1be14ea..6525793bf 100644
--- a/src/common/nullpo.c
+++ b/src/common/nullpo.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/nullpo.h b/src/common/nullpo.h
index 098e669f3..28d058dc0 100644
--- a/src/common/nullpo.h
+++ b/src/common/nullpo.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/random.c b/src/common/random.c
index ba70a5c1d..b3a13e054 100644
--- a/src/common/random.c
+++ b/src/common/random.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "common/timer.h" // gettick
#include <mt19937ar/mt19937ar.h> // init_genrand, genrand_int32, genrand_res53
+#include <stdlib.h>
#if defined(WIN32)
# include "common/winapi.h"
@@ -35,8 +36,14 @@
# include <unistd.h>
#endif
+/** @file
+ * Implementation of the random number generator interface.
+ */
+
+struct rnd_interface rnd_s;
+struct rnd_interface *rnd;
-/// Initializes the random number generator with an appropriate seed.
+/// @copydoc rnd_interface::init()
void rnd_init(void)
{
unsigned long seed = (unsigned long)timer->gettick();
@@ -53,53 +60,64 @@ void rnd_init(void)
#endif // HAVE_GETTID
#endif
init_genrand(seed);
+
+ // Also initialize the stdlib rng, just in case it's used somewhere.
+ srand((unsigned int)seed);
}
+/// @copydoc rnd_interface::final()
+void rnd_final(void)
+{
+}
-/// Initializes the random number generator.
+/// @copydoc rnd_interface::seed()
void rnd_seed(uint32 seed)
{
init_genrand(seed);
}
-
-/// Generates a random number in the interval [0, SINT32_MAX]
-int32 rnd(void)
+/// @copydoc rnd_interface::random()
+int32 rnd_random(void)
{
return (int32)genrand_int31();
}
-
-/// Generates a random number in the interval [0, dice_faces)
-/// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0)
+/// @copydoc rnd_interface::roll()
uint32 rnd_roll(uint32 dice_faces)
{
- return (uint32)(rnd_uniform()*dice_faces);
+ return (uint32)(rnd->uniform()*dice_faces);
}
-
-/// Generates a random number in the interval [min, max]
-/// Returns min if range is invalid.
+/// @copydoc rnd_interface::value()
int32 rnd_value(int32 min, int32 max)
{
- if( min >= max )
+ if (min >= max)
return min;
- return min + (int32)(rnd_uniform()*(max-min+1));
+ return min + (int32)(rnd->uniform()*(max-min+1));
}
-
-/// Generates a random number in the interval [0.0, 1.0)
-/// NOTE: interval is open ended, so 1.0 is excluded
+/// @copydoc rnd_interface::uniform()
double rnd_uniform(void)
{
return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32
}
-
-/// Generates a random number in the interval [0.0, 1.0) with 53-bit resolution
-/// NOTE: interval is open ended, so 1.0 is excluded
-/// NOTE: 53 bits is the maximum precision of a double
+/// @copydoc rnd_interface::uniform53()
double rnd_uniform53(void)
{
return genrand_res53();
}
+
+/// Interface base initialization.
+void rnd_defaults(void)
+{
+ rnd = &rnd_s;
+ rnd->init = rnd_init;
+ rnd->final = rnd_final;
+ rnd->seed = rnd_seed;
+ rnd->random = rnd_random;
+ rnd->roll = rnd_roll;
+ rnd->value = rnd_value;
+ rnd->uniform = rnd_uniform;
+ rnd->uniform53 = rnd_uniform53;
+}
diff --git a/src/common/random.h b/src/common/random.h
index 0b5abbcdc..1b249ef19 100644
--- a/src/common/random.h
+++ b/src/common/random.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,17 +21,81 @@
#ifndef COMMON_RANDOM_H
#define COMMON_RANDOM_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
+
+/** @file
+ * The random number generator interface.
+ */
+
+/// Random interface.
+struct rnd_interface {
+ /**
+ * Interface initialization.
+ *
+ * During initialization, the RNG is seeded with a random seed.
+ */
+ void (*init) (void);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Re-seeds the random number generator.
+ *
+ * @param seed The new seed.
+ */
+ void (*seed) (uint32 seed);
+
+ /**
+ * Generates a random number in the interval [0, SINT32_MAX].
+ */
+ int32 (*random) (void);
+
+ /**
+ * Generates a random number in the interval [0, dice_faces).
+ *
+ * @remark
+ * interval is open ended, so dice_faces is excluded (unless it's 0)
+ */
+ uint32 (*roll) (uint32 dice_faces);
+
+ /**
+ * Generates a random number in the interval [min, max].
+ *
+ * @retval min if range is invalid.
+ */
+ int32 (*value) (int32 min, int32 max);
+
+ /**
+ * Generates a random number in the interval [0.0, 1.0)
+ *
+ * @remark
+ * interval is open ended, so 1.0 is excluded
+ */
+ double (*uniform) (void);
+
+ /**
+ * Generates a random number in the interval [0.0, 1.0) with 53-bit resolution.
+ *
+ * 53 bits is the maximum precision of a double.
+ *
+ * @remark
+ * interval is open ended, so 1.0 is excluded
+ */
+ double (*uniform53) (void);
+};
+
+/**
+ * Utlity macro to call the frequently used rnd_interface#random().
+ *
+ * @related rnd_interface.
+ */
+#define rnd() rnd->random()
#ifdef HERCULES_CORE
-void rnd_init(void);
-void rnd_seed(uint32);
-
-int32 rnd(void);// [0, SINT32_MAX]
-uint32 rnd_roll(uint32 dice_faces);// [0, dice_faces)
-int32 rnd_value(int32 min, int32 max);// [min, max]
-double rnd_uniform(void);// [0.0, 1.0)
-double rnd_uniform53(void);// [0.0, 1.0)
+void rnd_defaults(void);
#endif // HERCULES_CORE
+HPShared struct rnd_interface *rnd; ///< Pointer to the random interface.
+
#endif /* COMMON_RANDOM_H */
diff --git a/src/common/showmsg.c b/src/common/showmsg.c
index 956222a7d..23679e762 100644
--- a/src/common/showmsg.c
+++ b/src/common/showmsg.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,11 +23,10 @@
#include "showmsg.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/core.h" //[Ind] - For SERVER_TYPE
#include "common/strlib.h" // StringBuf
-#include <libconfig/libconfig.h>
-
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h> // atexit
@@ -245,13 +244,13 @@ int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr)
continue;
} else if (*q == ';') {
// delimiter
- if (numpoint < sizeof(numbers)/sizeof(*numbers)) {
+ if (numpoint < ARRAYLENGTH(numbers)) {
// go to next array position
numpoint++;
} else {
// array is full, so we 'forget' the first value
- memmove(numbers,numbers+1,sizeof(numbers)/sizeof(*numbers)-1);
- numbers[sizeof(numbers)/sizeof(*numbers)-1]=0;
+ memmove(numbers, numbers+1, ARRAYLENGTH(numbers)-1);
+ numbers[ARRAYLENGTH(numbers)-1]=0;
}
++q;
// and next number
@@ -606,9 +605,6 @@ int vShowMessage_(enum msg_type flag, const char *string, va_list ap)
{
va_list apcopy;
char prefix[100];
-#if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN)
- FILE *fp;
-#endif
if (!string || *string == '\0') {
ShowError("Empty string passed to vShowMessage_().\n");
@@ -703,8 +699,8 @@ int vShowMessage_(enum msg_type flag, const char *string, va_list ap)
}
#if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN)
- if(strlen(DEBUGLOGPATH) > 0) {
- fp=fopen(DEBUGLOGPATH,"a");
+ if (strlen(DEBUGLOGPATH) > 0) {
+ FILE *fp = fopen(DEBUGLOGPATH,"a");
if (fp == NULL) {
FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH);
FFLUSH(STDERR);
@@ -799,16 +795,20 @@ void showmsg_showWarning(const char *string, ...)
vShowMessage_(MSG_WARNING, string, ap);
va_end(ap);
}
-void showmsg_showConfigWarning(config_setting_t *config, const char *string, ...) __attribute__((format(printf, 2, 3)));
-void showmsg_showConfigWarning(config_setting_t *config, const char *string, ...)
+void showmsg_showConfigWarning(struct config_setting_t *config, const char *string, ...) __attribute__((format(printf, 2, 3)));
+void showmsg_showConfigWarning(struct config_setting_t *config, const char *string, ...)
{
StringBuf buf;
va_list ap;
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, string);
- StrBuf->Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config));
+ StrBuf->Printf(&buf, " (%s:%u)\n", config_setting_source_file(config), config_setting_source_line(config));
va_start(ap, string);
+#ifdef BUILDBOT
+ vShowMessage_(MSG_ERROR, StrBuf->Value(&buf), ap);
+#else // BUILDBOT
vShowMessage_(MSG_WARNING, StrBuf->Value(&buf), ap);
+#endif // BUILDBOT
va_end(ap);
StrBuf->Destroy(&buf);
}
diff --git a/src/common/showmsg.h b/src/common/showmsg.h
index ed8776fb0..eee6b467b 100644
--- a/src/common/showmsg.h
+++ b/src/common/showmsg.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,10 +23,11 @@
#include "common/hercules.h"
-#include <libconfig/libconfig.h>
-
#include <stdarg.h>
+/* Forward Declarations */
+struct config_setting_t;
+
// for help with the console colors look here:
// http://www.edoceo.com/liberum/?doc=printf-with-color
// some code explanation (used here):
@@ -118,7 +119,7 @@ struct showmsg_interface {
void (*showDebug) (const char *, ...) __attribute__((format(printf, 1, 2)));
void (*showError) (const char *, ...) __attribute__((format(printf, 1, 2)));
void (*showFatalError) (const char *, ...) __attribute__((format(printf, 1, 2)));
- void (*showConfigWarning) (config_setting_t *config, const char *string, ...) __attribute__((format(printf, 2, 3)));
+ void (*showConfigWarning) (struct config_setting_t *config, const char *string, ...) __attribute__((format(printf, 2, 3)));
};
/* the purpose of these macros is simply to not make calling them be an annoyance */
@@ -129,7 +130,11 @@ struct showmsg_interface {
#define ShowSQL(fmt, ...) (showmsg->showSQL((fmt), ##__VA_ARGS__))
#define ShowInfo(fmt, ...) (showmsg->showInfo((fmt), ##__VA_ARGS__))
#define ShowNotice(fmt, ...) (showmsg->showNotice((fmt), ##__VA_ARGS__))
+#ifdef BUILDBOT
+#define ShowWarning(fmt, ...) (showmsg->showError((fmt), ##__VA_ARGS__))
+#else // BUILDBOT
#define ShowWarning(fmt, ...) (showmsg->showWarning((fmt), ##__VA_ARGS__))
+#endif // BUILDBOT
#define ShowDebug(fmt, ...) (showmsg->showDebug((fmt), ##__VA_ARGS__))
#define ShowError(fmt, ...) (showmsg->showError((fmt), ##__VA_ARGS__))
#define ShowFatalError(fmt, ...) (showmsg->showFatalError((fmt), ##__VA_ARGS__))
diff --git a/src/common/socket.c b/src/common/socket.c
index 740c07bdc..d4b8bb43f 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "common/HPM.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/db.h"
#include "common/memmgr.h"
#include "common/mmo.h"
@@ -37,35 +38,39 @@
#include <stdlib.h>
#include <sys/types.h>
+#ifdef SOCKET_EPOLL
+#include <sys/epoll.h>
+#endif // SOCKET_EPOLL
+
#ifdef WIN32
# include "common/winapi.h"
-#else
+#else // WIN32
# include <arpa/inet.h>
# include <errno.h>
# include <net/if.h>
# include <netdb.h>
#if defined __linux__ || defined __linux
# include <linux/tcp.h>
-#else
+#else // defined __linux__ || defined __linux
# include <netinet/in.h>
# include <netinet/tcp.h>
-#endif
+#endif // defined __linux__ || defined __linux
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <unistd.h>
-# ifndef SIOCGIFCONF
-# include <sys/sockio.h> // SIOCGIFCONF on Solaris, maybe others? [Shinomori]
-# endif
-# ifndef FIONBIO
-# include <sys/filio.h> // FIONBIO on Solaris [FlavioJS]
-# endif
+#ifndef SIOCGIFCONF
+# include <sys/sockio.h> // SIOCGIFCONF on Solaris, maybe others? [Shinomori]
+#endif // SIOCGIFCONF
+#ifndef FIONBIO
+# include <sys/filio.h> // FIONBIO on Solaris [FlavioJS]
+#endif // FIONBIO
-# ifdef HAVE_SETRLIMIT
-# include <sys/resource.h>
-# endif
-#endif
+#ifdef HAVE_SETRLIMIT
+# include <sys/resource.h>
+#endif // HAVE_SETRLIMIT
+#endif // WIN32
/**
* Socket Interface Source
@@ -75,13 +80,15 @@ struct socket_interface *sockt;
struct socket_data **session;
+const char *SOCKET_CONF_FILENAME = "conf/common/socket.conf";
+
#ifdef SEND_SHORTLIST
// Add a fd to the shortlist so that it'll be recognized as a fd that needs
// sending done on it.
void send_shortlist_add_fd(int fd);
// Do pending network sends (and eof handling) from the shortlist.
void send_shortlist_do_sends(void);
-#endif
+#endif // SEND_SHORTLIST
/////////////////////////////////////////////////////////////////////
#if defined(WIN32)
@@ -211,7 +218,7 @@ char* sErr(int code)
#define sFD_ZERO FD_ZERO
/////////////////////////////////////////////////////////////////////
-#else
+#else // defined(WIN32)
/////////////////////////////////////////////////////////////////////
// nix portability layer
@@ -243,29 +250,40 @@ char* sErr(int code)
#define sFD_ZERO FD_ZERO
/////////////////////////////////////////////////////////////////////
-#endif
+#endif // defined(WIN32)
/////////////////////////////////////////////////////////////////////
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
-#endif
+#endif // MSG_NOSIGNAL
+#ifndef SOCKET_EPOLL
+// Select based Event Dispatcher:
fd_set readfds;
+#else // SOCKET_EPOLL
+// Epoll based Event Dispatcher:
+static int epoll_maxevents = (FD_SETSIZE / 2);
+static int epfd = SOCKET_ERROR;
+static struct epoll_event epevent;
+static struct epoll_event *epevents = NULL;
+
+#endif // SOCKET_EPOLL
+
// Maximum packet size in bytes, which the client is able to handle.
// Larger packets cause a buffer overflow and stack corruption.
#if PACKETVER >= 20131223
static size_t socket_max_client_packet = 0xFFFF;
-#else
+#else // PACKETVER >= 20131223
static size_t socket_max_client_packet = 0x6000;
-#endif
+#endif // PACKETVER >= 20131223
#ifdef SHOW_SERVER_STATS
// Data I/O statistics
static size_t socket_data_i = 0, socket_data_ci = 0, socket_data_qi = 0;
static size_t socket_data_o = 0, socket_data_co = 0, socket_data_qo = 0;
static time_t socket_data_last_tick = 0;
-#endif
+#endif // SHOW_SERVER_STATS
// initial recv buffer size (this will also be the max. size)
// biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes)
@@ -281,14 +299,14 @@ static time_t socket_data_last_tick = 0;
int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that
int send_shortlist_count = 0;// how many fd's are in the shortlist
uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are already in the shortlist
-#endif
+#endif // SEND_SHORTLIST
static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse);
#ifndef MINICORE
int ip_rules = 1;
static int connect_check(uint32 ip);
-#endif
+#endif // MINICORE
const char* error_msg(void)
{
@@ -379,13 +397,13 @@ void setsocketopts(int fd, struct hSockOpt *opt)
ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd);
#ifdef TCP_THIN_LINEAR_TIMEOUTS
- if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, (char *)&yes, sizeof(yes)))
- ShowWarning("setsocketopts: Unable to set TCP_THIN_LINEAR_TIMEOUTS mode for connection #%d!\n", fd);
-#endif
+ if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, (char *)&yes, sizeof(yes)))
+ ShowWarning("setsocketopts: Unable to set TCP_THIN_LINEAR_TIMEOUTS mode for connection #%d!\n", fd);
+#endif // TCP_THIN_LINEAR_TIMEOUTS
#ifdef TCP_THIN_DUPACK
- if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, (char *)&yes, sizeof(yes)))
- ShowWarning("setsocketopts: Unable to set TCP_THIN_DUPACK mode for connection #%d!\n", fd);
-#endif
+ if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, (char *)&yes, sizeof(yes)))
+ ShowWarning("setsocketopts: Unable to set TCP_THIN_DUPACK mode for connection #%d!\n", fd);
+#endif // TCP_THIN_DUPACK
}
/*======================================
@@ -397,7 +415,7 @@ void set_eof(int fd)
#ifdef SEND_SHORTLIST
// Add this socket to the shortlist for eof handling.
send_shortlist_add_fd(fd);
-#endif
+#endif // SEND_SHORTLIST
sockt->session[fd]->flag.eof = 1;
}
}
@@ -435,7 +453,7 @@ int recv_to_fifo(int fd)
{
socket_data_ci += len;
}
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -452,12 +470,12 @@ int send_from_fifo(int fd)
len = sSend(fd, (const char *) sockt->session[fd]->wdata, (int)sockt->session[fd]->wdata_size, MSG_NOSIGNAL);
if( len == SOCKET_ERROR )
- {//An exception has occurred
+ { //An exception has occurred
if( sErrno != S_EWOULDBLOCK ) {
//ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd);
#ifdef SHOW_SERVER_STATS
socket_data_qo -= sockt->session[fd]->wdata_size;
-#endif
+#endif // SHOW_SERVER_STATS
sockt->session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex]
sockt->eof(fd);
}
@@ -479,7 +497,7 @@ int send_from_fifo(int fd)
{
socket_data_co += len;
}
-#endif
+#endif // SHOW_SERVER_STATS
}
return 0;
@@ -502,7 +520,8 @@ void flush_fifos(void)
/*======================================
* CORE : Connection functions
*--------------------------------------*/
-int connect_client(int listen_fd) {
+int connect_client(int listen_fd)
+{
int fd;
struct sockaddr_in client_address;
socklen_t len;
@@ -533,11 +552,27 @@ int connect_client(int listen_fd) {
sockt->close(fd);
return -1;
}
-#endif
+#endif // MINICORE
- if( sockt->fd_max <= fd ) sockt->fd_max = fd + 1;
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
sFD_SET(fd,&readfds);
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("connect_client: New Socket #%d failed to add to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ return -1;
+ }
+
+#endif // SOCKET_EPOLL
+
+ if( sockt->fd_max <= fd ) sockt->fd_max = fd + 1;
+
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
sockt->session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr);
@@ -585,8 +620,26 @@ int make_listen_bind(uint32 ip, uint16 port)
exit(EXIT_FAILURE);
}
+
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
+ sFD_SET(fd,&readfds);
+
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("make_listen_bind: failed to add listener socket #%d to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ exit(EXIT_FAILURE);
+ }
+
+#endif // SOCKET_EPOLL
+
if(sockt->fd_max <= fd) sockt->fd_max = fd + 1;
- sFD_SET(fd, &readfds);
+
create_session(fd, connect_client, null_send, null_parse);
sockt->session[fd]->client_addr = 0; // just listens
@@ -595,7 +648,8 @@ int make_listen_bind(uint32 ip, uint16 port)
return fd;
}
-int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
+int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt)
+{
struct sockaddr_in remote_address = { 0 };
int fd;
int result;
@@ -624,7 +678,7 @@ int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
remote_address.sin_port = htons(port);
if( !( opt && opt->silent ) )
- ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port);
+ ShowStatus("Connecting to %u.%u.%u.%u:%i\n", CONVIP(ip), port);
result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in));
if( result == SOCKET_ERROR ) {
@@ -636,9 +690,26 @@ int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
//Now the socket can be made non-blocking. [Skotlex]
sockt->set_nonblocking(fd, 1);
- if (sockt->fd_max <= fd) sockt->fd_max = fd + 1;
+
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
sFD_SET(fd,&readfds);
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("make_connection: failed to add socket #%d to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ return -1;
+ }
+
+#endif // SOCKET_EPOLL
+
+ if(sockt->fd_max <= fd) sockt->fd_max = fd + 1;
+
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
sockt->session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr);
@@ -667,7 +738,7 @@ static void delete_session(int fd)
#ifdef SHOW_SERVER_STATS
socket_data_qi -= sockt->session[fd]->rdata_size - sockt->session[fd]->rdata_pos;
socket_data_qo -= sockt->session[fd]->wdata_size;
-#endif
+#endif // SHOW_SERVER_STATS
aFree(sockt->session[fd]->rdata);
aFree(sockt->session[fd]->wdata);
if( sockt->session[fd]->session_data )
@@ -740,7 +811,7 @@ int rfifoskip(int fd, size_t len)
s->rdata_pos = s->rdata_pos + len;
#ifdef SHOW_SERVER_STATS
socket_data_qi -= len;
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -748,16 +819,19 @@ int rfifoskip(int fd, size_t len)
int wfifoset(int fd, size_t len)
{
size_t newreserve;
- struct socket_data* s = sockt->session[fd];
+ struct socket_data* s;
- if (!sockt->session_is_valid(fd) || s->wdata == NULL)
+ if (!sockt->session_is_valid(fd))
+ return 0;
+ s = sockt->session[fd];
+ if (s == NULL || s->wdata == NULL)
return 0;
// we have written len bytes to the buffer already before calling WFIFOSET
if (s->wdata_size+len > s->max_wdata) {
// actually there was a buffer overflow already
uint32 ip = s->client_addr;
- ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata);
+ ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%u.%u.%u.%u) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata);
ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16*)(s->wdata + s->wdata_size)));
// no other chance, make a better fifo model
exit(EXIT_FAILURE);
@@ -767,7 +841,7 @@ int wfifoset(int fd, size_t len)
{
// dynamic packets allow up to UINT16_MAX bytes (<packet_id>.W <packet_len>.W ...)
// all known fixed-size packets are within this limit, so use the same limit
- ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF);
+ ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFFU);
exit(EXIT_FAILURE);
}
else if( len == 0 )
@@ -791,7 +865,7 @@ int wfifoset(int fd, size_t len)
s->wdata_size += len;
#ifdef SHOW_SERVER_STATS
socket_data_qo += len;
-#endif
+#endif // SHOW_SERVER_STATS
//If the interserver has 200% of its normal size full, flush the data.
if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK )
sockt->flush(fd);
@@ -805,31 +879,35 @@ int wfifoset(int fd, size_t len)
#ifdef SEND_SHORTLIST
send_shortlist_add_fd(fd);
-#endif
+#endif // SEND_SHORTLIST
return 0;
}
int do_sockets(int next)
{
+#ifndef SOCKET_EPOLL
fd_set rfd;
struct timeval timeout;
+#endif // SOCKET_EPOLL
int ret,i;
// PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof.
// Send remaining data and process client-side disconnects here.
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
-#else
- for (i = 1; i < sockt->fd_max; i++)
- {
- if(!sockt->session[fd]
+#else // SEND_SHORTLIST
+ for (i = 1; i < sockt->fd_max; i++) {
+ if (sockt->session[i] == NULL)
continue;
- if(sockt->session[fd]>wdata_size)
- sockt->session[fd]>func_send(i);
+ if (sockt->session[i]->wdata_size > 0)
+ sockt->session[i]->func_send(i);
}
-#endif
+#endif // SEND_SHORTLIST
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher:
// can timeout until the next tick
timeout.tv_sec = next/1000;
@@ -847,6 +925,20 @@ int do_sockets(int next)
}
return 0; // interrupted by a signal, just loop and try again
}
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+
+ ret = epoll_wait(epfd, epevents, epoll_maxevents, next);
+ if(ret == SOCKET_ERROR)
+ {
+ if( sErrno != S_EINTR )
+ {
+ ShowFatalError("do_sockets: epoll_wait() failed, %s!\n", error_msg());
+ exit(EXIT_FAILURE);
+ }
+ return 0; // interrupted by a signal, just loop and try again
+ }
+#endif // SOCKET_EPOLL
sockt->last_tick = time(NULL);
@@ -858,7 +950,33 @@ int do_sockets(int next)
if( sockt->session[fd] )
sockt->session[fd]->func_recv(fd);
}
-#else
+#elif defined(SOCKET_EPOLL)
+ // epoll based selection
+
+ for( i = 0; i < ret; i++ )
+ {
+ struct epoll_event *it = &epevents[i];
+ struct socket_data *sock = sockt->session[ it->data.fd ];
+
+ if(!sock)
+ continue;
+
+ if ((it->events & EPOLLERR) ||
+ (it->events & EPOLLHUP) ||
+ (!(it->events & EPOLLIN)))
+ {
+ // Got Error on this connection
+ sockt->eof( it->data.fd );
+
+ } else if (it->events & EPOLLIN) {
+ // data wainting
+ sock->func_recv( it->data.fd );
+
+ }
+
+ }
+
+#else // defined(SOCKET_EPOLL)
// otherwise assume that the fd_set is a bit-array and enumerate it in a standard way
for( i = 1; ret && i < sockt->fd_max; ++i )
{
@@ -868,12 +986,12 @@ int do_sockets(int next)
--ret;
}
}
-#endif
+#endif // defined(SOCKET_EPOLL)
// POSTSEND Send remaining data and handle eof sessions.
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
-#else
+#else // SEND_SHORTLIST
for (i = 1; i < sockt->fd_max; i++)
{
if(!sockt->session[i])
@@ -887,7 +1005,7 @@ int do_sockets(int next)
sockt->session[i]->func_parse(i); //This should close the session immediately.
}
}
-#endif
+#endif // SEND_SHORTLIST
// parse input data on each socket
for(i = 1; i < sockt->fd_max; i++)
@@ -905,10 +1023,6 @@ int do_sockets(int next)
}
}
-#ifdef __clang_analyzer__
- // Let Clang's static analyzer know this never happens (it thinks it might because of a NULL check in session_is_valid)
- if (!sockt->session[i]) continue;
-#endif // __clang_analyzer__
sockt->session[i]->func_parse(i);
if(!sockt->session[i])
@@ -930,14 +1044,14 @@ int do_sockets(int next)
sprintf(buf, "In: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | Out: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | RAM: %.03f MB", socket_data_i/1024., socket_data_ci/1024., socket_data_qi/1024., socket_data_o/1024., socket_data_co/1024., socket_data_qo/1024., iMalloc->usage()/1024.);
#ifdef _WIN32
SetConsoleTitle(buf);
-#else
+#else // _WIN32
ShowMessage("\033[s\033[1;1H\033[2K%s\033[u", buf);
-#endif
+#endif // _WIN32
socket_data_last_tick = sockt->last_tick;
socket_data_i = socket_data_ci = 0;
socket_data_o = socket_data_co = 0;
}
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -947,17 +1061,19 @@ int do_sockets(int next)
//////////////////////////////
// IP rules and DDoS protection
-typedef struct connect_history {
+struct connect_history {
uint32 ip;
int64 tick;
int count;
unsigned ddos : 1;
-} ConnectHistory;
+};
-typedef struct access_control {
+struct access_control {
uint32 ip;
uint32 mask;
-} AccessControl;
+};
+
+VECTOR_STRUCT_DECL(access_control_list, struct access_control);
enum aco {
ACO_DENY_ALLOW,
@@ -965,16 +1081,14 @@ enum aco {
ACO_MUTUAL_FAILURE
};
-static AccessControl* access_allow = NULL;
-static AccessControl* access_deny = NULL;
+static struct access_control_list access_allow;
+static struct access_control_list access_deny;
static int access_order = ACO_DENY_ALLOW;
-static int access_allownum = 0;
-static int access_denynum = 0;
static int access_debug = 0;
static int ddos_count = 10;
static int ddos_interval = 3*1000;
static int ddos_autoreset = 10*60*1000;
-DBMap *connect_history = NULL;
+struct DBMap *connect_history = NULL;
static int connect_check_(uint32 ip);
@@ -984,7 +1098,7 @@ static int connect_check(uint32 ip)
{
int result = connect_check_(ip);
if( access_debug ) {
- ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!");
+ ShowInfo("connect_check: Connection from %u.%u.%u.%u %s\n", CONVIP(ip),result ? "allowed." : "denied!");
}
return result;
}
@@ -994,33 +1108,35 @@ static int connect_check(uint32 ip)
/// 1 or 2 : Connection Accepted
static int connect_check_(uint32 ip)
{
- ConnectHistory* hist = NULL;
+ struct connect_history *hist = NULL;
int i;
int is_allowip = 0;
int is_denyip = 0;
int connect_ok = 0;
// Search the allow list
- for( i=0; i < access_allownum; ++i ){
- 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",
+ for (i = 0; i < VECTOR_LENGTH(access_allow); ++i) {
+ struct access_control *entry = &VECTOR_INDEX(access_allow, i);
+ if (SUBNET_MATCH(ip, entry->ip, entry->mask)) {
+ if (access_debug) {
+ ShowInfo("connect_check: Found match from allow list:%u.%u.%u.%u IP:%u.%u.%u.%u Mask:%u.%u.%u.%u\n",
CONVIP(ip),
- CONVIP(access_allow[i].ip),
- CONVIP(access_allow[i].mask));
+ CONVIP(entry->ip),
+ CONVIP(entry->mask));
}
is_allowip = 1;
break;
}
}
// Search the deny list
- for( i=0; i < access_denynum; ++i ){
- 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",
+ for (i = 0; i < VECTOR_LENGTH(access_deny); ++i) {
+ struct access_control *entry = &VECTOR_INDEX(access_deny, i);
+ if (SUBNET_MATCH(ip, entry->ip, entry->mask)) {
+ if (access_debug) {
+ ShowInfo("connect_check: Found match from deny list:%u.%u.%u.%u IP:%u.%u.%u.%u Mask:%u.%u.%u.%u\n",
CONVIP(ip),
- CONVIP(access_deny[i].ip),
- CONVIP(access_deny[i].mask));
+ CONVIP(entry->ip),
+ CONVIP(entry->mask));
}
is_denyip = 1;
break;
@@ -1064,7 +1180,7 @@ static int connect_check_(uint32 ip)
hist->tick = timer->gettick();
if( ++hist->count >= ddos_count ) {// DDoS attack detected
hist->ddos = 1;
- ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip));
+ ShowWarning("connect_check: DDoS Attack detected from %u.%u.%u.%u!\n", CONVIP(ip));
return (connect_ok == 2 ? 1 : 0);
}
return connect_ok;
@@ -1075,7 +1191,7 @@ static int connect_check_(uint32 ip)
}
}
// IP not found, add to history
- CREATE(hist, ConnectHistory, 1);
+ CREATE(hist, struct connect_history, 1);
hist->ip = ip;
hist->tick = timer->gettick();
uidb_put(connect_history, ip, hist);
@@ -1084,11 +1200,12 @@ static int connect_check_(uint32 ip)
/// Timer function.
/// Deletes old connection history records.
-static int connect_check_clear(int tid, int64 tick, int id, intptr_t data) {
+static int connect_check_clear(int tid, int64 tick, int id, intptr_t data)
+{
int clear = 0;
int list = 0;
- ConnectHistory *hist = NULL;
- DBIterator *iter;
+ struct connect_history *hist = NULL;
+ struct DBIterator *iter;
if( !db_size(connect_history) )
return 0;
@@ -1115,11 +1232,14 @@ static int connect_check_clear(int tid, int64 tick, int id, intptr_t data) {
/// Parses the ip address and mask and puts it into acc.
/// Returns 1 is successful, 0 otherwise.
-int access_ipmask(const char* str, AccessControl* acc)
+int access_ipmask(const char *str, struct access_control *acc)
{
uint32 ip;
uint32 mask;
+ nullpo_ret(str);
+ nullpo_ret(acc);
+
if( strcmp(str,"all") == 0 ) {
ip = 0;
mask = 0;
@@ -1152,80 +1272,216 @@ int access_ipmask(const char* str, AccessControl* acc)
}
}
if( access_debug ){
- ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask));
+ ShowInfo("access_ipmask: Loaded IP:%u.%u.%u.%u mask:%u.%u.%u.%u\n", CONVIP(ip), CONVIP(mask));
}
acc->ip = ip;
acc->mask = mask;
return 1;
}
+
+/**
+ * Adds an entry to the access list.
+ *
+ * @param setting The setting to read from.
+ * @param list_name The list name (used in error messages).
+ * @param access_list The access list to edit.
+ *
+ * @retval false in case of failure
+ */
+bool access_list_add(struct config_setting_t *setting, const char *list_name, struct access_control_list *access_list)
+{
+ const char *temp = NULL;
+ int i, setting_length;
+
+ nullpo_retr(false, setting);
+ nullpo_retr(false, list_name);
+ nullpo_retr(false, access_list);
+
+ if ((setting_length = libconfig->setting_length(setting)) <= 0)
+ return false;
+
+ VECTOR_ENSURE(*access_list, setting_length, 1);
+ for (i = 0; i < setting_length; i++) {
+ struct access_control acc;
+ if ((temp = libconfig->setting_get_string_elem(setting, i)) == NULL) {
+ continue;
+ }
+
+ if (!access_ipmask(temp, &acc)) {
+ ShowError("access_list_add: Invalid ip or ip range %s '%d'!\n", list_name, i);
+ continue;
+ }
+ VECTOR_PUSH(*access_list, acc);
+ }
+
+ return true;
+}
+
//////////////////////////////
-#endif
+#endif // MINICORE
//////////////////////////////
-int socket_config_read(const char* cfgName)
+/**
+ * Reads 'socket_configuration/ip_rules' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool socket_config_read_iprules(const char *filename, struct config_t *config, bool imported)
{
- char line[1024],w1[1024],w2[1024];
- FILE *fp;
+#ifndef MINICORE
+ struct config_setting_t *setting = NULL;
+ const char *temp = NULL;
- fp = fopen(cfgName, "r");
- if(fp == NULL) {
- ShowError("File not found: %s\n", cfgName);
- return 1;
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "socket_configuration/ip_rules")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("socket_config_read: socket_configuration/ip_rules was not found in %s!\n", filename);
+ return false;
}
+ libconfig->setting_lookup_bool(setting, "enable", &ip_rules);
- while (fgets(line, sizeof(line), fp)) {
- if(line[0] == '/' && line[1] == '/')
- continue;
- if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
- continue;
+ if (!ip_rules)
+ return true;
- if (!strcmpi(w1, "stall_time")) {
- sockt->stall_time = atoi(w2);
- if( sockt->stall_time < 3 )
- sockt->stall_time = 3;/* a minimum is required to refrain it from killing itself */
+ if (libconfig->setting_lookup_string(setting, "order", &temp) == CONFIG_TRUE) {
+ if (strcmpi(temp, "deny,allow" ) == 0) {
+ access_order = ACO_DENY_ALLOW;
+ } else if (strcmpi(temp, "allow, deny") == 0) {
+ access_order = ACO_ALLOW_DENY;
+ } else if (strcmpi(temp, "mutual-failure") == 0) {
+ access_order = ACO_MUTUAL_FAILURE;
+ } else {
+ ShowWarning("socket_config_read: invalid value '%s' for socket_configuration/ip_rules/order.\n", temp);
}
+ }
+
+ if ((setting = libconfig->lookup(config, "socket_configuration/ip_rules/allow_list")) == NULL) {
+ if (!imported)
+ ShowError("socket_config_read: socket_configuration/ip_rules/allow_list was not found in %s!\n", filename);
+ } else {
+ access_list_add(setting, "allow_list", &access_allow);
+ }
+
+ if ((setting = libconfig->lookup(config, "socket_configuration/ip_rules/deny_list")) == NULL) {
+ if (!imported)
+ ShowError("socket_config_read: socket_configuration/ip_rules/deny_list was not found in %s!\n", filename);
+ } else {
+ access_list_add(setting, "deny_list", &access_deny);
+ }
+#endif // ! MINICORE
+
+ return true;
+}
+
+/**
+ * Reads 'socket_configuration/ddos' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool socket_config_read_ddos(const char *filename, struct config_t *config, bool imported)
+{
#ifndef MINICORE
- else if (!strcmpi(w1, "enable_ip_rules")) {
- ip_rules = config_switch(w2);
- } else if (!strcmpi(w1, "order")) {
- if (!strcmpi(w2, "deny,allow"))
- access_order = ACO_DENY_ALLOW;
- else if (!strcmpi(w2, "allow,deny"))
- access_order = ACO_ALLOW_DENY;
- else if (!strcmpi(w2, "mutual-failure"))
- access_order = ACO_MUTUAL_FAILURE;
- } else if (!strcmpi(w1, "allow")) {
- RECREATE(access_allow, AccessControl, access_allownum+1);
- if (access_ipmask(w2, &access_allow[access_allownum]))
- ++access_allownum;
- else
- ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line);
- } else if (!strcmpi(w1, "deny")) {
- RECREATE(access_deny, AccessControl, access_denynum+1);
- if (access_ipmask(w2, &access_deny[access_denynum]))
- ++access_denynum;
- else
- ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line);
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "socket_configuration/ddos")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("socket_config_read: socket_configuration/ddos was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_int(setting, "interval", &ddos_interval);
+ libconfig->setting_lookup_int(setting, "count", &ddos_count);
+ libconfig->setting_lookup_int(setting, "autoreset", &ddos_autoreset);
+
+#endif // ! MINICORE
+ return true;
+}
+
+/**
+ * Reads 'socket_configuration' and initializes required variables.
+ *
+ * @param filename Path to configuration file.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool socket_config_read(const char *filename, bool imported)
+{
+ struct config_t config;
+ struct config_setting_t *setting = NULL;
+ const char *import;
+ int i32 = 0;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false;
+
+ if ((setting = libconfig->lookup(&config, "socket_configuration")) == NULL) {
+ libconfig->destroy(&config);
+ if (imported)
+ return true;
+ ShowError("socket_config_read: socket_configuration was not found in %s!\n", filename);
+ return false;
+ }
+
+ if (libconfig->setting_lookup_int(setting, "stall_time", &i32) == CONFIG_TRUE) {
+ if (i32 < 3)
+ i32 = 3; /* a minimum is required in order to refrain from killing itself */
+ sockt->stall_time = i32;
+ }
+
+#ifdef SOCKET_EPOLL
+ if (libconfig->setting_lookup_int(setting, "epoll_maxevents", &i32) == CONFIG_TRUE) {
+ if (i32 < 16)
+ i32 = 16; // minimum that seems to be useful
+ epoll_maxevents = i32;
+ }
+#endif // SOCKET_EPOLL
+
+#ifndef MINICORE
+ {
+ uint32 ui32 = 0;
+ libconfig->setting_lookup_bool(setting, "debug", &access_debug);
+ if (libconfig->setting_lookup_uint32(setting, "socket_max_client_packet", &ui32) == CONFIG_TRUE) {
+ socket_max_client_packet = ui32;
}
- else if (!strcmpi(w1,"ddos_interval"))
- ddos_interval = atoi(w2);
- else if (!strcmpi(w1,"ddos_count"))
- ddos_count = atoi(w2);
- else if (!strcmpi(w1,"ddos_autoreset"))
- ddos_autoreset = atoi(w2);
- else if (!strcmpi(w1,"debug"))
- access_debug = config_switch(w2);
- else if (!strcmpi(w1,"socket_max_client_packet"))
- socket_max_client_packet = strtoul(w2, NULL, 0);
-#endif
- else if (!strcmpi(w1, "import"))
- socket_config_read(w2);
- else
- ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
- }
-
- fclose(fp);
- return 0;
+ }
+
+ if (!socket_config_read_iprules(filename, &config, imported))
+ retval = false;
+ if (!socket_config_read_ddos(filename, &config, imported))
+ retval = false;
+#endif // MINICORE
+
+ // import should overwrite any previous configuration, so it should be called last
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, SOCKET_CONF_FILENAME) == 0) {
+ ShowWarning("socket_config_read: Loop detected! Skipping 'import'...\n");
+ } else {
+ if (!socket_config_read(import, true))
+ retval = false;
+ }
+ }
+
+ libconfig->destroy(&config);
+ return retval;
}
void socket_final(void)
@@ -1234,11 +1490,9 @@ void socket_final(void)
#ifndef MINICORE
if( connect_history )
db_destroy(connect_history);
- if( access_allow )
- aFree(access_allow);
- if( access_deny )
- aFree(access_deny);
-#endif
+ VECTOR_CLEAR(access_allow);
+ VECTOR_CLEAR(access_deny);
+#endif // MINICORE
for( i = 1; i < sockt->fd_max; i++ )
if(sockt->session[i])
@@ -1254,6 +1508,18 @@ void socket_final(void)
VECTOR_CLEAR(sockt->lan_subnets);
VECTOR_CLEAR(sockt->allowed_ips);
VECTOR_CLEAR(sockt->trusted_ips);
+
+#ifdef SOCKET_EPOLL
+ if(epfd != SOCKET_ERROR){
+ close(epfd);
+ epfd = SOCKET_ERROR;
+ }
+ if(epevents != NULL){
+ aFree(epevents);
+ epevents = NULL;
+ }
+#endif // SOCKET_EPOLL
+
}
/// Closes a socket.
@@ -1263,7 +1529,17 @@ void socket_close(int fd)
return;// invalid
sockt->flush(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket)
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher
sFD_CLR(fd, &readfds);// this needs to be done before closing the socket
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+ epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &epevent); // removing the socket from epoll when it's being closed is not required but recommended
+#endif // SOCKET_EPOLL
+
sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes
sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket.
if (sockt->session[fd]) delete_session(fd);
@@ -1354,7 +1630,6 @@ int socket_getips(uint32* ips, int max)
void socket_init(void)
{
- char *SOCKET_CONF_FILENAME = "conf/packet.conf";
uint64 rlim_cur = FD_SETSIZE;
#ifdef WIN32
@@ -1400,20 +1675,44 @@ void socket_init(void)
}
}
}
-#endif
+#endif // defined(HAVE_SETRLIMIT) && !defined(CYGWIN)
+
+#ifndef MINICORE
+ VECTOR_INIT(access_allow);
+ VECTOR_INIT(access_deny);
+#endif // ! MINICORE
// Get initial local ips
sockt->naddr_ = sockt->getips(sockt->addr_,16);
+ socket_config_read(SOCKET_CONF_FILENAME, false);
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher:
sFD_ZERO(&readfds);
+ ShowInfo("Server uses '" CL_WHITE "select" CL_RESET "' as event dispatcher\n");
+
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher:
+ epfd = epoll_create(FD_SETSIZE); // 2.6.8 or newer ignores the expected socket amount argument
+ if(epfd == SOCKET_ERROR){
+ ShowError("Failed to Create Epoll Event Dispatcher: %s\n", error_msg());
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&epevent, 0x00, sizeof(struct epoll_event));
+ epevents = aCalloc(epoll_maxevents, sizeof(struct epoll_event));
+
+ ShowInfo("Server uses '" CL_WHITE "epoll" CL_RESET "' with up to " CL_WHITE "%d" CL_RESET " events per cycle as event dispatcher\n", epoll_maxevents);
+
+#endif // SOCKET_EPOLL
+
#if defined(SEND_SHORTLIST)
memset(send_shortlist_set, 0, sizeof(send_shortlist_set));
-#endif
+#endif // defined(SEND_SHORTLIST)
CREATE(sockt->session, struct socket_data *, FD_SETSIZE);
- socket_config_read(SOCKET_CONF_FILENAME);
-
// initialize last send-receive tick
sockt->last_tick = time(NULL);
@@ -1426,9 +1725,9 @@ void socket_init(void)
connect_history = uidb_alloc(DB_OPT_RELEASE_DATA);
timer->add_func_list(connect_check_clear, "connect_check_clear");
timer->add_interval(timer->gettick()+1000, connect_check_clear, 0, 0, 5*60*1000);
-#endif
+#endif // MINICORE
- ShowInfo("Server supports up to '"CL_WHITE"%"PRId64""CL_RESET"' concurrent connections.\n", rlim_cur);
+ ShowInfo("Server supports up to '"CL_WHITE"%"PRIu64""CL_RESET"' concurrent connections.\n", rlim_cur);
}
bool session_is_valid(int fd)
@@ -1442,9 +1741,11 @@ bool session_is_active(int fd)
}
// Resolves hostname into a numeric ip.
-uint32 host2ip(const char* hostname)
+uint32 host2ip(const char *hostname)
{
- struct hostent* h = gethostbyname(hostname);
+ struct hostent* h;
+ nullpo_ret(hostname);
+ h = gethostbyname(hostname);
return (h != NULL) ? ntohl(*(uint32*)h->h_addr) : 0;
}
@@ -1477,7 +1778,8 @@ uint16 ntows(uint16 netshort)
}
/* [Ind/Hercules] - socket_datasync */
-void socket_datasync(int fd, bool send) {
+void socket_datasync(int fd, bool send)
+{
struct {
unsigned int length;/* short is not enough for some */
} data_list[] = {
@@ -1616,7 +1918,7 @@ void send_shortlist_do_sends(void)
}
}
}
-#endif
+#endif // SEND_SHORTLIST
/**
* Checks whether the given IP comes from LAN or WAN.
@@ -1686,7 +1988,7 @@ bool socket_trusted_ip_check(uint32 ip)
* @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_vector *list, const char *filename, const char *groupname)
+int socket_net_config_read_sub(struct config_setting_t *t, struct s_subnet_vector *list, const char *filename, const char *groupname)
{
int i, len;
char ipbuf[64], maskbuf[64];
@@ -1722,11 +2024,11 @@ int socket_net_config_read_sub(config_setting_t *t, struct s_subnet_vector *list
*/
void socket_net_config_read(const char *filename)
{
- config_t network_config;
+ struct config_t network_config;
int i;
nullpo_retv(filename);
- if (libconfig->read_file(&network_config, filename)) {
+ if (!libconfig->load_file(&network_config, filename)) {
ShowError("LAN Support configuration file is not found: '%s'. This server won't be able to accept connections from any servers.\n", filename);
return;
}
@@ -1751,15 +2053,18 @@ void socket_net_config_read(const char *filename)
ShowError("No allowed server IP ranges configured. This server won't be able to accept connections from any char servers.\n");
}
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));
+#ifndef BUILDBOT
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);
}
+#endif // BUILDBOT
libconfig->destroy(&network_config);
return;
}
-void socket_defaults(void) {
+void socket_defaults(void)
+{
sockt = &sockt_s;
sockt->fd_max = 0;
diff --git a/src/common/socket.h b/src/common/socket.h
index 8936c7772..e3a309f20 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -22,7 +22,6 @@
#define COMMON_SOCKET_H
#include "common/hercules.h"
-#include "common/conf.h"
#include "common/db.h"
#ifdef WIN32
@@ -34,7 +33,9 @@
# include <sys/types.h>
#endif
+/* Forward Declarations */
struct hplugin_data_store;
+struct config_setting_t;
#define FIFOSIZE_SERVERLINK 256*1024
@@ -46,16 +47,16 @@ struct hplugin_data_store;
sockt->realloc_writefifo((fd), (size)); \
} while(0)
-#define RFIFOP(fd,pos) (sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos + (pos))
-#define WFIFOP(fd,pos) (sockt->session[fd]->wdata + sockt->session[fd]->wdata_size + (pos))
+#define RFIFOP(fd,pos) ((const void *)(sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos + (pos)))
+#define WFIFOP(fd,pos) ((void *)(sockt->session[fd]->wdata + sockt->session[fd]->wdata_size + (pos)))
-#define RFIFOB(fd,pos) (*(uint8*)RFIFOP((fd),(pos)))
+#define RFIFOB(fd,pos) (*(const uint8*)RFIFOP((fd),(pos)))
#define WFIFOB(fd,pos) (*(uint8*)WFIFOP((fd),(pos)))
-#define RFIFOW(fd,pos) (*(uint16*)RFIFOP((fd),(pos)))
+#define RFIFOW(fd,pos) (*(const uint16*)RFIFOP((fd),(pos)))
#define WFIFOW(fd,pos) (*(uint16*)WFIFOP((fd),(pos)))
-#define RFIFOL(fd,pos) (*(uint32*)RFIFOP((fd),(pos)))
+#define RFIFOL(fd,pos) (*(const uint32*)RFIFOP((fd),(pos)))
#define WFIFOL(fd,pos) (*(uint32*)WFIFOP((fd),(pos)))
-#define RFIFOQ(fd,pos) (*(uint64*)RFIFOP((fd),(pos)))
+#define RFIFOQ(fd,pos) (*(const uint64*)RFIFOP((fd),(pos)))
#define WFIFOQ(fd,pos) (*(uint64*)WFIFOP((fd),(pos)))
#define RFIFOSPACE(fd) (sockt->session[fd]->max_rdata - sockt->session[fd]->rdata_size)
#define WFIFOSPACE(fd) (sockt->session[fd]->max_wdata - sockt->session[fd]->wdata_size)
@@ -76,21 +77,31 @@ struct hplugin_data_store;
#define RFIFOSKIP(fd, len) (sockt->rfifoskip(fd, len))
/* [Ind/Hercules] */
-#define RFIFO2PTR(fd) (void*)(sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos)
+#define RFIFO2PTR(fd) ((const void *)(sockt->session[fd]->rdata + sockt->session[fd]->rdata_pos))
#define RP2PTR(fd) RFIFO2PTR(fd)
/* [Hemagx/Hercules] */
-#define WFIFO2PTR(fd) (void*)(sockt->session[fd]->wdata + sockt->session[fd]->wdata_pos)
+#define WFIFO2PTR(fd) ((void *)(sockt->session[fd]->wdata + sockt->session[fd]->wdata_size))
#define WP2PTR(fd) WFIFO2PTR(fd)
// buffer I/O macros
-#define RBUFP(p,pos) (((uint8*)(p)) + (pos))
-#define RBUFB(p,pos) (*(uint8*)RBUFP((p),(pos)))
-#define RBUFW(p,pos) (*(uint16*)RBUFP((p),(pos)))
-#define RBUFL(p,pos) (*(uint32*)RBUFP((p),(pos)))
-#define RBUFQ(p,pos) (*(uint64*)RBUFP((p),(pos)))
-
-#define WBUFP(p,pos) (((uint8*)(p)) + (pos))
+static inline const void *RBUFP_(const void *p, int pos) __attribute__((const, unused));
+static inline const void *RBUFP_(const void *p, int pos)
+{
+ return ((const uint8 *)p) + pos;
+}
+#define RBUFP(p,pos) RBUFP_(p, (int)(pos))
+#define RBUFB(p,pos) (*(const uint8 *)RBUFP((p),(pos)))
+#define RBUFW(p,pos) (*(const uint16 *)RBUFP((p),(pos)))
+#define RBUFL(p,pos) (*(const uint32 *)RBUFP((p),(pos)))
+#define RBUFQ(p,pos) (*(const uint64 *)RBUFP((p),(pos)))
+
+static inline void *WBUFP_(void *p, int pos) __attribute__((const, unused));
+static inline void *WBUFP_(void *p, int pos)
+{
+ return ((uint8 *)p) + pos;
+}
+#define WBUFP(p,pos) WBUFP_(p, (int)(pos))
#define WBUFB(p,pos) (*(uint8*)WBUFP((p),(pos)))
#define WBUFW(p,pos) (*(uint16*)WBUFP((p),(pos)))
#define WBUFL(p,pos) (*(uint32*)WBUFP((p),(pos)))
@@ -214,7 +225,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_vector *list, const char *filename, const char *groupname);
+ int (*net_config_read_sub) (struct 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/spinlock.h b/src/common/spinlock.h
index 4d9c4c668..c04416285 100644
--- a/src/common/spinlock.h
+++ b/src/common/spinlock.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -37,74 +37,75 @@
#endif
#ifdef WIN32
-
-typedef struct __declspec( align(64) ) SPIN_LOCK{
+struct __declspec(align(64)) spin_lock {
volatile LONG lock;
volatile LONG nest;
volatile LONG sync_lock;
-} SPIN_LOCK;
+};
#else
-typedef struct SPIN_LOCK{
- volatile int32 lock;
- volatile int32 nest; // nesting level.
-
- volatile int32 sync_lock;
-} __attribute__((aligned(64))) SPIN_LOCK;
+struct spin_lock {
+ volatile int32 lock;
+ volatile int32 nest; // nesting level.
+ volatile int32 sync_lock;
+} __attribute__((aligned(64)));
#endif
-
#ifdef HERCULES_CORE
-static forceinline void InitializeSpinLock(SPIN_LOCK *lck){
- lck->lock = 0;
- lck->nest = 0;
- lck->sync_lock = 0;
+static forceinline void InitializeSpinLock(struct spin_lock *lck)
+{
+ lck->lock = 0;
+ lck->nest = 0;
+ lck->sync_lock = 0;
}
-static forceinline void FinalizeSpinLock(SPIN_LOCK *lck){
+static forceinline void FinalizeSpinLock(struct spin_lock *lck)
+{
return;
}
-#define getsynclock(l) do { if(InterlockedCompareExchange((l), 1, 0) == 0) break; rathread_yield(); } while(/*always*/1)
+#define getsynclock(l) do { if(InterlockedCompareExchange((l), 1, 0) == 0) break; thread->yield(); } while(/*always*/1)
#define dropsynclock(l) do { InterlockedExchange((l), 0); } while(0)
-static forceinline void EnterSpinLock(SPIN_LOCK *lck){
- int tid = rathread_get_tid();
+static forceinline void EnterSpinLock(struct spin_lock *lck)
+{
+ int tid = thread->get_tid();
- // Get Sync Lock && Check if the requester thread already owns the lock.
- // if it owns, increase nesting level
- getsynclock(&lck->sync_lock);
- if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){
- InterlockedIncrement(&lck->nest);
- dropsynclock(&lck->sync_lock);
- return; // Got Lock
- }
- // drop sync lock
+ // Get Sync Lock && Check if the requester thread already owns the lock.
+ // if it owns, increase nesting level
+ getsynclock(&lck->sync_lock);
+ if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) {
+ InterlockedIncrement(&lck->nest);
dropsynclock(&lck->sync_lock);
-
- // Spin until we've got it !
- while(1){
- if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){
- InterlockedIncrement(&lck->nest);
- return; // Got Lock
- }
- rathread_yield(); // Force ctxswitch to another thread.
+ return; // Got Lock
+ }
+ // drop sync lock
+ dropsynclock(&lck->sync_lock);
+
+ // Spin until we've got it !
+ while (true) {
+ if (InterlockedCompareExchange(&lck->lock, tid, 0) == 0) {
+ InterlockedIncrement(&lck->nest);
+ return; // Got Lock
}
+ thread->yield(); // Force ctxswitch to another thread.
+ }
}
-static forceinline void LeaveSpinLock(SPIN_LOCK *lck){
- int tid = rathread_get_tid();
+static forceinline void LeaveSpinLock(struct spin_lock *lck)
+{
+ int tid = thread->get_tid();
- getsynclock(&lck->sync_lock);
+ getsynclock(&lck->sync_lock);
- if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock.
- if(InterlockedDecrement(&lck->nest) == 0)
- InterlockedExchange(&lck->lock, 0); // Unlock!
- }
+ if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { // this thread owns the lock.
+ if (InterlockedDecrement(&lck->nest) == 0)
+ InterlockedExchange(&lck->lock, 0); // Unlock!
+ }
- dropsynclock(&lck->sync_lock);
+ dropsynclock(&lck->sync_lock);
}
#endif // HERCULES_CORE
diff --git a/src/common/sql.c b/src/common/sql.c
index f6280c436..c80edbce4 100644
--- a/src/common/sql.c
+++ b/src/common/sql.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -23,7 +23,9 @@
#include "sql.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/memmgr.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
#include "common/timer.h"
@@ -32,12 +34,13 @@
# include "common/winapi.h" // Needed before mysql.h
#endif
#include <mysql.h>
+#include <stdio.h>
#include <stdlib.h> // strtoul
void hercules_mysql_error_handler(unsigned int ecode);
-int mysql_reconnect_type;
-unsigned int mysql_reconnect_count;
+int mysql_reconnect_type = 2;
+int mysql_reconnect_count = 1;
struct sql_interface sql_s;
struct sql_interface *SQL;
@@ -78,11 +81,11 @@ struct SqlStmt {
///////////////////////////////////////////////////////////////////////////////
/// Allocates and initializes a new Sql handle.
-Sql* Sql_Malloc(void)
+struct Sql *Sql_Malloc(void)
{
- Sql* self;
+ struct Sql *self;
- CREATE(self, Sql, 1);
+ CREATE(self, struct Sql, 1);
mysql_init(&self->handle);
StrBuf->Init(&self->buf);
self->lengths = NULL;
@@ -92,10 +95,10 @@ Sql* Sql_Malloc(void)
return self;
}
-static int Sql_P_Keepalive(Sql* self);
+static int Sql_P_Keepalive(struct Sql *self);
/// Establishes a connection.
-int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db)
+int Sql_Connect(struct Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db)
{
if( self == NULL )
return SQL_ERROR;
@@ -118,7 +121,7 @@ int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* hos
}
/// Retrieves the timeout of the connection.
-int Sql_GetTimeout(Sql* self, uint32* out_timeout)
+int Sql_GetTimeout(struct Sql *self, uint32 *out_timeout)
{
if( self && out_timeout && SQL_SUCCESS == SQL->Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) {
char* data;
@@ -135,12 +138,13 @@ int Sql_GetTimeout(Sql* self, uint32* out_timeout)
}
/// Retrieves the name of the columns of a table into out_buf, with the separator after each name.
-int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep)
+int Sql_GetColumnNames(struct Sql *self, const char *table, char *out_buf, size_t buf_len, char sep)
{
char* data;
size_t len;
size_t off = 0;
+ nullpo_retr(SQL_ERROR, out_buf);
if( self == NULL || SQL_ERROR == SQL->Query(self, "EXPLAIN `%s`", table) )
return SQL_ERROR;
@@ -163,7 +167,7 @@ int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_l
}
/// Changes the encoding of the connection.
-int Sql_SetEncoding(Sql* self, const char* encoding)
+int Sql_SetEncoding(struct Sql *self, const char *encoding)
{
if( self && mysql_set_character_set(&self->handle, encoding) == 0 )
return SQL_SUCCESS;
@@ -171,7 +175,7 @@ int Sql_SetEncoding(Sql* self, const char* encoding)
}
/// Pings the connection.
-int Sql_Ping(Sql* self)
+int Sql_Ping(struct Sql *self)
{
if( self && mysql_ping(&self->handle) == 0 )
return SQL_SUCCESS;
@@ -183,7 +187,7 @@ int Sql_Ping(Sql* self)
/// @private
static int Sql_P_KeepaliveTimer(int tid, int64 tick, int id, intptr_t data)
{
- Sql* self = (Sql*)data;
+ struct Sql *self = (struct Sql *)data;
ShowInfo("Pinging SQL server to keep connection alive...\n");
Sql_Ping(self);
return 0;
@@ -193,7 +197,7 @@ static int Sql_P_KeepaliveTimer(int tid, int64 tick, int id, intptr_t data)
///
/// @return the keepalive timer id, or INVALID_TIMER
/// @private
-static int Sql_P_Keepalive(Sql* self)
+static int Sql_P_Keepalive(struct Sql *self)
{
uint32 timeout, ping_interval;
@@ -213,26 +217,27 @@ static int Sql_P_Keepalive(Sql* self)
}
/// Escapes a string.
-size_t Sql_EscapeString(Sql* self, char *out_to, const char *from)
+size_t Sql_EscapeString(struct Sql *self, char *out_to, const char *from)
{
- if( self )
+ if (self != NULL)
return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from));
else
return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from));
}
/// Escapes a string.
-size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len)
+size_t Sql_EscapeStringLen(struct Sql *self, char *out_to, const char *from, size_t from_len)
{
- if( self )
+ if (self != NULL)
return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len);
else
return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len);
}
/// Executes a query.
-int Sql_Query(Sql *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
-int Sql_Query(Sql *self, const char *query, ...) {
+int Sql_Query(struct Sql *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
+int Sql_Query(struct Sql *self, const char *query, ...)
+{
int res;
va_list args;
@@ -244,7 +249,7 @@ int Sql_Query(Sql *self, const char *query, ...) {
}
/// Executes a query.
-int Sql_QueryV(Sql* self, const char* query, va_list args)
+int Sql_QueryV(struct Sql *self, const char *query, va_list args)
{
if( self == NULL )
return SQL_ERROR;
@@ -269,7 +274,7 @@ int Sql_QueryV(Sql* self, const char* query, va_list args)
}
/// Executes a query.
-int Sql_QueryStr(Sql* self, const char* query)
+int Sql_QueryStr(struct Sql *self, const char *query)
{
if( self == NULL )
return SQL_ERROR;
@@ -294,33 +299,34 @@ int Sql_QueryStr(Sql* self, const char* query)
}
/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query.
-uint64 Sql_LastInsertId(Sql* self)
+uint64 Sql_LastInsertId(struct Sql *self)
{
- if( self )
+ if (self != NULL)
return (uint64)mysql_insert_id(&self->handle);
else
return 0;
}
/// Returns the number of columns in each row of the result.
-uint32 Sql_NumColumns(Sql* self)
+uint32 Sql_NumColumns(struct Sql *self)
{
- if( self && self->result )
+ if (self != NULL && self->result != NULL)
return (uint32)mysql_num_fields(self->result);
return 0;
}
/// Returns the number of rows in the result.
-uint64 Sql_NumRows(Sql* self)
+uint64 Sql_NumRows(struct Sql *self)
{
- if( self && self->result )
+ if (self != NULL && self->result != NULL)
return (uint64)mysql_num_rows(self->result);
return 0;
}
/// Fetches the next row.
-int Sql_NextRow(Sql* self) {
- if( self && self->result ) {
+int Sql_NextRow(struct Sql *self)
+{
+ if (self != NULL && self->result != NULL) {
self->row = mysql_fetch_row(self->result);
if( self->row ) {
self->lengths = mysql_fetch_lengths(self->result);
@@ -334,7 +340,7 @@ int Sql_NextRow(Sql* self) {
}
/// Gets the data of a column.
-int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len)
+int Sql_GetData(struct Sql *self, size_t col, char **out_buf, size_t *out_len)
{
if( self && self->row ) {
if( col < SQL->NumColumns(self) ) {
@@ -350,7 +356,8 @@ int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len)
}
/// Frees the result of the query.
-void Sql_FreeResult(Sql* self) {
+void Sql_FreeResult(struct Sql *self)
+{
if( self && self->result ) {
mysql_free_result(self->result);
self->result = NULL;
@@ -360,7 +367,7 @@ void Sql_FreeResult(Sql* self) {
}
/// Shows debug information (last query).
-void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line)
+void Sql_ShowDebug_(struct Sql *self, const char *debug_file, const unsigned long debug_line)
{
if( self == NULL )
ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line);
@@ -371,7 +378,8 @@ void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug
}
/// Frees a Sql handle returned by Sql_Malloc.
-void Sql_Free(Sql* self) {
+void Sql_Free(struct Sql *self)
+{
if( self )
{
SQL->FreeResult(self);
@@ -408,6 +416,7 @@ static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz)
/// @private
static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null)
{
+ nullpo_retr(SQL_ERROR, bind);
memset(bind, 0, sizeof(MYSQL_BIND));
switch( buffer_type )
{
@@ -416,39 +425,48 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type,
break;
// fixed size
case SQLDT_UINT8: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY;
buffer_len = 1;
break;
case SQLDT_UINT16: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT;
buffer_len = 2;
break;
case SQLDT_UINT32: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG;
buffer_len = 4;
break;
case SQLDT_UINT64: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG;
buffer_len = 8;
break;
// platform dependent size
case SQLDT_UCHAR: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char));
buffer_len = sizeof(char);
break;
case SQLDT_USHORT: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short));
buffer_len = sizeof(short);
break;
case SQLDT_UINT: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int));
buffer_len = sizeof(int);
break;
case SQLDT_ULONG: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long));
buffer_len = sizeof(long);
break;
case SQLDT_ULONGLONG: bind->is_unsigned = 1;
+ FALLTHROUGH
case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64));
buffer_len = sizeof(int64);
break;
@@ -466,7 +484,7 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type,
case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB;
break;
default:
- ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type);
+ ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%u)\n", buffer_type);
return SQL_ERROR;
}
bind->buffer = buffer;
@@ -479,7 +497,8 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type,
/// Prints debug information about a field (type and length).
///
/// @private
-static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) {
+static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix)
+{
const char *sign = (is_unsigned ? "UNSIGNED " : "");
const char *type_string = NULL;
switch (type) {
@@ -514,12 +533,13 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_ty
/// Reports debug information about a truncated column.
///
/// @private
-static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i)
+static void SqlStmt_P_ShowDebugTruncatedColumn(struct SqlStmt *self, size_t i)
{
MYSQL_RES* meta;
MYSQL_FIELD* field;
MYSQL_BIND* column;
+ nullpo_retv(self);
meta = mysql_stmt_result_metadata(self->stmt);
field = mysql_fetch_field_direct(meta, (unsigned int)i);
ShowSQL("DB error - data of field '%s' was truncated.\n", field->name);
@@ -534,8 +554,9 @@ static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i)
}
/// Allocates and initializes a new SqlStmt handle.
-SqlStmt* SqlStmt_Malloc(Sql* sql) {
- SqlStmt* self;
+struct SqlStmt *SqlStmt_Malloc(struct Sql *sql)
+{
+ struct SqlStmt *self;
MYSQL_STMT* stmt;
if( sql == NULL )
@@ -546,7 +567,7 @@ SqlStmt* SqlStmt_Malloc(Sql* sql) {
ShowSQL("DB error - %s\n", mysql_error(&sql->handle));
return NULL;
}
- CREATE(self, SqlStmt, 1);
+ CREATE(self, struct SqlStmt, 1);
StrBuf->Init(&self->buf);
self->stmt = stmt;
self->params = NULL;
@@ -561,8 +582,9 @@ SqlStmt* SqlStmt_Malloc(Sql* sql) {
}
/// Prepares the statement.
-int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
-int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) {
+int SqlStmt_Prepare(struct SqlStmt *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
+int SqlStmt_Prepare(struct SqlStmt *self, const char *query, ...)
+{
int res;
va_list args;
@@ -574,7 +596,7 @@ int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) {
}
/// Prepares the statement.
-int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
+int SqlStmt_PrepareV(struct SqlStmt *self, const char *query, va_list args)
{
if( self == NULL )
return SQL_ERROR;
@@ -594,7 +616,7 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
}
/// Prepares the statement.
-int SqlStmt_PrepareStr(SqlStmt* self, const char* query)
+int SqlStmt_PrepareStr(struct SqlStmt *self, const char *query)
{
if( self == NULL )
return SQL_ERROR;
@@ -614,7 +636,7 @@ int SqlStmt_PrepareStr(SqlStmt* self, const char* query)
}
/// Returns the number of parameters in the prepared statement.
-size_t SqlStmt_NumParams(SqlStmt* self)
+size_t SqlStmt_NumParams(struct SqlStmt *self)
{
if( self )
return (size_t)mysql_stmt_param_count(self->stmt);
@@ -623,7 +645,7 @@ size_t SqlStmt_NumParams(SqlStmt* self)
}
/// Binds a parameter to a buffer.
-int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len)
+int SqlStmt_BindParam(struct SqlStmt *self, size_t idx, enum SqlDataType buffer_type, const void *buffer, size_t buffer_len)
{
if( self == NULL )
return SQL_ERROR;
@@ -644,14 +666,23 @@ int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, v
self->params[i].buffer_type = MYSQL_TYPE_NULL;
self->bind_params = true;
}
- if( idx < self->max_params )
- return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL);
- else
- return SQL_SUCCESS;// out of range - ignore
+ if (idx >= self->max_params)
+ return SQL_SUCCESS; // out of range - ignore
+
+PRAGMA_GCC46(GCC diagnostic push)
+PRAGMA_GCC46(GCC diagnostic ignored "-Wcast-qual")
+ /*
+ * MySQL uses the same struct with a non-const buffer for both
+ * parameters (input) and columns (output).
+ * As such, we get to close our eyes and pretend we didn't see we're
+ * dropping a const qualifier here.
+ */
+ return Sql_P_BindSqlDataType(self->params+idx, buffer_type, (void *)buffer, buffer_len, NULL, NULL);
+PRAGMA_GCC46(GCC diagnostic pop)
}
/// Executes the prepared statement.
-int SqlStmt_Execute(SqlStmt* self)
+int SqlStmt_Execute(struct SqlStmt *self)
{
if( self == NULL )
return SQL_ERROR;
@@ -676,7 +707,7 @@ int SqlStmt_Execute(SqlStmt* self)
}
/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement.
-uint64 SqlStmt_LastInsertId(SqlStmt* self)
+uint64 SqlStmt_LastInsertId(struct SqlStmt *self)
{
if( self )
return (uint64)mysql_stmt_insert_id(self->stmt);
@@ -685,7 +716,7 @@ uint64 SqlStmt_LastInsertId(SqlStmt* self)
}
/// Returns the number of columns in each row of the result.
-size_t SqlStmt_NumColumns(SqlStmt* self)
+size_t SqlStmt_NumColumns(struct SqlStmt *self)
{
if( self )
return (size_t)mysql_stmt_field_count(self->stmt);
@@ -694,7 +725,8 @@ size_t SqlStmt_NumColumns(SqlStmt* self)
}
/// Binds the result of a column to a buffer.
-int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null) {
+int SqlStmt_BindColumn(struct SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null)
+{
if (self == NULL)
return SQL_ERROR;
@@ -735,16 +767,16 @@ int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type,
}
/// Returns the number of rows in the result.
-uint64 SqlStmt_NumRows(SqlStmt* self)
+uint64 SqlStmt_NumRows(struct SqlStmt *self)
{
- if( self )
+ if (self != NULL)
return (uint64)mysql_stmt_num_rows(self->stmt);
else
return 0;
}
/// Fetches the next row.
-int SqlStmt_NextRow(SqlStmt* self)
+int SqlStmt_NextRow(struct SqlStmt *self)
{
int err;
size_t i;
@@ -762,8 +794,6 @@ int SqlStmt_NextRow(SqlStmt* self)
// check for errors
if (err == MYSQL_NO_DATA)
return SQL_NO_DATA;
-#if defined(MYSQL_DATA_TRUNCATED)
- // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS]
if (err == MYSQL_DATA_TRUNCATED) {
my_bool truncated;
@@ -788,7 +818,6 @@ int SqlStmt_NextRow(SqlStmt* self)
ShowSQL("DB error - data truncated (unknown source)\n");
return SQL_ERROR;
}
-#endif
if (err) {
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
@@ -800,18 +829,6 @@ int SqlStmt_NextRow(SqlStmt* self)
for (i = 0; i < cols; ++i) {
unsigned long length = self->column_lengths[i].length;
MYSQL_BIND *column = &self->columns[i];
-#if !defined(MYSQL_DATA_TRUNCATED)
- // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS]
- if (column->buffer_length < length) {
- // report truncated column
- if (column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB) {
- // string/enum/blob column
- SqlStmt_P_ShowDebugTruncatedColumn(self, i);
- return SQL_ERROR;
- }
- // FIXME numeric types and null [FlavioJS]
- }
-#endif
if (self->column_lengths[i].out_length)
*self->column_lengths[i].out_length = (uint32)length;
if (column->buffer_type == MYSQL_TYPE_STRING) {
@@ -827,14 +844,14 @@ int SqlStmt_NextRow(SqlStmt* self)
}
/// Frees the result of the statement execution.
-void SqlStmt_FreeResult(SqlStmt* self)
+void SqlStmt_FreeResult(struct SqlStmt *self)
{
if( self )
mysql_stmt_free_result(self->stmt);
}
/// Shows debug information (with statement).
-void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line)
+void SqlStmt_ShowDebug_(struct SqlStmt *self, const char *debug_file, const unsigned long debug_line)
{
if( self == NULL )
ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line);
@@ -845,7 +862,7 @@ void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned lo
}
/// Frees a SqlStmt returned by SqlStmt_Malloc.
-void SqlStmt_Free(SqlStmt* self)
+void SqlStmt_Free(struct SqlStmt *self)
{
if( self )
{
@@ -862,12 +879,14 @@ void SqlStmt_Free(SqlStmt* self)
aFree(self);
}
}
+
/* receives mysql error codes during runtime (not on first-time-connects) */
-void hercules_mysql_error_handler(unsigned int ecode) {
- static unsigned int retry = 1;
+void hercules_mysql_error_handler(unsigned int ecode)
+{
switch( ecode ) {
case 2003:/* Can't connect to MySQL (this error only happens here when failing to reconnect) */
if( mysql_reconnect_type == 1 ) {
+ static int retry = 1;
if( ++retry > mysql_reconnect_count ) {
ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry);
exit(EXIT_FAILURE);
@@ -876,49 +895,62 @@ void hercules_mysql_error_handler(unsigned int ecode) {
break;
}
}
-void Sql_inter_server_read(const char* cfgName, bool first) {
- char line[1024], w1[1024], w2[1024];
- FILE* fp;
-
- fp = fopen(cfgName, "r");
- if(fp == NULL) {
- if( first ) {
- ShowFatalError("File not found: %s\n", cfgName);
- exit(EXIT_FAILURE);
- } else
- ShowError("File not found: %s\n", cfgName);
- return;
+
+/**
+ * Parses mysql_reconnect from inter_configuration.
+ *
+ * @param filename Path to configuration file.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool Sql_inter_server_read(const char *filename, bool imported)
+{
+ struct config_t config;
+ const struct config_setting_t *setting = NULL;
+ const char *import = NULL;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false;
+
+ if ((setting = libconfig->lookup(&config, "inter_configuration/mysql_reconnect")) == NULL) {
+ config_destroy(&config);
+ if (imported)
+ return true;
+ ShowError("Sql_inter_server_read: inter_configuration/mysql_reconnect was not found in %s!\n", filename);
+ return false;
}
- while (fgets(line, sizeof(line), fp)) {
- int i = sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2);
- if (i != 2)
- continue;
+ if (libconfig->setting_lookup_int(setting, "type", &mysql_reconnect_type) == CONFIG_TRUE) {
+ if (mysql_reconnect_type != 1 && mysql_reconnect_type != 2) {
+ ShowError("%s::inter_configuration/mysql_reconnect/type is set to %d which is not valid, defaulting to 1...\n", filename, mysql_reconnect_type);
+ mysql_reconnect_type = 1;
+ }
+ }
+ if (libconfig->setting_lookup_int(setting, "count", &mysql_reconnect_count) == CONFIG_TRUE) {
+ if (mysql_reconnect_count < 1)
+ mysql_reconnect_count = 1;
+ }
- if(!strcmpi(w1,"mysql_reconnect_type")) {
- mysql_reconnect_type = atoi(w2);
- switch( mysql_reconnect_type ) {
- case 1:
- case 2:
- break;
- default:
- ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type);
- mysql_reconnect_type = 1;
- break;
- }
- } else if(!strcmpi(w1,"mysql_reconnect_count")) {
- mysql_reconnect_count = atoi(w2);
- if( mysql_reconnect_count < 1 )
- mysql_reconnect_count = 1;
- } else if(!strcmpi(w1,"import"))
- Sql_inter_server_read(w2,false);
+ // import should overwrite any previous configuration, so it should be called last
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, "conf/common/inter-server.conf") == 0) { // FIXME: Hardcoded path
+ ShowWarning("Sql_inter_server_read: Loop detected in %s! Skipping 'import'...\n", filename);
+ } else {
+ if (!Sql_inter_server_read(import, true))
+ retval = false;
+ }
}
- fclose(fp);
- return;
+ libconfig->destroy(&config);
+ return retval;
}
-void Sql_HerculesUpdateCheck(Sql* self) {
+void Sql_HerculesUpdateCheck(struct Sql *self)
+{
char line[22];// "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1
FILE* ifp;/* index fp */
unsigned int performed = 0;
@@ -971,7 +1003,7 @@ void Sql_HerculesUpdateCheck(Sql* self) {
fclose(ifp);
if( performed ) {
- ShowSQL("- detected %d new "CL_WHITE"SQL updates"CL_RESET"\n",performed);
+ ShowSQL("- detected %u new "CL_WHITE"SQL updates"CL_RESET"\n",performed);
ShowMessage("%s",StrBuf->Value(&buf));
ShowSQL("To manually skip, type: 'sql update skip <file name>'\n");
}
@@ -979,7 +1011,8 @@ void Sql_HerculesUpdateCheck(Sql* self) {
StrBuf->Destroy(&buf);
}
-void Sql_HerculesUpdateSkip(Sql* self,const char *filename) {
+void Sql_HerculesUpdateSkip(struct Sql *self, const char *filename)
+{
char path[41];// "sql-files/upgrades/" (19) + "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1
char timestamp[11];// "1360186680" (10) + 1
FILE* ifp;/* index fp */
@@ -1015,10 +1048,13 @@ void Sql_HerculesUpdateSkip(Sql* self,const char *filename) {
return;
}
-void Sql_Init(void) {
- Sql_inter_server_read("conf/inter-server.conf",true);
+void Sql_Init(void)
+{
+ Sql_inter_server_read("conf/common/inter-server.conf", false); // FIXME: Hardcoded path
}
-void sql_defaults(void) {
+
+void sql_defaults(void)
+{
SQL = &sql_s;
SQL->Connect = Sql_Connect;
diff --git a/src/common/sql.h b/src/common/sql.h
index e949a8280..4d9a12cc1 100644
--- a/src/common/sql.h
+++ b/src/common/sql.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -71,90 +71,86 @@ enum SqlDataType {
SQLDT_LASTID
};
-struct Sql;// Sql handle (private access)
-struct SqlStmt;// Sql statement (private access)
-
-typedef enum SqlDataType SqlDataType;
-typedef struct Sql Sql;
-typedef struct SqlStmt SqlStmt;
+struct Sql; ///< Sql handle (private access)
+struct SqlStmt; ///< Sql statement (private access)
struct sql_interface {
/// Establishes a connection.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*Connect) (Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db);
+ int (*Connect) (struct Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db);
/// Retrieves the timeout of the connection.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*GetTimeout) (Sql* self, uint32* out_timeout);
+ int (*GetTimeout) (struct Sql *self, uint32 *out_timeout);
/// Retrieves the name of the columns of a table into out_buf, with the separator after each name.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*GetColumnNames) (Sql* self, const char* table, char* out_buf, size_t buf_len, char sep);
+ int (*GetColumnNames) (struct Sql *self, const char *table, char *out_buf, size_t buf_len, char sep);
/// Changes the encoding of the connection.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*SetEncoding) (Sql* self, const char* encoding);
+ int (*SetEncoding) (struct Sql *self, const char *encoding);
/// Pings the connection.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*Ping) (Sql* self);
+ int (*Ping) (struct Sql *self);
/// Escapes a string.
/// The output buffer must be at least strlen(from)*2+1 in size.
///
/// @return The size of the escaped string
- size_t (*EscapeString) (Sql* self, char* out_to, const char* from);
+ size_t (*EscapeString) (struct Sql *self, char *out_to, const char *from);
/// Escapes a string.
/// The output buffer must be at least from_len*2+1 in size.
///
/// @return The size of the escaped string
- size_t (*EscapeStringLen) (Sql* self, char* out_to, const char* from, size_t from_len);
+ size_t (*EscapeStringLen) (struct Sql *self, char *out_to, const char *from, size_t from_len);
/// Executes a query.
/// Any previous result is freed.
/// The query is constructed as if it was sprintf.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*Query) (Sql *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
+ int (*Query) (struct Sql *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
/// Executes a query.
/// Any previous result is freed.
/// The query is constructed as if it was svprintf.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*QueryV) (Sql* self, const char* query, va_list args);
+ int (*QueryV) (struct Sql *self, const char *query, va_list args);
/// Executes a query.
/// Any previous result is freed.
/// The query is used directly.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*QueryStr) (Sql* self, const char* query);
+ int (*QueryStr) (struct Sql *self, const char *query);
/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query.
///
/// @return Value of the auto-increment column
- uint64 (*LastInsertId) (Sql* self);
+ uint64 (*LastInsertId) (struct Sql *self);
/// Returns the number of columns in each row of the result.
///
/// @return Number of columns
- uint32 (*NumColumns) (Sql* self);
+ uint32 (*NumColumns) (struct Sql *self);
/// Returns the number of rows in the result.
///
/// @return Number of rows
- uint64 (*NumRows) (Sql* self);
+ uint64 (*NumRows) (struct Sql *self);
/// Fetches the next row.
/// The data of the previous row is no longer valid.
///
/// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA
- int (*NextRow) (Sql* self);
+ int (*NextRow) (struct Sql *self);
/// Gets the data of a column.
/// The data remains valid until the next row is fetched or the result is freed.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*GetData) (Sql* self, size_t col, char** out_buf, size_t* out_len);
+ int (*GetData) (struct Sql *self, size_t col, char **out_buf, size_t *out_len);
/// Frees the result of the query.
- void (*FreeResult) (Sql* self);
+ void (*FreeResult) (struct Sql *self);
/// Shows debug information (last query).
- void (*ShowDebug_) (Sql* self, const char* debug_file, const unsigned long debug_line);
+ void (*ShowDebug_) (struct Sql *self, const char *debug_file, const unsigned long debug_line);
/// Frees a Sql handle returned by Sql_Malloc.
- void (*Free) (Sql* self);
+ void (*Free) (struct Sql *self);
/// Allocates and initializes a new Sql handle.
struct Sql *(*Malloc) (void);
@@ -180,56 +176,56 @@ struct sql_interface {
/// Queries in Sql and SqlStmt are independent and don't affect each other.
///
/// @return SqlStmt handle or NULL if an error occurred
- struct SqlStmt* (*StmtMalloc)(Sql* sql);
+ struct SqlStmt* (*StmtMalloc)(struct Sql *sql);
/// Prepares the statement.
/// Any previous result is freed and all parameter bindings are removed.
/// The query is constructed as if it was sprintf.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtPrepare) (SqlStmt *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
+ int (*StmtPrepare) (struct SqlStmt *self, const char *query, ...) __attribute__((format(printf, 2, 3)));
/// Prepares the statement.
/// Any previous result is freed and all parameter bindings are removed.
/// The query is constructed as if it was svprintf.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtPrepareV)(SqlStmt* self, const char* query, va_list args);
+ int (*StmtPrepareV)(struct SqlStmt *self, const char *query, va_list args);
/// Prepares the statement.
/// Any previous result is freed and all parameter bindings are removed.
/// The query is used directly.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtPrepareStr)(SqlStmt* self, const char* query);
+ int (*StmtPrepareStr)(struct SqlStmt *self, const char *query);
/// Returns the number of parameters in the prepared statement.
///
/// @return Number or parameters
- size_t (*StmtNumParams)(SqlStmt* self);
+ size_t (*StmtNumParams)(struct SqlStmt *self);
/// Binds a parameter to a buffer.
/// The buffer data will be used when the statement is executed.
/// All parameters should have bindings.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtBindParam)(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len);
+ int (*StmtBindParam)(struct SqlStmt *self, size_t idx, enum SqlDataType buffer_type, const void *buffer, size_t buffer_len);
/// Executes the prepared statement.
/// Any previous result is freed and all column bindings are removed.
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtExecute)(SqlStmt* self);
+ int (*StmtExecute)(struct SqlStmt *self);
/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement.
///
/// @return Value of the auto-increment column
- uint64 (*StmtLastInsertId)(SqlStmt* self);
+ uint64 (*StmtLastInsertId)(struct SqlStmt *self);
/// Returns the number of columns in each row of the result.
///
/// @return Number of columns
- size_t (*StmtNumColumns)(SqlStmt* self);
+ size_t (*StmtNumColumns)(struct SqlStmt *self);
/// Binds the result of a column to a buffer.
/// The buffer will be filled with data when the next row is fetched.
@@ -237,26 +233,26 @@ struct sql_interface {
/// and the null-terminator (an extra byte).
///
/// @return SQL_SUCCESS or SQL_ERROR
- int (*StmtBindColumn)(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null);
+ int (*StmtBindColumn)(struct SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null);
/// Returns the number of rows in the result.
///
/// @return Number of rows
- uint64 (*StmtNumRows)(SqlStmt* self);
+ uint64 (*StmtNumRows)(struct SqlStmt *self);
/// Fetches the next row.
/// All column bindings will be filled with data.
///
/// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA
- int (*StmtNextRow)(SqlStmt* self);
+ int (*StmtNextRow)(struct SqlStmt *self);
/// Frees the result of the statement execution.
- void (*StmtFreeResult)(SqlStmt* self);
+ void (*StmtFreeResult)(struct SqlStmt *self);
/// Frees a SqlStmt returned by SqlStmt_Malloc.
- void (*StmtFree)(SqlStmt* self);
+ void (*StmtFree)(struct SqlStmt *self);
- void (*StmtShowDebug_)(SqlStmt* self, const char* debug_file, const unsigned long debug_line);
+ void (*StmtShowDebug_)(struct SqlStmt *self, const char *debug_file, const unsigned long debug_line);
};
@@ -265,8 +261,8 @@ void sql_defaults(void);
void Sql_Init(void);
-void Sql_HerculesUpdateCheck(Sql* self);
-void Sql_HerculesUpdateSkip(Sql* self,const char *filename);
+void Sql_HerculesUpdateCheck(struct Sql *self);
+void Sql_HerculesUpdateSkip(struct Sql *self, const char *filename);
#endif // HERCULES_CORE
HPShared struct sql_interface *SQL;
diff --git a/src/common/strlib.c b/src/common/strlib.c
index 997b01ffa..df8093456 100644
--- a/src/common/strlib.c
+++ b/src/common/strlib.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -271,10 +271,9 @@ char* strlib_strtok_r(char *s1, const char *s2, char **lasts)
size_t strlib_strnlen(const char *string, size_t maxlen)
{
-// TODO: The _MSC_VER check can probably be removed (we no longer support VS
-// versions <= 2003, do we?), but this implementation might be still necessary
-// for NetBSD 5.x and possibly some Solaris versions.
-#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
+// TODO: Verify whether this implementation is still necessary for NetBSD 5.x
+// and possibly some Solaris versions.
+#if !(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)
/* Find the length of STRING, but scan at most MAXLEN characters.
* If no '\0' terminator is found in that many characters, return MAXLEN.
*/
@@ -345,6 +344,7 @@ int strlib_config_switch(const char *str) {
}
/// strncpy that always null-terminates the string
+/// @remark this function will read at most `n` - 1 bytes from `src` (from 0 to `n` - 2)
char *strlib_safestrncpy(char *dst, const char *src, size_t n)
{
if( n > 0 )
@@ -424,13 +424,12 @@ int strlib_strline(const char *str, size_t pos)
/// @param output Output string
/// @param input Binary input buffer
/// @param count Number of bytes to convert
-bool strlib_bin2hex(char *output, unsigned char *input, size_t count)
+bool strlib_bin2hex(char *output, const unsigned char *input, size_t count)
{
char toHex[] = "0123456789abcdef";
size_t i;
- for( i = 0; i < count; ++i )
- {
+ for (i = 0; i < count; ++i) {
*output++ = toHex[(*input & 0xF0) >> 4];
*output++ = toHex[(*input & 0x0F) >> 0];
++input;
@@ -630,6 +629,8 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
svstate.opt = opt;
svstate.delim = delim;
svstate.done = false;
+ svstate.start = 0;
+ svstate.end = 0;
// parse
count = 0;
@@ -773,6 +774,7 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca
case '\v': out_dest[j++] = 'v'; break;
case '\f': out_dest[j++] = 'f'; break;
case '\?': out_dest[j++] = '?'; break;
+ case '\"': out_dest[j++] = '"'; break;
default:// to octal
out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6));
out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3));
@@ -1114,7 +1116,7 @@ void strlib_defaults(void) {
strlib->normalize_name_ = strlib_normalize_name;
strlib->stristr_ = strlib_stristr;
-#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
+#if !(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)
strlib->strnlen_ = strlib_strnlen;
#else
strlib->strnlen_ = NULL;
diff --git a/src/common/strlib.h b/src/common/strlib.h
index c523f5d86..fa7d577eb 100644
--- a/src/common/strlib.h
+++ b/src/common/strlib.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -33,7 +33,7 @@
#define normalize_name(str,delims) (strlib->normalize_name_((str),(delims)))
#define stristr(haystack,needle) (strlib->stristr_((haystack),(needle)))
-#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
+#if !(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)
#define strnlen(string,maxlen) (strlib->strnlen_((string),(maxlen)))
#endif
@@ -98,7 +98,7 @@ struct strlib_interface {
char *(*normalize_name_) (char* str,const char* delims);
const char *(*stristr_) (const char *haystack, const char *needle);
- /* only used when '!(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)', needs to be defined at all times however */
+ /* only used when '!(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)', needs to be defined at all times however */
size_t (*strnlen_) (const char* string, size_t maxlen);
/* only used when 'WIN32' */
@@ -125,7 +125,7 @@ struct strlib_interface {
/// Produces the hexadecimal representation of the given input.
/// The output buffer must be at least count*2+1 in size.
/// Returns true on success, false on failure.
- bool (*bin2hex_) (char* output, unsigned char* input, size_t count);
+ bool (*bin2hex_) (char *output, const unsigned char *input, size_t count);
};
struct stringbuf_interface {
diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c
index 7cc4cd16a..3c7e25a0c 100644
--- a/src/common/sysinfo.c
+++ b/src/common/sysinfo.c
@@ -31,6 +31,7 @@
#include "common/cbasetypes.h"
#include "common/core.h"
#include "common/memmgr.h"
+#include "common/nullpo.h"
#include "common/strlib.h"
#include <stdio.h> // fopen
@@ -38,6 +39,7 @@
#ifdef WIN32
# include <windows.h>
#else
+# include <sys/time.h> // time constants
# include <unistd.h>
#endif
@@ -236,11 +238,13 @@ enum windows_ver_suite {
* @retval true if a revision was correctly detected.
* @retval false if no revision was detected. out is set to NULL in this case.
*/
-bool sysinfo_svn_get_revision(char **out) {
+bool sysinfo_svn_get_revision(char **out)
+{
// Only include SVN support if detected it, or we're on MSVC
#if !defined(SYSINFO_VCSTYPE) || SYSINFO_VCSTYPE == VCSTYPE_SVN || SYSINFO_VCSTYPE == VCSTYPE_UNKNOWN
FILE *fp;
+ nullpo_ret(out);
// subversion 1.7 uses a sqlite3 database
// FIXME this is hackish at best...
// - ignores database file structure
@@ -290,40 +294,8 @@ bool sysinfo_svn_get_revision(char **out) {
if (*out != NULL)
return true;
}
-
- // subversion 1.6 and older?
- if ((fp = fopen(".svn/entries", "r")) != NULL) {
- char line[1024];
- int rev;
- // Check the version
- if (fgets(line, sizeof(line), fp)) {
- if (!ISDIGIT(line[0])) {
- // XML File format
- while (fgets(line,sizeof(line),fp))
- if (strstr(line,"revision=")) break;
- if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) {
- if (*out != NULL)
- aFree(*out);
- *out = aCalloc(1, 8);
- snprintf(*out, 8, "%d", rev);
- }
- } else {
- // Bin File format
- if (fgets(line, sizeof(line), fp) == NULL) { printf("Can't get bin name\n"); } // Get the name
- if (fgets(line, sizeof(line), fp) == NULL) { printf("Can't get entries kind\n"); } // Get the entries kind
- if (fgets(line, sizeof(line), fp)) { // Get the rev numver
- if (*out != NULL)
- aFree(*out);
- *out = aCalloc(1, 8);
- snprintf(*out, 8, "%d", atoi(line));
- }
- }
- }
- fclose(fp);
-
- if (*out != NULL)
- return true;
- }
+#else
+ nullpo_ret(out);
#endif
if (*out != NULL)
aFree(*out);
@@ -338,11 +310,13 @@ bool sysinfo_svn_get_revision(char **out) {
* @retval true if a revision was correctly detected.
* @retval false if no revision was detected. out is set to NULL in this case.
*/
-bool sysinfo_git_get_revision(char **out) {
+bool sysinfo_git_get_revision(char **out)
+{
// Only include Git support if we detected it, or we're on MSVC
#if !defined(SYSINFO_VCSTYPE) || SYSINFO_VCSTYPE == VCSTYPE_GIT || SYSINFO_VCSTYPE == VCSTYPE_UNKNOWN
char ref[128], filepath[128], line[128];
+ nullpo_ret(out);
strcpy(ref, "HEAD");
while (*ref) {
@@ -367,6 +341,7 @@ bool sysinfo_git_get_revision(char **out) {
if (*out != NULL)
return true;
#else
+ nullpo_ret(out);
if (*out != NULL)
aFree(*out);
*out = NULL;
@@ -384,7 +359,8 @@ typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
*
* Once retrieved, the version string is stored into sysinfo->p->osversion.
*/
-void sysinfo_osversion_retrieve(void) {
+void sysinfo_osversion_retrieve(void)
+{
OSVERSIONINFOEX osvi;
StringBuf buf;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -635,7 +611,8 @@ typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
* System info is not stored anywhere after retrieval
* @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx
**/
-void sysinfo_systeminfo_retrieve( LPSYSTEM_INFO info ) {
+void sysinfo_systeminfo_retrieve(LPSYSTEM_INFO info)
+{
PGNSI pGNSI;
// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
@@ -652,7 +629,8 @@ void sysinfo_systeminfo_retrieve( LPSYSTEM_INFO info ) {
* Returns number of bytes in a memory page
* Only needed when compiling with MSVC
**/
-long sysinfo_getpagesize( void ) {
+long sysinfo_getpagesize(void)
+{
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
@@ -666,7 +644,8 @@ long sysinfo_getpagesize( void ) {
* Once retrieved, the name is stored into sysinfo->p->cpu and the
* number of cores in sysinfo->p->cpucores.
*/
-void sysinfo_cpu_retrieve(void) {
+void sysinfo_cpu_retrieve(void)
+{
StringBuf buf;
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
@@ -702,7 +681,8 @@ void sysinfo_cpu_retrieve(void) {
*
* Once retrieved, the name is stored into sysinfo->p->arch.
*/
-void sysinfo_arch_retrieve(void) {
+void sysinfo_arch_retrieve(void)
+{
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
@@ -730,7 +710,8 @@ void sysinfo_arch_retrieve(void) {
*
* Once retrieved, the value is stored in sysinfo->p->vcsrevision_src.
*/
-void sysinfo_vcsrevision_src_retrieve(void) {
+void sysinfo_vcsrevision_src_retrieve(void)
+{
if (sysinfo->p->vcsrevision_src != NULL) {
aFree(sysinfo->p->vcsrevision_src);
sysinfo->p->vcsrevision_src = NULL;
@@ -754,7 +735,8 @@ void sysinfo_vcsrevision_src_retrieve(void) {
*
* Once retrieved, the value is stored in sysinfo->p->vcstype_name.
*/
-void sysinfo_vcstype_name_retrieve(void) {
+void sysinfo_vcstype_name_retrieve(void)
+{
if (sysinfo->p->vcstype_name != NULL) {
aFree(sysinfo->p->vcstype_name);
sysinfo->p->vcstype_name = NULL;
@@ -783,7 +765,8 @@ void sysinfo_vcstype_name_retrieve(void) {
*
* Output example: "Linux", "Darwin", "Windows", etc.
*/
-const char *sysinfo_platform(void) {
+const char *sysinfo_platform(void)
+{
return sysinfo->p->platform;
}
@@ -801,7 +784,8 @@ const char *sysinfo_platform(void) {
* Output example: "Windows 2008 Small Business Server", "OS X 10.8 Mountain Lion",
* "Gentoo Base System Release 2.2", "Debian GNU/Linux 6.0.6 (squeeze)", etc.
*/
-const char *sysinfo_osversion(void) {
+const char *sysinfo_osversion(void)
+{
return sysinfo->p->osversion;
}
@@ -820,7 +804,8 @@ const char *sysinfo_osversion(void) {
* "Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz", "Intel Core i7",
* "x86 CPU, Family 6, Model 54, Stepping 1", etc.
*/
-const char *sysinfo_cpu(void) {
+const char *sysinfo_cpu(void)
+{
return sysinfo->p->cpu;
}
@@ -833,7 +818,8 @@ const char *sysinfo_cpu(void) {
*
* @return the number of CPU cores.
*/
-int sysinfo_cpucores(void) {
+int sysinfo_cpucores(void)
+{
return sysinfo->p->cpucores;
}
@@ -850,7 +836,8 @@ int sysinfo_cpucores(void) {
*
* Output example: "x86", "x86_64", "IA-64", "ARM", etc.
*/
-const char *sysinfo_arch(void) {
+const char *sysinfo_arch(void)
+{
return sysinfo->p->arch;
}
@@ -860,7 +847,8 @@ const char *sysinfo_arch(void) {
* @retval true if this is a 64 bit build.
* @retval false if this isn't a 64 bit build (i.e. it is a 32 bit build).
*/
-bool sysinfo_is64bit(void) {
+bool sysinfo_is64bit(void)
+{
#ifdef _LP64
return true;
#else
@@ -878,7 +866,8 @@ bool sysinfo_is64bit(void) {
* Output example: "Microsoft Visual C++ 2012 (v170050727)",
* "Clang v5.0.0", "MinGW32 v3.20", "GCC v4.7.3", etc.
*/
-const char *sysinfo_compiler(void) {
+const char *sysinfo_compiler(void)
+{
return sysinfo->p->compiler;
}
@@ -893,7 +882,8 @@ const char *sysinfo_compiler(void) {
*
* Output example: "-ggdb -O2 -flto -pipe -ffast-math ..."
*/
-const char *sysinfo_cflags(void) {
+const char *sysinfo_cflags(void)
+{
return sysinfo->p->cflags;
}
@@ -908,7 +898,8 @@ const char *sysinfo_cflags(void) {
*
* @see VCSTYPE_NONE, VCSTYPE_GIT, VCSTYPE_SVN, VCSTYPE_UNKNOWN
*/
-int sysinfo_vcstypeid(void) {
+int sysinfo_vcstypeid(void)
+{
return sysinfo->p->vcstype;
}
@@ -925,7 +916,8 @@ int sysinfo_vcstypeid(void) {
*
* Output example: "Git", "SVN", "Exported"
*/
-const char *sysinfo_vcstype(void) {
+const char *sysinfo_vcstype(void)
+{
return sysinfo->p->vcstype_name;
}
@@ -943,7 +935,8 @@ const char *sysinfo_vcstype(void) {
*
* Output example: Git: "9128feccf3bddda94a7f8a170305565416815b40", SVN: "17546"
*/
-const char *sysinfo_vcsrevision_src(void) {
+const char *sysinfo_vcsrevision_src(void)
+{
return sysinfo->p->vcsrevision_src;
}
@@ -959,7 +952,8 @@ const char *sysinfo_vcsrevision_src(void) {
*
* Output example: Git: "9128feccf3bddda94a7f8a170305565416815b40", SVN: "17546"
*/
-const char *sysinfo_vcsrevision_scripts(void) {
+const char *sysinfo_vcsrevision_scripts(void)
+{
return sysinfo->p->vcsrevision_scripts;
}
@@ -967,7 +961,8 @@ const char *sysinfo_vcsrevision_scripts(void) {
* Reloads the run-time (scripts) VCS revision information. To be used during
* script reloads to refresh the cached version.
*/
-void sysinfo_vcsrevision_reload(void) {
+void sysinfo_vcsrevision_reload(void)
+{
if (sysinfo->p->vcsrevision_scripts != NULL) {
aFree(sysinfo->p->vcsrevision_scripts);
sysinfo->p->vcsrevision_scripts = NULL;
@@ -989,7 +984,8 @@ void sysinfo_vcsrevision_reload(void) {
* @retval false if the current process is running as regular user, or
* in any case under Windows.
*/
-bool sysinfo_is_superuser(void) {
+bool sysinfo_is_superuser(void)
+{
#ifndef _WIN32
if (geteuid() == 0)
return true;
@@ -1000,7 +996,8 @@ bool sysinfo_is_superuser(void) {
/**
* Interface runtime initialization.
*/
-void sysinfo_init(void) {
+void sysinfo_init(void)
+{
sysinfo->p->compiler = SYSINFO_COMPILER;
#ifdef WIN32
sysinfo->p->platform = "Windows";
@@ -1026,7 +1023,8 @@ void sysinfo_init(void) {
/**
* Interface shutdown cleanup.
*/
-void sysinfo_final(void) {
+void sysinfo_final(void)
+{
#ifdef WIN32
// Only need to be free'd in win32, they're #defined elsewhere
if (sysinfo->p->osversion)
@@ -1052,10 +1050,24 @@ void sysinfo_final(void) {
sysinfo->p->vcstype_name = NULL;
}
+static const char *sysinfo_time(void)
+{
+#if defined(WIN32)
+ return "ticks count";
+#elif defined(ENABLE_RDTSC)
+ return "rdtsc";
+#elif defined(HAVE_MONOTONIC_CLOCK)
+ return "monotonic clock";
+#else
+ return "time of day";
+#endif
+}
+
/**
* Interface default values initialization.
*/
-void sysinfo_defaults(void) {
+void sysinfo_defaults(void)
+{
sysinfo = &sysinfo_s;
memset(&sysinfo_p, '\0', sizeof(sysinfo_p));
sysinfo->p = &sysinfo_p;
@@ -1072,6 +1084,7 @@ void sysinfo_defaults(void) {
sysinfo->is64bit = sysinfo_is64bit;
sysinfo->compiler = sysinfo_compiler;
sysinfo->cflags = sysinfo_cflags;
+ sysinfo->time = sysinfo_time;
sysinfo->vcstype = sysinfo_vcstype;
sysinfo->vcstypeid = sysinfo_vcstypeid;
sysinfo->vcsrevision_src = sysinfo_vcsrevision_src;
diff --git a/src/common/sysinfo.h b/src/common/sysinfo.h
index 904be832f..2a391bfa4 100644
--- a/src/common/sysinfo.h
+++ b/src/common/sysinfo.h
@@ -52,6 +52,7 @@ struct sysinfo_interface {
bool (*is64bit) (void);
const char *(*compiler) (void);
const char *(*cflags) (void);
+ const char *(*time) (void);
const char *(*vcstype) (void);
int (*vcstypeid) (void);
const char *(*vcsrevision_src) (void);
diff --git a/src/common/thread.c b/src/common/thread.c
index 6012791e2..aaafab943 100644
--- a/src/common/thread.c
+++ b/src/common/thread.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -20,10 +20,6 @@
*/
#define HERCULES_CORE
-// Basic Threading abstraction (for pthread / win32 based systems)
-//
-// Author: Florian Wilkemeyer <fw@f-ws.de>
-
#include "thread.h"
#include "common/cbasetypes.h"
@@ -48,13 +44,22 @@
#define HAS_TLS
#endif
-#define RA_THREADS_MAX 64
+/** @file
+ * Thread interface implementation.
+ * @author Florian Wilkemeyer <fw@f-ws.de>
+ */
+
+struct thread_interface thread_s;
+struct thread_interface *thread;
-struct rAthread {
+/// The maximum amount of threads.
+#define THREADS_MAX 64
+
+struct thread_handle {
unsigned int myID;
- RATHREAD_PRIO prio;
- rAthreadProc proc;
+ enum thread_priority prio;
+ threadFunc proc;
void *param;
#ifdef WIN32
@@ -68,16 +73,17 @@ struct rAthread {
__thread int g_rathread_ID = -1;
#endif
-///
-/// Subystem Code
-///
-static struct rAthread l_threads[RA_THREADS_MAX];
+// Subystem Code
+
+static struct thread_handle l_threads[THREADS_MAX];
-void rathread_init(void) {
- register unsigned int i;
- memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) );
+/// @copydoc thread_interface::init()
+void thread_init(void)
+{
+ register int i;
+ memset(&l_threads, 0x00, THREADS_MAX * sizeof(struct thread_handle));
- for(i = 0; i < RA_THREADS_MAX; i++){
+ for (i = 0; i < THREADS_MAX; i++) {
l_threads[i].myID = i;
}
@@ -85,46 +91,53 @@ void rathread_init(void) {
#ifdef HAS_TLS
g_rathread_ID = 0;
#endif
- l_threads[0].prio = RAT_PRIO_NORMAL;
- l_threads[0].proc = (rAthreadProc)0xDEADCAFE;
+ l_threads[0].prio = THREADPRIO_NORMAL;
+ l_threads[0].proc = (threadFunc)0xDEADCAFE;
-}//end: rathread_init()
+}
-void rathread_final(void) {
- register unsigned int i;
+/// @copydoc thread_interface::final()
+void thread_final(void)
+{
+ register int i;
// Unterminated Threads Left?
- // Shouldn't happen ..
- // Kill 'em all!
- //
- for(i = 1; i < RA_THREADS_MAX; i++){
- if(l_threads[i].proc != NULL){
- ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
- rathread_destroy(&l_threads[i]);
+ // Shouldn't happen ... Kill 'em all!
+ for (i = 1; i < THREADS_MAX; i++) {
+ if (l_threads[i].proc != NULL){
+ ShowWarning("thread_final: unterminated Thread (tid %d entry_point %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
+ thread->destroy(&l_threads[i]);
}
}
+}
-}//end: rathread_final()
-
-// gets called whenever a thread terminated ..
-static void rat_thread_terminated(rAthread *handle) {
+/**
+ * Gets called whenever a thread terminated.
+ *
+ * @param handle The terminated thread's handle.
+ */
+static void thread_terminated(struct thread_handle *handle)
+{
// Preserve handle->myID and handle->hThread, set everything else to its default value
handle->param = NULL;
handle->proc = NULL;
- handle->prio = RAT_PRIO_NORMAL;
-}//end: rat_thread_terminated()
+ handle->prio = THREADPRIO_NORMAL;
+}
#ifdef WIN32
-DWORD WINAPI raThreadMainRedirector(LPVOID p){
+DWORD WINAPI thread_main_redirector(LPVOID p)
+{
#else
-static void *raThreadMainRedirector( void *p ){
+static void *thread_main_redirector(void *p)
+{
sigset_t set; // on Posix Thread platforms
#endif
void *ret;
+ struct thread_handle *self = p;
// Update myID @ TLS to right id.
#ifdef HAS_TLS
- g_rathread_ID = ((rAthread*)p)->myID;
+ g_rathread_ID = self->myID;
#endif
#ifndef WIN32
@@ -138,66 +151,68 @@ static void *raThreadMainRedirector( void *p ){
(void)sigaddset(&set, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &set, NULL);
-
#endif
- ret = ((rAthread*)p)->proc( ((rAthread*)p)->param ) ;
+ ret = self->proc(self->param);
#ifdef WIN32
- CloseHandle( ((rAthread*)p)->hThread );
+ CloseHandle(self->hThread);
#endif
- rat_thread_terminated( (rAthread*)p );
+ thread_terminated(self);
#ifdef WIN32
return (DWORD)ret;
#else
return ret;
#endif
-}//end: raThreadMainRedirector()
+}
+
+// API Level
-///
-/// API Level
-///
-rAthread *rathread_create(rAthreadProc entryPoint, void *param) {
- return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL );
-}//end: rathread_create()
+/// @copydoc thread_interface::create()
+struct thread_handle *thread_create(threadFunc entry_point, void *param)
+{
+ return thread->create_opt(entry_point, param, (1<<23) /*8MB*/, THREADPRIO_NORMAL);
+}
-rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio) {
+/// @copydoc thread_interface::create_opt()
+struct thread_handle *thread_create_opt(threadFunc entry_point, void *param, size_t stack_size, enum thread_priority prio)
+{
#ifndef WIN32
pthread_attr_t attr;
#endif
size_t tmp;
- unsigned int i;
- rAthread *handle = NULL;
+ int i;
+ struct thread_handle *handle = NULL;
// given stacksize aligned to systems pagesize?
- tmp = szStack % sysinfo->getpagesize();
- if(tmp != 0)
- szStack += tmp;
+ tmp = stack_size % sysinfo->getpagesize();
+ if (tmp != 0)
+ stack_size += tmp;
// Get a free Thread Slot.
- for(i = 0; i < RA_THREADS_MAX; i++){
+ for (i = 0; i < THREADS_MAX; i++) {
if(l_threads[i].proc == NULL){
handle = &l_threads[i];
break;
}
}
- if(handle == NULL){
- ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint);
+ if (handle == NULL) {
+ ShowError("thread_create_opt: cannot create new thread (entry_point: %p) - no free thread slot found!", entry_point);
return NULL;
}
- handle->proc = entryPoint;
+ handle->proc = entry_point;
handle->param = param;
#ifdef WIN32
- handle->hThread = CreateThread(NULL, szStack, raThreadMainRedirector, (void*)handle, 0, NULL);
+ handle->hThread = CreateThread(NULL, stack_size, thread_main_redirector, handle, 0, NULL);
#else
pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, szStack);
+ pthread_attr_setstacksize(&attr, stack_size);
- if(pthread_create(&handle->hThread, &attr, raThreadMainRedirector, (void*)handle) != 0){
+ if (pthread_create(&handle->hThread, &attr, thread_main_redirector, handle) != 0) {
handle->proc = NULL;
handle->param = NULL;
return NULL;
@@ -205,99 +220,122 @@ rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack
pthread_attr_destroy(&attr);
#endif
- rathread_prio_set( handle, prio );
+ thread->prio_set(handle, prio);
return handle;
-}//end: rathread_createEx
+}
-void rathread_destroy(rAthread *handle) {
+/// @copydoc thread_interface::destroy()
+void thread_destroy(struct thread_handle *handle)
+{
#ifdef WIN32
- if( TerminateThread(handle->hThread, 0) != FALSE){
+ if (TerminateThread(handle->hThread, 0) != FALSE) {
CloseHandle(handle->hThread);
- rat_thread_terminated(handle);
+ thread_terminated(handle);
}
#else
- if( pthread_cancel( handle->hThread ) == 0){
+ if (pthread_cancel(handle->hThread) == 0) {
// We have to join it, otherwise pthread wont re-cycle its internal resources assoc. with this thread.
- pthread_join( handle->hThread, NULL );
+ pthread_join(handle->hThread, NULL);
// Tell our manager to release resources ;)
- rat_thread_terminated(handle);
+ thread_terminated(handle);
}
#endif
-}//end: rathread_destroy()
+}
-rAthread *rathread_self(void) {
+struct thread_handle *thread_self(void)
+{
#ifdef HAS_TLS
- rAthread *handle = &l_threads[g_rathread_ID];
+ struct thread_handle *handle = &l_threads[g_rathread_ID];
- if(handle->proc != NULL) // entry point set, so its used!
+ if (handle->proc != NULL) // entry point set, so its used!
return handle;
#else
// .. so no tls means we have to search the thread by its api-handle ..
int i;
- #ifdef WIN32
- HANDLE hSelf;
- hSelf = GetCurrent = GetCurrentThread();
- #else
- pthread_t hSelf;
- hSelf = pthread_self();
- #endif
+#ifdef WIN32
+ HANDLE hSelf;
+ hSelf = GetCurrent = GetCurrentThread();
+#else
+ pthread_t hSelf;
+ hSelf = pthread_self();
+#endif
- for(i = 0; i < RA_THREADS_MAX; i++){
- if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
+ for (i = 0; i < THREADS_MAX; i++) {
+ if (l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
return &l_threads[i];
}
#endif
return NULL;
-}//end: rathread_self()
+}
-int rathread_get_tid(void) {
-
-#ifdef HAS_TLS
+/// @copydoc thread_interface::get_tid()
+int thread_get_tid(void)
+{
+#if defined(HAS_TLS)
return g_rathread_ID;
+#elif defined(WIN32)
+ return (int)GetCurrentThreadId();
#else
- // TODO
- #ifdef WIN32
- return (int)GetCurrentThreadId();
- #else
- return (intptr_t)pthread_self();
- #endif
+ return (int)pthread_self();
#endif
+}
-}//end: rathread_get_tid()
-
-bool rathread_wait(rAthread *handle, void **out_exitCode) {
+/// @copydoc thread_interface::wait()
+bool thread_wait(struct thread_handle *handle, void **out_exit_code)
+{
// Hint:
// no thread data cleanup routine call here!
// its managed by the callProxy itself..
- //
#ifdef WIN32
WaitForSingleObject(handle->hThread, INFINITE);
return true;
#else
- if(pthread_join(handle->hThread, out_exitCode) == 0)
+ if (pthread_join(handle->hThread, out_exit_code) == 0)
return true;
return false;
#endif
-}//end: rathread_wait()
+}
-void rathread_prio_set(rAthread *handle, RATHREAD_PRIO prio) {
- handle->prio = RAT_PRIO_NORMAL;
+/// @copydoc thread_interface::prio_set()
+void thread_prio_set(struct thread_handle *handle, enum thread_priority prio)
+{
+ handle->prio = THREADPRIO_NORMAL;
//@TODO
-}//end: rathread_prio_set()
+}
-RATHREAD_PRIO rathread_prio_get(rAthread *handle) {
+/// @copydoc thread_interface::prio_get()
+enum thread_priority thread_prio_get(struct thread_handle *handle)
+{
return handle->prio;
-}//end: rathread_prio_get()
+}
-void rathread_yield(void) {
+/// @copydoc thread_interface::yield()
+void thread_yield(void) {
#ifdef WIN32
SwitchToThread();
#else
sched_yield();
#endif
-}//end: rathread_yield()
+}
+
+/// Interface base initialization.
+void thread_defaults(void)
+{
+ thread = &thread_s;
+ thread->init = thread_init;
+ thread->final = thread_final;
+ thread->create = thread_create;
+ thread->create_opt = thread_create_opt;
+ thread->destroy = thread_destroy;
+ thread->self = thread_self;
+ thread->get_tid = thread_get_tid;
+ thread->wait = thread_wait;
+ thread->prio_set = thread_prio_set;
+ thread->prio_get = thread_prio_get;
+ thread->yield = thread_yield;
+}
diff --git a/src/common/thread.h b/src/common/thread.h
index 261735306..c668afbb4 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,114 +21,136 @@
#ifndef COMMON_THREAD_H
#define COMMON_THREAD_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
-typedef struct rAthread rAthread;
-typedef void* (*rAthreadProc)(void*);
-
-typedef enum RATHREAD_PRIO {
- RAT_PRIO_LOW = 0,
- RAT_PRIO_NORMAL,
- RAT_PRIO_HIGH
-} RATHREAD_PRIO;
-
-
-#ifdef HERCULES_CORE
-/**
- * Creates a new Thread
- *
- * @param entyPoint - entryProc,
- * @param param - general purpose parameter, would be given as parameter to the thread's entry point.
- *
- * @return not NULL if success
+/** @file
+ * Basic Threading abstraction (for pthread / win32 based systems).
*/
-rAthread *rathread_create(rAthreadProc entryPoint, void *param);
+/* Opaque Types */
+struct thread_handle; ///< Thread handle.
+typedef void *(*threadFunc)(void *); ///< Thread entry point function.
+
+/* Enums */
+
+/// Thread priority
+enum thread_priority {
+ THREADPRIO_LOW = 0,
+ THREADPRIO_NORMAL,
+ THREADPRIO_HIGH
+};
+
+/// The thread interface
+struct thread_interface {
+ /// Interface initialization.
+ void (*init) (void);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Creates a new Thread.
+ *
+ * @param enty_point Thread's entry point.
+ * @param param General purpose parameter, would be given as
+ * parameter to the thread's entry point.
+ *
+ * @return The created thread object.
+ * @retval NULL in vase of failure.
+ */
+ struct thread_handle *(*create) (threadFunc entry_point, void *param);
+
+ /**
+ * Creates a new Thread (with more creation options).
+ *
+ * @param enty_point Thread's entry point.
+ * @param param General purpose parameter, would be given as
+ * parameter to the thread's entry point.
+ * @param stack_size Stack Size in bytes.
+ * @param prio Priority of the Thread in the OS scheduler.
+ *
+ * @return The created thread object.
+ * @retval NULL in case of failure.
+ */
+ struct thread_handle *(*create_opt) (threadFunc entry_point, void *param, size_t stack_size, enum thread_priority prio);
+
+ /**
+ * Destroys the given Thread immediately.
+ *
+ * @remark
+ * The Handle gets invalid after call! don't use it afterwards.
+ *
+ * @param handle The thread to destroy.
+ */
+ void (*destroy) (struct thread_handle *handle);
+
+ /**
+ * Returns the thread handle of the thread calling this function.
+ *
+ * @remark
+ * This won't work in the program's main thread.
+ *
+ * @warning
+ * The underlying implementation might not perform very well, cache
+ * the value received!
+ *
+ * @return the thread handle.
+ * @retval NULL in case of failure.
+ */
+ struct thread_handle *(*self) (void);
+
+ /**
+ * Returns own thread id (TID).
+ *
+ * @remark
+ * This is an unique identifier for the calling thread, and depends
+ * on platform/ compiler, and may not be the systems Thread ID!
+ *
+ * @return the thread ID.
+ * @retval -1 in case of failure.
+ */
+ int (*get_tid) (void);
+
+ /**
+ * Waits for the given thread to terminate.
+ *
+ * @param[in] handle The thread to wait (join) for.
+ * @param[out] out_exit_code Pointer to return the exit code of the
+ * given thread after termination (optional).
+ *
+ * @retval true if the given thread has been terminated.
+ */
+ bool (*wait) (struct thread_handle *handle, void **out_exit_code);
+
+ /**
+ * Sets the given priority in the OS scheduler.
+ *
+ * @param handle The thread to set the priority for.
+ * @param prio The priority to set (@see enum thread_priority).
+ */
+ void (*prio_set) (struct thread_handle *handle, enum thread_priority prio);
+
+ /**
+ * Gets the current priority of the given thread.
+ *
+ * @param handle The thread to get the priority for.
+ */
+ enum thread_priority (*prio_get) (struct thread_handle *handle);
+
+ /**
+ * Tells the OS scheduler to yield the execution of the calling thread.
+ *
+ * @remark
+ * This will not "pause" the thread, it just allows the OS to spend
+ * the remaining time of the slice to another thread.
+ */
+ void (*yield) (void);
+};
-/**
- * Creates a new Thread (with more creation options)
- *
- * @param entyPoint - entryProc,
- * @param param - general purpose parameter, would be given as parameter to the thread's entry point
- * @param szStack - stack Size in bytes
- * @param prio - Priority of the Thread @ OS Scheduler..
- *
- * @return not NULL if success
- */
-rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio);
-
-
-/**
- * Destroys the given Thread immediately
- *
- * @note The Handle gets invalid after call! don't use it afterwards.
- *
- * @param handle - thread to destroy.
- */
-void rathread_destroy(rAthread *handle);
-
-
-/**
- * Returns the thread handle of the thread calling this function
- *
- * @note this wont work @ programs main thread
- * @note the underlying implementation might not perform very well, cache the value received!
- *
- * @return not NULL if success
- */
-rAthread *rathread_self(void);
-
-
-/**
- * Returns own thread id (TID)
- *
- * @note this is an unique identifier for the calling thread, and
- * depends on platform/ compiler, and may not be the systems Thread ID!
- *
- * @return -1 when fails, otherwise >= 0
- */
-int rathread_get_tid(void);
-
-
-/**
- * Waits for the given thread to terminate
- *
- * @param handle - thread to wait (join) for
- * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated
- *
- * @return true - if the given thread has been terminated.
- */
-bool rathread_wait(rAthread *handle, void **out_exitCode);
-
-
-/**
- * Sets the given PRIORITY @ OS Task Scheduler
- *
- * @param handle - thread to set prio for
- * @param rio - the priority (RAT_PRIO_LOW ... )
- */
-void rathread_prio_set(rAthread *handle, RATHREAD_PRIO prio);
-
-
-/**
- * Gets the current Prio of the given thread
- *
- * @param handle - the thread to get the prio for.
- */
-RATHREAD_PRIO rathread_prio_get(rAthread *handle);
-
-
-/**
- * Tells the OS scheduler to yield the execution of the calling thread
- *
- * @note: this will not "pause" the thread,
- * it just allows the OS to spend the remaining time
- * of the slice to another thread.
- */
-void rathread_yield(void);
-
-void rathread_init(void);
-void rathread_final(void);
+#ifdef HERCULES_CORE
+void thread_defaults(void);
#endif // HERCULES_CORE
+HPShared struct thread_interface *thread; ///< Pointer to the thread interface.
+
#endif /* COMMON_THREAD_H */
diff --git a/src/common/timer.c b/src/common/timer.c
index 7f71157ae..4f2b86a32 100644
--- a/src/common/timer.c
+++ b/src/common/timer.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "common/cbasetypes.h"
#include "common/db.h"
#include "common/memmgr.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/utils.h"
@@ -50,7 +51,7 @@ struct timer_interface *timer;
// timers (array)
static struct TimerData* timer_data = NULL;
static int timer_data_max = 0;
-static int timer_data_num = 0;
+static int timer_data_num = 1;
// free timers (array)
static int* free_timer_list = NULL;
@@ -87,6 +88,8 @@ struct timer_func_list {
int timer_add_func_list(TimerFunc func, char* name) {
struct timer_func_list* tfl;
+ nullpo_ret(func);
+ nullpo_ret(name);
if (name) {
for( tfl=tfl_root; tfl != NULL; tfl=tfl->next )
{// check suspicious cases
@@ -255,10 +258,6 @@ 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);
}
@@ -303,7 +302,19 @@ static int acquire_timer(void) {
int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) {
int tid;
+ nullpo_retr(INVALID_TIMER, func);
+
tid = acquire_timer();
+ if (timer_data[tid].type != 0 && timer_data[tid].type != TIMER_REMOVE_HEAP)
+ {
+ ShowError("timer_add error: wrong tid type: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(INVALID_TIMER, 0);
+ }
+ if (timer_data[tid].func != NULL)
+ {
+ ShowError("timer_add error: func non NULL: [%d]%p(%s) -> %p(%s)\n", tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(INVALID_TIMER, 0);
+ }
timer_data[tid].tick = tick;
timer_data[tid].func = func;
timer_data[tid].id = id;
@@ -317,9 +328,11 @@ int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) {
/// Starts a new timer that automatically restarts itself (infinite loop until manually removed).
/// Returns the timer's id, or INVALID_TIMER if it fails.
-int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval) {
+int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval)
+{
int tid;
+ nullpo_retr(INVALID_TIMER, func);
if (interval < 1) {
ShowError("timer_add_interval: invalid interval (tick=%"PRId64" %p[%s] id=%d data=%"PRIdPTR" diff_tick=%"PRId64")\n",
tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, timer->gettick()));
@@ -327,6 +340,18 @@ int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int in
}
tid = acquire_timer();
+ if (timer_data[tid].type != 0 && timer_data[tid].type != TIMER_REMOVE_HEAP)
+ {
+ ShowError("timer_add_interval: wrong tid type: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(INVALID_TIMER, 0);
+ return INVALID_TIMER;
+ }
+ if (timer_data[tid].func != NULL)
+ {
+ ShowError("timer_add_interval: func non NULL: [%d]%p(%s) -> %p(%s)\n", tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(INVALID_TIMER, 0);
+ return INVALID_TIMER;
+ }
timer_data[tid].tick = tick;
timer_data[tid].func = func;
timer_data[tid].id = id;
@@ -340,22 +365,35 @@ int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int in
/// Retrieves internal timer data
const struct TimerData* timer_get(int tid) {
+ Assert_retr(NULL, tid > 0);
return ( tid >= 0 && tid < timer_data_num ) ? &timer_data[tid] : NULL;
}
/// Marks a timer specified by 'id' for immediate deletion once it expires.
/// Param 'func' is used for debug/verification purposes.
/// Returns 0 on success, < 0 on failure.
-int timer_do_delete(int tid, TimerFunc func) {
- if( tid < 0 || tid >= timer_data_num ) {
- ShowError("timer_do_delete error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func));
+int timer_do_delete(int tid, TimerFunc func)
+{
+ nullpo_ret(func);
+
+ if (tid < 1 || tid >= timer_data_num) {
+ ShowError("timer_do_delete error : no such timer [%d](%p(%s))\n", tid, func, search_timer_func_list(func));
+ Assert_retr(-1, 0);
return -1;
}
if( timer_data[tid].func != func ) {
- ShowError("timer_do_delete error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func));
+ ShowError("timer_do_delete error : function mismatch [%d]%p(%s) != %p(%s)\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func));
+ Assert_retr(-2, 0);
return -2;
}
+ if (timer_data[tid].type == 0 || timer_data[tid].type == TIMER_REMOVE_HEAP)
+ {
+ ShowError("timer_do_delete: timer already deleted: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), func, search_timer_func_list(func));
+ Assert_retr(-3, 0);
+ return -3;
+ }
+
timer_data[tid].func = NULL;
timer_data[tid].type = TIMER_ONCE_AUTODEL;
@@ -365,6 +403,11 @@ int timer_do_delete(int tid, TimerFunc func) {
/// Adjusts a timer's expiration time.
/// Returns the new tick value, or -1 if it fails.
int64 timer_addtick(int tid, int64 tick) {
+ if (tid < 1 || tid >= timer_data_num) {
+ ShowError("timer_addtick error : no such timer [%d]\n", tid);
+ Assert_retr(-1, 0);
+ return -1;
+ }
return timer->settick(tid, timer_data[tid].tick+tick);
}
@@ -383,7 +426,19 @@ int64 timer_settick(int tid, int64 tick)
// search timer position
ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid);
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));
+ ShowError("timer_settick: no such timer [%d](%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(-1, 0);
+ return -1;
+ }
+
+ if (timer_data[tid].type == 0 || timer_data[tid].type == TIMER_REMOVE_HEAP) {
+ ShowError("timer_settick error: set tick for deleted timer %d, [%d](%p(%s))\n", timer_data[tid].type, tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(-1, 0);
+ return -1;
+ }
+ if (timer_data[tid].func == NULL) {
+ ShowError("timer_settick error: set tick for timer with wrong func [%d](%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
+ Assert_retr(-1, 0);
return -1;
}
@@ -438,6 +493,7 @@ int do_timer(int64 tick)
default:
case TIMER_ONCE_AUTODEL:
timer_data[tid].type = 0;
+ timer_data[tid].func = NULL;
if (free_timer_list_pos >= free_timer_list_max) {
free_timer_list_max += 256;
RECREATE(free_timer_list,int,free_timer_list_max);
diff --git a/src/common/timer.h b/src/common/timer.h
index 2161f5e31..88c891dff 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/common/utils.c b/src/common/utils.c
index 73df3aae1..bcfc153e3 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -54,6 +54,9 @@ void WriteDump(FILE* fp, const void* buffer, size_t length)
size_t i;
char hex[48+1], ascii[16+1];
+ nullpo_retv(fp);
+ nullpo_retv(buffer);
+
fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n");
ascii[16] = 0;
@@ -78,10 +81,12 @@ void WriteDump(FILE* fp, const void* buffer, size_t length)
}
/// Dumps given buffer on the console.
-void ShowDump(const void *buffer, size_t length) {
+void ShowDump(const void *buffer, size_t length)
+{
size_t i;
char hex[48+1], ascii[16+1];
+ nullpo_retv(buffer);
ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n");
ascii[16] = 0;
@@ -108,6 +113,7 @@ static char* checkpath(char *path, const char *srcpath)
{
// just make sure the char*path is not const
char *p = path;
+
if (NULL == path || NULL == srcpath)
return path;
while(*srcpath) {
@@ -400,7 +406,9 @@ int apply_percentrate(int value, int rate, int maxrate)
//-----------------------------------------------------
const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
{
- size_t len = strftime(str, size, format, localtime(&timestamp));
+ size_t len;
+ nullpo_retr(NULL, str);
+ len = strftime(str, size, format, localtime(&timestamp));
memset(str + len, '\0', size - len);
return str;
}
@@ -413,6 +421,7 @@ bool HCache_check(const char *file)
char s_path[255], dT[1];
time_t rtime;
+ nullpo_retr(false, file);
if (!(first = fopen(file,"rb")))
return false;
@@ -456,10 +465,14 @@ bool HCache_check(const char *file)
return true;
}
-FILE *HCache_open(const char *file, const char *opt) {
+FILE *HCache_open(const char *file, const char *opt)
+{
FILE *first;
char s_path[255];
+ nullpo_retr(NULL, file);
+ nullpo_retr(NULL, opt);
+
if( file[0] == '.' && file[1] == '/' )
file += 2;
else if( file[0] == '.' )
@@ -498,15 +511,19 @@ void HCache_init(void)
}
/* transit to fread, shields vs warn_unused_result */
-size_t hread(void * ptr, size_t size, size_t count, FILE * stream) {
+size_t hread(void *ptr, size_t size, size_t count, FILE *stream)
+{
return fread(ptr, size, count, stream);
}
+
/* transit to fwrite, shields vs warn_unused_result */
-size_t hwrite(const void * ptr, size_t size, size_t count, FILE * stream) {
+size_t hwrite(const void *ptr, size_t size, size_t count, FILE *stream)
+{
return fwrite(ptr, size, count, stream);
}
-void HCache_defaults(void) {
+void HCache_defaults(void)
+{
HCache = &HCache_s;
HCache->init = HCache_init;
diff --git a/src/common/utils.h b/src/common/utils.h
index 3f181ef12..9d3c323ef 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -24,6 +24,9 @@
#include "common/hercules.h"
#include <stdio.h> // FILE*
+#ifndef WIN32
+# include <unistd.h> // sleep()
+#endif
/* [HCache] 1-byte key to ensure our method is the latest, we can modify to ensure the method matches */
#define HCACHE_KEY 'k'
diff --git a/src/common/winapi.h b/src/common/winapi.h
index 724f052a0..b410e00cd 100644
--- a/src/common/winapi.h
+++ b/src/common/winapi.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify