diff options
Diffstat (limited to 'src/common')
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(×tamp)); + size_t len; + nullpo_retr(NULL, str); + len = strftime(str, size, format, localtime(×tamp)); 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 |