diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/common/HPM.c | 362 | ||||
-rw-r--r-- | src/common/HPM.h | 83 | ||||
-rw-r--r-- | src/common/HPMi.h | 70 | ||||
-rw-r--r-- | src/common/Makefile.in | 5 | ||||
-rw-r--r-- | src/common/console.c | 409 | ||||
-rw-r--r-- | src/common/console.h | 71 | ||||
-rw-r--r-- | src/common/core.c | 260 | ||||
-rw-r--r-- | src/common/core.h | 38 | ||||
-rw-r--r-- | src/common/db.c | 2019 | ||||
-rw-r--r-- | src/common/db.h | 123 | ||||
-rw-r--r-- | src/common/ers.c | 20 | ||||
-rw-r--r-- | src/common/grfio.c | 29 | ||||
-rw-r--r-- | src/common/malloc.c | 162 | ||||
-rw-r--r-- | src/common/malloc.h | 72 | ||||
-rw-r--r-- | src/common/mapindex.c | 72 | ||||
-rw-r--r-- | src/common/mapindex.h | 16 | ||||
-rw-r--r-- | src/common/mmo.h | 35 | ||||
-rw-r--r-- | src/common/netbuffer.c | 8 | ||||
-rw-r--r-- | src/common/raconf.c | 6 | ||||
-rw-r--r-- | src/common/showmsg.c | 35 | ||||
-rw-r--r-- | src/common/showmsg.h | 32 | ||||
-rw-r--r-- | src/common/socket.c | 80 | ||||
-rw-r--r-- | src/common/socket.h | 3 | ||||
-rw-r--r-- | src/common/sql.c | 261 | ||||
-rw-r--r-- | src/common/sql.h | 244 | ||||
-rw-r--r-- | src/common/strlib.c | 362 | ||||
-rw-r--r-- | src/common/strlib.h | 244 | ||||
-rw-r--r-- | src/common/timer.c | 135 | ||||
-rw-r--r-- | src/common/timer.h | 34 |
30 files changed, 3282 insertions, 2015 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e8c6c0a70..dbc30734c 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -36,6 +36,7 @@ set( COMMON_ALL_HEADERS set( COMMON_MINI_HEADERS ${COMMON_ALL_HEADERS} "${COMMON_SOURCE_DIR}/core.h" + "${COMMON_SOURCE_DIR}/console.h" "${COMMON_SOURCE_DIR}/malloc.h" "${COMMON_SOURCE_DIR}/showmsg.h" "${COMMON_SOURCE_DIR}/strlib.h" @@ -43,6 +44,7 @@ set( COMMON_MINI_HEADERS CACHE INTERNAL "" ) set( COMMON_MINI_SOURCES "${COMMON_SOURCE_DIR}/core.c" + "${COMMON_SOURCE_DIR}/console.c" "${COMMON_SOURCE_DIR}/malloc.c" "${COMMON_SOURCE_DIR}/showmsg.c" "${COMMON_SOURCE_DIR}/strlib.c" @@ -61,10 +63,13 @@ set( COMMON_BASE_HEADERS ${COMMON_ALL_HEADERS} "${COMMON_SOURCE_DIR}/conf.h" "${COMMON_SOURCE_DIR}/core.h" + "${COMMON_SOURCE_DIR}/console.h" "${COMMON_SOURCE_DIR}/db.h" "${COMMON_SOURCE_DIR}/des.h" "${COMMON_SOURCE_DIR}/ers.h" "${COMMON_SOURCE_DIR}/grfio.h" + "${COMMON_SOURCE_DIR}/HPM.h" + "${COMMON_SOURCE_DIR}/HPMi.h" "${COMMON_SOURCE_DIR}/malloc.h" "${COMMON_SOURCE_DIR}/mapindex.h" "${COMMON_SOURCE_DIR}/md5calc.h" @@ -86,10 +91,12 @@ set( COMMON_BASE_HEADERS set( COMMON_BASE_SOURCES "${COMMON_SOURCE_DIR}/conf.c" "${COMMON_SOURCE_DIR}/core.c" + "${COMMON_SOURCE_DIR}/console.c" "${COMMON_SOURCE_DIR}/db.c" "${COMMON_SOURCE_DIR}/des.c" "${COMMON_SOURCE_DIR}/ers.c" "${COMMON_SOURCE_DIR}/grfio.c" + "${COMMON_SOURCE_DIR}/HPM.c" "${COMMON_SOURCE_DIR}/malloc.c" "${COMMON_SOURCE_DIR}/mapindex.c" "${COMMON_SOURCE_DIR}/md5calc.c" diff --git a/src/common/HPM.c b/src/common/HPM.c new file mode 100644 index 000000000..28ea8f413 --- /dev/null +++ b/src/common/HPM.c @@ -0,0 +1,362 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/core.h" +#include "../common/malloc.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/timer.h" +#include "../common/conf.h" +#include "../common/utils.h" +#include "../common/console.h" +#include "../common/strlib.h" +#include "../common/sql.h" +#include "HPM.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef WIN32 +#include <unistd.h> +#endif + +void hplugin_trigger_event(enum hp_event_types type) { + unsigned int i; + for( i = 0; i < HPM->plugin_count; i++ ) { + if( HPM->plugins[i]->hpi->event[type] != NULL ) + (HPM->plugins[i]->hpi->event[type])(); + } +} + +void hplugin_export_symbol(void *var, char *name) { + RECREATE(HPM->symbols, struct hpm_symbol *, ++HPM->symbol_count); + CREATE(HPM->symbols[HPM->symbol_count - 1] ,struct hpm_symbol, 1); + HPM->symbols[HPM->symbol_count - 1]->name = name; + HPM->symbols[HPM->symbol_count - 1]->ptr = var; +} + +void *hplugin_import_symbol(char *name) { + unsigned int i; + + for( i = 0; i < HPM->symbol_count; i++ ) { + if( strcmp(HPM->symbols[i]->name,name) == 0 ) + return HPM->symbols[i]->ptr; + } + + ShowError("HPM:get_symbol: '"CL_WHITE"%s"CL_RESET"' not found!\n",name); + return NULL; +} + +bool hplugin_iscompatible(char* version) { + unsigned int req_major = 0, req_minor = 0; + + if( version == NULL ) + return false; + + sscanf(version, "%u.%u", &req_major, &req_minor); + + return ( req_major == HPM->version[0] && req_minor <= HPM->version[1] ) ? true : false; +} + +bool hplugin_exists(const char *filename) { + unsigned int i; + for(i = 0; i < HPM->plugin_count; i++) { + if( strcmpi(HPM->plugins[i]->filename,filename) == 0 ) + return true; + } + return false; +} +struct hplugin *hplugin_create(void) { + RECREATE(HPM->plugins, struct hplugin *, ++HPM->plugin_count); + CREATE(HPM->plugins[HPM->plugin_count - 1], struct hplugin, 1); + HPM->plugins[HPM->plugin_count - 1]->idx = HPM->plugin_count - 1; + HPM->plugins[HPM->plugin_count - 1]->filename = NULL; + return HPM->plugins[HPM->plugin_count - 1]; +} +#define HPM_POP(x) { #x , x } +bool hplugin_populate(struct hplugin *plugin, const char *filename) { + void **Link; + struct { + const char* name; + void *Ref; + } ToLink[] = { + HPM_POP(ShowMessage), + HPM_POP(ShowStatus), + HPM_POP(ShowSQL), + HPM_POP(ShowInfo), + HPM_POP(ShowNotice), + HPM_POP(ShowWarning), + HPM_POP(ShowDebug), + HPM_POP(ShowError), + HPM_POP(ShowFatalError), + }; + int i, length = ARRAYLENGTH(ToLink); + + for(i = 0; i < length; i++) { + if( !( Link = plugin_import(plugin->dll, ToLink[i].name,void **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve '%s' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", ToLink[i].name, filename); + HPM->unload(plugin); + return false; + } + *Link = ToLink[i].Ref; + } + + return true; +} +void hplugin_load(const char* filename) { + struct hplugin *plugin; + struct hplugin_info *info; + struct HPMi_interface **HPMi; + bool anyEvent = false; + void **import_symbol_ref; + Sql **sql_handle; + + if( HPM->exists(filename) ) { + ShowWarning("HPM:plugin_load: attempting to load duplicate '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + return; + } + + plugin = HPM->create(); + + if( !( plugin->dll = plugin_open(filename) ) ){ + ShowWarning("HPM:plugin_load: failed to load '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !( info = plugin_import(plugin->dll, "pinfo",struct hplugin_info*) ) ) { + ShowDebug("HPM:plugin_load: failed to retrieve 'plugin_info' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !(info->type & SERVER_TYPE) ) { + HPM->unload(plugin); + return; + } + + if( !HPM->iscompatible(info->req_version) ) { + ShowWarning("HPM:plugin_load: '"CL_WHITE"%s"CL_RESET"' incompatible version '%s' -> '%s', skipping...\n", filename, info->req_version, HPM_VERSION); + HPM->unload(plugin); + return; + } + + if( !( import_symbol_ref = plugin_import(plugin->dll, "import_symbol",void **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'import_symbol' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + *import_symbol_ref = HPM->import_symbol; + + if( !( sql_handle = plugin_import(plugin->dll, "mysql_handle",Sql **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'mysql_handle' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + *sql_handle = HPM->import_symbol("sql_handle"); + + if( !( HPMi = plugin_import(plugin->dll, "HPMi",struct HPMi_interface **) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'HPMi' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !( *HPMi = plugin_import(plugin->dll, "HPMi_s",struct HPMi_interface *) ) ) { + ShowWarning("HPM:plugin_load: failed to retrieve 'HPMi_s' for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + plugin->hpi = *HPMi; + + if( ( plugin->hpi->event[HPET_INIT] = plugin_import(plugin->dll, "plugin_init",void (*)(void)) ) ) + anyEvent = true; + + if( ( plugin->hpi->event[HPET_FINAL] = plugin_import(plugin->dll, "plugin_final",void (*)(void)) ) ) + anyEvent = true; + + if( ( plugin->hpi->event[HPET_READY] = plugin_import(plugin->dll, "server_online",void (*)(void)) ) ) + anyEvent = true; + + if( !anyEvent ) { + ShowWarning("HPM:plugin_load: no events found for '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename); + HPM->unload(plugin); + return; + } + + if( !HPM->populate(plugin,filename) ) + return; + + if( SERVER_TYPE == SERVER_TYPE_MAP ) { + plugin->hpi->addCommand = HPM->import_symbol("addCommand"); + plugin->hpi->addScript = HPM->import_symbol("addScript"); + plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand"); + } + + plugin->info = info; + plugin->filename = aStrdup(filename); + + return; +} + +void hplugin_unload(struct hplugin* plugin) { + unsigned int i = plugin->idx, cursor = 0; + + if( plugin->filename ) + aFree(plugin->filename); + if( plugin->dll ) + plugin_close(plugin->dll); + + aFree(plugin); + if( !HPM->off ) { + HPM->plugins[i] = NULL; + for(i = 0; i < HPM->plugin_count; i++) { + if( HPM->plugins[i] == NULL ) + continue; + if( cursor != i ) + HPM->plugins[cursor] = HPM->plugins[i]; + cursor++; + } + if( !(HPM->plugin_count = cursor) ) { + aFree(HPM->plugins); + HPM->plugins = NULL; + } + } +} + +void hplugins_config_read(void) { + config_t plugins_conf; + config_setting_t *plist = NULL; + const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name + + if (conf_read_file(&plugins_conf, config_filename)) + return; + + if( HPM->symbol_defaults_sub ) + HPM->symbol_defaults_sub(); + + plist = config_lookup(&plugins_conf, "plugins_list"); + + if (plist != NULL) { + int length = config_setting_length(plist), i; + char filename[60]; + for(i = 0; i < length; i++) { + snprintf(filename, 60, "plugins/%s%s", config_setting_get_string_elem(plist,i), DLL_EXT); + HPM->load(filename); + } + config_destroy(&plugins_conf); + } + + if( HPM->plugin_count ) + ShowStatus("HPM: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded, type '"CL_WHITE"plugins"CL_RESET"' to list them\n", HPM->plugin_count); +} +void hplugins_share_defaults(void) { + /* console */ + HPM->share(console->addCommand,"addCPCommand"); + /* core */ + HPM->share(&runflag,"runflag"); + HPM->share(arg_v,"arg_v"); + HPM->share(&arg_c,"arg_c"); + HPM->share(SERVER_NAME,"SERVER_NAME"); + HPM->share(&SERVER_TYPE,"SERVER_TYPE"); + HPM->share((void*)get_svn_revision,"get_svn_revision"); + HPM->share((void*)get_git_hash,"get_git_hash"); + HPM->share(DB, "DB"); + HPM->share(malloclib, "malloclib"); + /* socket */ + HPM->share(RFIFOSKIP,"RFIFOSKIP"); + HPM->share(WFIFOSET,"WFIFOSET"); + HPM->share(do_close,"do_close"); + HPM->share(make_connection,"make_connection"); + HPM->share(session,"session"); + HPM->share(&fd_max,"fd_max"); + HPM->share(addr_,"addr"); + /* strlib */ + HPM->share(strlib,"strlib"); + HPM->share(sv,"sv"); + HPM->share(StrBuf,"StrBuf"); + /* sql */ + HPM->share(SQL,"SQL"); + /* timer */ + HPM->share(gettick,"gettick"); + HPM->share(add_timer,"add_timer"); + HPM->share(add_timer_interval,"add_timer_interval"); + HPM->share(add_timer_func_list,"add_timer_func_list"); + HPM->share(delete_timer,"delete_timer"); + HPM->share(get_uptime,"get_uptime"); +} +CPCMD(plugins) { + if( HPM->plugin_count == 0 ) { + ShowInfo("HPC: there are no plugins loaded\n"); + } else { + unsigned int i; + + ShowInfo("HPC: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded\n",HPM->plugin_count); + + for(i = 0; i < HPM->plugin_count; i++) { + ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n",HPM->plugins[i]->info->name,HPM->plugins[i]->filename); + } + } +} +void hpm_init(void) { + HPM->symbols = NULL; + HPM->plugins = NULL; + HPM->plugin_count = HPM->symbol_count = 0; + HPM->off = false; + + sscanf(HPM_VERSION, "%d.%d", &HPM->version[0], &HPM->version[1]); + + if( HPM->version[0] == 0 && HPM->version[1] == 0 ) { + ShowError("HPM:init:failed to retrieve HPM version!!\n"); + return; + } + HPM->symbol_defaults(); + + console->addCommand("plugins",CPCMD_A(plugins)); + + return; +} + +void hpm_final(void) { + unsigned int i; + + HPM->off = true; + + for( i = 0; i < HPM->plugin_count; i++ ) { + HPM->unload(HPM->plugins[i]); + } + + if( HPM->plugins ) + aFree(HPM->plugins); + + for( i = 0; i < HPM->symbol_count; i++ ) { + aFree(HPM->symbols[i]); + } + + if( HPM->symbols ) + aFree(HPM->symbols); + + return; +} +void hpm_defaults(void) { + HPM = &HPM_s; + + HPM->init = hpm_init; + HPM->final = hpm_final; + + HPM->create = hplugin_create; + HPM->load = hplugin_load; + HPM->unload = hplugin_unload; + HPM->event = hplugin_trigger_event; + HPM->exists = hplugin_exists; + HPM->iscompatible = hplugin_iscompatible; + HPM->import_symbol = hplugin_import_symbol; + HPM->share = hplugin_export_symbol; + HPM->symbol_defaults = hplugins_share_defaults; + HPM->config_read = hplugins_config_read; + HPM->populate = hplugin_populate; + HPM->symbol_defaults_sub = NULL; +} diff --git a/src/common/HPM.h b/src/common/HPM.h new file mode 100644 index 000000000..10b1f0e79 --- /dev/null +++ b/src/common/HPM.h @@ -0,0 +1,83 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef _HPM_H_ +#define _HPM_H_ + +#include "../common/cbasetypes.h" +#include "../common/HPMi.h" + +#ifdef WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include <windows.h> + #define plugin_open(x) LoadLibraryA(x) + #define plugin_import(x,y,z) (z)GetProcAddress(x,y) + #define plugin_close(x) FreeLibrary(x) + + #define DLL_EXT ".dll" + #define DLL HINSTANCE +#else + #include <dlfcn.h> + #define plugin_open(x) dlopen(x,RTLD_NOW) + #define plugin_import(x,y,z) (z)dlsym(x,y) + #define plugin_close(x) dlclose(x) + + #ifdef CYGWIN + #define DLL_EXT ".dll" + #else + #define DLL_EXT ".so" + #endif + + #define DLL void * + + #include <string.h> // size_t + +#endif + +struct hplugin { + DLL dll; + unsigned int idx; + char *filename; + struct hplugin_info *info; + struct HPMi_interface *hpi; +}; + +struct hpm_symbol { + char *name; + void *ptr; +}; + +/* Hercules Plugin Manager Interface */ +struct HPM_interface { + /* vars */ + unsigned int version[2]; + bool off; + /* data */ + struct hplugin **plugins; + unsigned int plugin_count; + struct hpm_symbol **symbols; + unsigned int symbol_count; + /* funcs */ + void (*init) (void); + void (*final) (void); + struct hplugin * (*create) (void); + void (*load) (const char* filename); + void (*unload) (struct hplugin* plugin); + bool (*exists) (const char *filename); + bool (*iscompatible) (char* version); + void (*event) (enum hp_event_types type); + void *(*import_symbol) (char *); + void (*share) (void *, char *); + void (*symbol_defaults) (void); + void (*config_read) (void); + bool (*populate) (struct hplugin *plugin,const char *filename); + void (*symbol_defaults_sub) (void); +} HPM_s; + +struct HPM_interface *HPM; + +void hpm_defaults(void); + +#endif /* _HPM_H_ */ diff --git a/src/common/HPMi.h b/src/common/HPMi.h new file mode 100644 index 000000000..3cdb804e0 --- /dev/null +++ b/src/common/HPMi.h @@ -0,0 +1,70 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef _HPMi_H_ +#define _HPMi_H_ + +#include "../common/cbasetypes.h" +#include "../common/core.h" +#include "../common/console.h" +#include "../common/sql.h" + +struct script_state; +struct AtCommandInfo; + +#ifdef WIN32 + #define HPExport __declspec(dllexport) +#else + #define HPExport +#endif + +#ifndef _SHOWMSG_H_ + HPExport void (*ShowMessage) (const char *, ...); + HPExport void (*ShowStatus) (const char *, ...); + HPExport void (*ShowSQL) (const char *, ...); + HPExport void (*ShowInfo) (const char *, ...); + HPExport void (*ShowNotice) (const char *, ...); + HPExport void (*ShowWarning) (const char *, ...); + HPExport void (*ShowDebug) (const char *, ...); + HPExport void (*ShowError) (const char *, ...); + HPExport void (*ShowFatalError) (const char *, ...); +#endif + +/* after */ +#include "../common/showmsg.h" + +#define HPM_VERSION "0.1" + +struct hplugin_info { + char* name; + enum server_types type; + char* version; + char* req_version; +}; + +HPExport void *(*import_symbol) (char *name); +HPExport Sql *mysql_handle; + +#define GET_SYMBOL(n) import_symbol(n) + +#define SERVER_TYPE_ALL SERVER_TYPE_LOGIN|SERVER_TYPE_CHAR|SERVER_TYPE_MAP + +enum hp_event_types { + HPET_INIT,/* server starts */ + HPET_FINAL,/* server is shutting down */ + HPET_READY,/* server is ready (online) */ + HPET_MAX, +}; + +/* Hercules Plugin Mananger Include Interface */ +HPExport struct HPMi_interface { + void (*event[HPET_MAX]) (void); + bool (*addCommand) (char *name, bool (*func)(const int fd, struct map_session_data* sd, const char* command, const char* message,struct AtCommandInfo *info)); + bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st)); + void (*addCPCommand) (char *name, CParseFunc func); +} HPMi_s; +#ifndef _HPM_H_ + HPExport struct HPMi_interface *HPMi; +#endif + +#endif /* _HPMi_H_ */ diff --git a/src/common/Makefile.in b/src/common/Makefile.in index c24499c02..279f82e5f 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -1,9 +1,10 @@ -COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o \ +COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/HPM.o \ obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \ - obj_all/conf.o obj_all/thread.o obj_all/mutex.o obj_all/raconf.o obj_all/mempool.o + obj_all/conf.o obj_all/thread.o obj_all/mutex.o obj_all/raconf.o obj_all/mempool.o obj_all/console.o \ + obj_all/miniconsole.o COMMON_H = $(shell ls ../common/*.h) diff --git a/src/common/console.c b/src/common/console.c new file mode 100644 index 000000000..ba93b8e09 --- /dev/null +++ b/src/common/console.c @@ -0,0 +1,409 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams + +#include "../common/showmsg.h" +#include "../common/core.h" +#include "../config/core.h" +#include "console.h" + +#ifndef MINICORE + #include "../common/ers.h" + #include "../common/malloc.h" + #include "../common/atomic.h" + #include "../common/spinlock.h" + #include "../common/thread.h" + #include "../common/mutex.h" + #include "../common/timer.h" + #include "../common/strlib.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#ifndef _WIN32 + #include <unistd.h> +#else + #include "../common/winapi.h" // Console close event handling +#endif + +#ifdef CONSOLE_INPUT + #ifdef _WIN32 + #include <conio.h> /* _kbhit() */ + #endif +#endif + +struct console_interface console_s; + +/*====================================== + * CORE : Display title + *--------------------------------------*/ +void display_title(void) { + const char* svn = get_svn_revision(); + const char* git = get_git_hash(); + + ShowMessage("\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" Hercules Development Team presents "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" _ _ _ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | | | | | | "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | |_| | ___ _ __ ___ _ _| | ___ ___ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | _ |/ _ \\ '__/ __| | | | |/ _ \\/ __|"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" | | | | __/ | | (__| |_| | | __/\\__ \\"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" \\_| |_/\\___|_| \\___|\\__,_|_|\\___||___/"CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" http://hercules.ws/board/ "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_BG_RED" "CL_BT_WHITE" "CL_BG_RED""CL_CLL""CL_NORMAL"\n"); + + if( git[0] != HERC_UNKNOWN_VER ) + ShowInfo("Git Hash: '"CL_WHITE"%s"CL_RESET"'\n", git); + else if( svn[0] != HERC_UNKNOWN_VER ) + ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'\n", svn); +} +#ifdef CONSOLE_INPUT +#ifdef _WIN32 +int console_parse_key_pressed(void) { + return _kbhit(); +} +#else /* _WIN32 */ +int console_parse_key_pressed(void) { + struct timeval tv; + fd_set fds; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); + + return FD_ISSET(STDIN_FILENO, &fds); +} +#endif /* _WIN32 */ +CPCMD(exit) { + runflag = 0; +} +CPCMD(ers_report) { + ers_report(); +} +CPCMD(help) { + unsigned int i = 0; + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( console->cmd_list[i]->next_count ) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",console->cmd_list[i]->cmd); + console->parse_list_subs(console->cmd_list[i],2); + } else { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"'\n",console->cmd_list[i]->cmd); + } + } +} +/* [Ind/Hercules] */ +CPCMD(malloc_usage) { + unsigned int val = (unsigned int)malloclib->usage(); + ShowInfo("malloc_usage: %.2f MB\n",(double)(val)/1024); +} +#define CP_DEF_C(x) { #x , NULL , NULL, NULL } +#define CP_DEF_C2(x,y) { #x , NULL , #y, NULL } +#define CP_DEF_S(x,y) { #x , console_parse_ ## x , #y, NULL } +#define CP_DEF(x) { #x , console_parse_ ## x , NULL, NULL } +void console_load_defaults(void) { + struct { + char *name; + CParseFunc func; + char *connect; + struct CParseEntry *self; + } default_list[] = { + CP_DEF(help), + CP_DEF_C(server), + CP_DEF_S(ers_report,server), + CP_DEF_S(malloc_usage,server), + CP_DEF_S(exit,server), + }; + unsigned int i, len = ARRAYLENGTH(default_list); + struct CParseEntry *cmd; + + RECREATE(console->cmds,struct CParseEntry *, len); + + for(i = 0; i < len; i++) { + CREATE(cmd, struct CParseEntry, 1); + + safestrncpy(cmd->cmd, default_list[i].name, CP_CMD_LENGTH); + + if( default_list[i].func ) + cmd->u.func = default_list[i].func; + else + cmd->u.next = NULL; + + cmd->next_count = 0; + + console->cmd_count++; + console->cmds[i] = cmd; + default_list[i].self = cmd; + if( !default_list[i].connect ) { + RECREATE(console->cmd_list,struct CParseEntry *, ++console->cmd_list_count); + console->cmd_list[console->cmd_list_count - 1] = cmd; + } + } + + for(i = 0; i < len; i++) { + unsigned int k; + if( !default_list[i].connect ) + continue; + for(k = 0; k < console->cmd_count; k++) { + if( strcmpi(default_list[i].connect,console->cmds[k]->cmd) == 0 ) { + cmd = default_list[i].self; + RECREATE(console->cmds[k]->u.next, struct CParseEntry *, ++console->cmds[k]->next_count); + console->cmds[k]->u.next[console->cmds[k]->next_count - 1] = cmd; + break; + } + } + } +} +void console_parse_create(char *name, CParseFunc func) { + unsigned int i; + char *tok; + char sublist[CP_CMD_LENGTH * 5]; + struct CParseEntry *cmd; + + safestrncpy(sublist, name, CP_CMD_LENGTH * 5); + tok = strtok(sublist,":"); + + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 ) + break; + } + + if( i == console->cmd_list_count ) { + RECREATE(console->cmds,struct CParseEntry *, ++console->cmd_count); + CREATE(cmd, struct CParseEntry, 1); + safestrncpy(cmd->cmd, tok, CP_CMD_LENGTH); + cmd->next_count = 0; + console->cmds[console->cmd_count - 1] = cmd; + RECREATE(console->cmd_list,struct CParseEntry *, ++console->cmd_list_count); + console->cmd_list[console->cmd_list_count - 1] = cmd; + i = console->cmd_list_count - 1; + } + + cmd = console->cmd_list[i]; + while( ( tok = strtok(NULL, ":") ) != NULL ) { + + for(i = 0; i < cmd->next_count; i++) { + if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) + break; + } + + if ( i == cmd->next_count ) { + RECREATE(console->cmds,struct CParseEntry *, ++console->cmd_count); + CREATE(console->cmds[console->cmd_count-1], struct CParseEntry, 1); + safestrncpy(console->cmds[console->cmd_count-1]->cmd, tok, CP_CMD_LENGTH); + console->cmds[console->cmd_count-1]->next_count = 0; + RECREATE(cmd->u.next, struct CParseEntry *, ++cmd->next_count); + cmd->u.next[cmd->next_count - 1] = console->cmds[console->cmd_count-1]; + cmd = console->cmds[console->cmd_count-1]; + continue; + } + + } + cmd->u.func = func; +} +void console_parse_list_subs(struct CParseEntry *cmd, unsigned char depth) { + unsigned int i; + char msg[CP_CMD_LENGTH * 2]; + for( i = 0; i < cmd->next_count; i++ ) { + if( cmd->u.next[i]->next_count ) { + memset(msg, '-', depth); + snprintf(msg + depth,CP_CMD_LENGTH * 2, " '"CL_WHITE"%s"CL_RESET"'",cmd->u.next[i]->cmd); + ShowInfo("%s subs\n",msg); + console->parse_list_subs(cmd->u.next[i],depth + 1); + } else { + memset(msg, '-', depth); + snprintf(msg + depth,CP_CMD_LENGTH * 2, " %s",cmd->u.next[i]->cmd); + ShowInfo("%s\n",msg); + } + } +} +void console_parse_sub(char *line) { + struct CParseEntry *cmd; + char bline[200]; + char *tok; + char sublist[CP_CMD_LENGTH * 5]; + unsigned int i, len = 0; + memcpy(bline, line, 200); + tok = strtok(line, " "); + for ( i = 0; i < console->cmd_list_count; i++ ) { + if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 ) + break; + } + + if( i == console->cmd_list_count ) { + ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known command, type '"CL_WHITE"help"CL_RESET"' to list all commands\n",line); + return; + } + + cmd = console->cmd_list[i]; + + len += snprintf(sublist,CP_CMD_LENGTH * 5,"%s", cmd->cmd) + 1; + + if( cmd->next_count == 0 && console->cmd_list[i]->u.func ) { + char *r = NULL; + if( (tok = strtok(NULL, " ")) ) { + r = bline; + r += len + 1; + } + cmd->u.func(r); + } else { + while( ( tok = strtok(NULL, " ") ) != NULL ) { + for( i = 0; i < cmd->next_count; i++ ) { + if( strcmpi(cmd->u.next[i]->cmd,tok) == 0 ) + break; + } + if( i == cmd->next_count ) { + if( strcmpi("help",tok) == 0 ) { + if( cmd->next_count ) { + ShowInfo("- '"CL_WHITE"%s"CL_RESET"' subs\n",sublist); + console->parse_list_subs(cmd,2); + } else { + ShowError("'"CL_WHITE"%s"CL_RESET"' doesn't possess any subcommands\n",sublist); + } + return; + } + ShowError("'"CL_WHITE"%s"CL_RESET"' is not a known subcommand of '"CL_WHITE"%s"CL_RESET"'\n",tok,cmd->cmd); + ShowError("type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + return; + } + if( cmd->u.next[i]->next_count == 0 && cmd->u.next[i]->u.func ) { + char *r = NULL; + if( (tok = strtok(NULL, " ")) ) { + r = bline; + r += len + strlen(cmd->u.next[i]->cmd) + 1; + } + cmd->u.next[i]->u.func(r); + return; + } else + cmd = cmd->u.next[i]; + len += snprintf(sublist + len,CP_CMD_LENGTH * 5,":%s", cmd->cmd); + } + ShowError("it is only a category, type '"CL_WHITE"%s help"CL_RESET"' to list its subcommands\n",sublist); + } +} +void console_parse(char* line) { + int c, i = 0, len = MAX_CONSOLE_INPUT - 1;/* we leave room for the \0 :P */ + + while( (c = fgetc(stdin)) != EOF ) { + if( --len == 0 ) + break; + if( (line[i++] = c) == '\n') { + line[i-1] = '\0';/* clear, we skip the new line */ + break;/* new line~! we leave it for the next cycle */ + } + } + + line[i++] = '\0'; +} +void *cThread_main(void *x) { + + while( console->ptstate ) {/* loopx */ + if( console->key_pressed() ) { + char input[MAX_CONSOLE_INPUT]; + + console->parse(input); + if( input[0] != '\0' ) {/* did we get something? */ + EnterSpinLock(&console->ptlock); + + if( cinput.count == CONSOLE_PARSE_SIZE ) { + LeaveSpinLock(&console->ptlock); + continue;/* drop */ + } + + safestrncpy(cinput.queue[cinput.count++],input,MAX_CONSOLE_INPUT); + LeaveSpinLock(&console->ptlock); + } + } + ramutex_lock( console->ptmutex ); + racond_wait( console->ptcond, console->ptmutex, -1 ); + ramutex_unlock( console->ptmutex ); + } + + return NULL; +} +int console_parse_timer(int tid, unsigned int tick, int id, intptr_t data) { + int i; + EnterSpinLock(&console->ptlock); + for(i = 0; i < cinput.count; i++) { + console->parse_sub(cinput.queue[i]); + } + cinput.count = 0; + LeaveSpinLock(&console->ptlock); + racond_signal(console->ptcond); + return 0; +} +void console_parse_final(void) { + if( console->ptstate ) { + InterlockedDecrement(&console->ptstate); + racond_signal(console->ptcond); + + /* wait for thread to close */ + rathread_wait(console->pthread, NULL); + + racond_destroy(console->ptcond); + ramutex_destroy(console->ptmutex); + } +} +void console_parse_init(void) { + cinput.count = 0; + + console->ptstate = 1; + + InitializeSpinLock(&console->ptlock); + + console->ptmutex = ramutex_create(); + console->ptcond = racond_create(); + + if( (console->pthread = rathread_create(console->pthread_main, NULL)) == NULL ){ + ShowFatalError("console_parse_init: failed to spawn console_parse thread.\n"); + exit(EXIT_FAILURE); + } + + add_timer_func_list(console->parse_timer, "console_parse_timer"); + add_timer_interval(gettick() + 1000, console->parse_timer, 0, 0, 500);/* start listening in 1s; re-try every 0.5s */ + +} +#endif /* CONSOLE_INPUT */ + +void console_init (void) { +#ifdef CONSOLE_INPUT + console->cmd_count = console->cmd_list_count = 0; + console->load_defaults(); + console->parse_init(); +#endif +} +void console_final(void) { +#ifdef CONSOLE_INPUT + unsigned int i; + console->parse_final(); + for( i = 0; i < console->cmd_count; i++ ) { + if( console->cmds[i]->next_count ) + aFree(console->cmds[i]->u.next); + aFree(console->cmds[i]); + } + aFree(console->cmds); + aFree(console->cmd_list); +#endif +} +void console_defaults(void) { + console = &console_s; + console->init = console_init; + console->final = console_final; + console->display_title = display_title; +#ifdef CONSOLE_INPUT + console->parse_init = console_parse_init; + console->parse_final = console_parse_final; + console->parse_timer = console_parse_timer; + console->pthread_main = cThread_main; + console->parse = console_parse; + console->parse_sub = console_parse_sub; + console->key_pressed = console_parse_key_pressed; + console->load_defaults = console_load_defaults; + console->parse_list_subs = console_parse_list_subs; + console->addCommand = console_parse_create; +#endif +} diff --git a/src/common/console.h b/src/common/console.h new file mode 100644 index 000000000..ebce013f7 --- /dev/null +++ b/src/common/console.h @@ -0,0 +1,71 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ + +#include "../common/thread.h" +#include "../common/mutex.h" +#include "../common/spinlock.h" +#include "../config/core.h" + +/** + * Queue Max + * why is there a limit, why not make it dynamic? - I'm playing it safe, I'd rather not play with memory management between threads + **/ +#define CONSOLE_PARSE_SIZE 10 + +typedef void (*CParseFunc)(char *line); +#define CPCMD(x) void console_parse_ ##x (char *line) +#define CPCMD_A(x) console_parse_ ##x + +#define CP_CMD_LENGTH 20 +struct CParseEntry { + char cmd[CP_CMD_LENGTH]; + union { + CParseFunc func; + struct CParseEntry **next; + } u; + unsigned short next_count; +}; + +struct { + char queue[CONSOLE_PARSE_SIZE][MAX_CONSOLE_INPUT]; + unsigned short count; +} cinput; + +struct console_interface { + void (*init) (void); + void (*final) (void); + void (*display_title) (void); +#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 CParseEntry **cmd_list; + struct CParseEntry **cmds; + unsigned int cmd_count; + unsigned int cmd_list_count; + /* */ + void (*parse_init) (void); + void (*parse_final) (void); + int (*parse_timer) (int tid, unsigned int tick, int id, intptr_t data); + void *(*pthread_main) (void *x); + void (*parse) (char* line); + void (*parse_sub) (char* line); + int (*key_pressed) (void); + void (*load_defaults) (void); + void (*parse_list_subs) (struct CParseEntry *cmd, unsigned char depth); + void (*addCommand) (char *name, CParseFunc func); +#endif +}; + +struct console_interface *console; + +void console_defaults(void); + +#endif /* _CONSOLE_H_ */ diff --git a/src/common/core.c b/src/common/core.c index e1f99885b..0959e6fc9 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -1,16 +1,23 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/mmo.h" #include "../common/showmsg.h" #include "../common/malloc.h" +#include "../common/strlib.h" #include "core.h" +#include "../common/console.h" + #ifndef MINICORE -#include "../common/db.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/thread.h" -#include "../common/mempool.h" + #include "../common/db.h" + #include "../common/socket.h" + #include "../common/timer.h" + #include "../common/thread.h" + #include "../common/mempool.h" + #include "../common/sql.h" + #include "../config/core.h" + #include "../common/HPM.h" #endif #include <stdio.h> @@ -23,20 +30,14 @@ #include "../common/winapi.h" // Console close event handling #endif - /// Called when a terminate signal is received. void (*shutdown_callback)(void) = NULL; -#if defined(BUILDBOT) - int buildbotflag = 0; -#endif - int runflag = CORE_ST_RUN; int arg_c = 0; char **arg_v = NULL; char *SERVER_NAME = NULL; -char SERVER_TYPE = ATHENA_SERVER_NONE; #ifndef MINICORE // minimalist Core // Added by Gabuzomeu @@ -52,8 +53,7 @@ char SERVER_TYPE = ATHENA_SERVER_NONE; #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; @@ -74,26 +74,23 @@ sigfunc *compat_signal(int signo, sigfunc *func) * CORE : Console events for Windows *--------------------------------------*/ #ifdef _WIN32 -static BOOL WINAPI console_handler(DWORD c_event) -{ - switch(c_event) - { - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - default: - return FALSE; +static BOOL WINAPI console_handler(DWORD c_event) { + switch(c_event) { + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if( shutdown_callback != NULL ) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + default: + return FALSE; } return TRUE; } -static void cevents_init() -{ +static void cevents_init() { if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) ShowWarning ("Unable to install the console handler!\n"); } @@ -102,42 +99,40 @@ static void cevents_init() /*====================================== * CORE : Signal Sub Function *--------------------------------------*/ -static void sig_proc(int sn) -{ +static void sig_proc(int sn) { static int is_called = 0; switch (sn) { - case SIGINT: - case SIGTERM: - if (++is_called > 3) - exit(EXIT_SUCCESS); - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - case SIGSEGV: - case SIGFPE: - do_abort(); - // Pass the signal to the system's default handler - compat_signal(sn, SIG_DFL); - raise(sn); - break; -#ifndef _WIN32 - case SIGXFSZ: - // ignore and allow it to set errno to EFBIG - ShowWarning ("Max file size reached!\n"); - //run_flag = 0; // should we quit? - break; - case SIGPIPE: - //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c - break; // does nothing here -#endif + case SIGINT: + case SIGTERM: + if (++is_called > 3) + exit(EXIT_SUCCESS); + if( shutdown_callback != NULL ) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + case SIGSEGV: + case SIGFPE: + do_abort(); + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); + break; + #ifndef _WIN32 + case SIGXFSZ: + // ignore and allow it to set errno to EFBIG + ShowWarning ("Max file size reached!\n"); + //run_flag = 0; // should we quit? + break; + case SIGPIPE: + //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c + break; // does nothing here + #endif } } -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 @@ -155,13 +150,11 @@ void signals_init (void) #endif #ifdef SVNVERSION - const char *get_svn_revision(void) - { - return EXPAND_AND_QUOTE(SVNVERSION); - } +const char *get_svn_revision(void) { + return EXPAND_AND_QUOTE(SVNVERSION); +} #else// not SVNVERSION -const char* get_svn_revision(void) -{ +const char* get_svn_revision(void) { static char svn_version_buffer[16] = ""; FILE *fp; @@ -196,12 +189,10 @@ const char* get_svn_revision(void) fclose(fp); // parse buffer - for( i = prefix_len + 1; i + postfix_len <= len; ++i ) - { + for( i = prefix_len + 1; i + postfix_len <= len; ++i ) { if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 ) continue; // postfix missmatch - for( j = i; j > 0; --j ) - {// skip digits + for( j = i; j > 0; --j ) {// skip digits if( !ISDIGIT(buffer[j - 1]) ) break; } @@ -218,29 +209,23 @@ const char* get_svn_revision(void) } // subversion 1.6 and older? - if ((fp = fopen(".svn/entries", "r")) != NULL) - { + 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])) - { + 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) { snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); } - } - else - { + } 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(fgets(line, sizeof(line), fp)) { // Get the rev numver snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); } } @@ -252,86 +237,109 @@ const char* get_svn_revision(void) } // fallback - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); + svn_version_buffer[0] = HERC_UNKNOWN_VER; return svn_version_buffer; } #endif - -/*====================================== - * CORE : Display title - * ASCII By CalciumKid 1/12/2011 - *--------------------------------------*/ -static void display_title(void) { - //ClearScreen(); // clear screen and go up/left (0, 0 position in text) - - ShowMessage("\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - - ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); +/* whats our origin */ +#define GIT_ORIGIN "refs/remotes/origin/master" +/* Grabs the hash from the last time the user updated his working copy (last pull) */ +const char *get_git_hash (void) { + static char HerculesGitHash[41] = "";//Sha(40) + 1 + FILE *fp; + + if( HerculesGitHash[0] != '\0' ) + return HerculesGitHash; + + if ( (fp = fopen (".git/"GIT_ORIGIN, "r")) != NULL) { + char line[64]; + char *rev = malloc (sizeof (char) * 50); + + if (fgets (line, sizeof (line), fp) && sscanf (line, "%50s", rev)) + snprintf (HerculesGitHash, sizeof (HerculesGitHash), "%s", rev); + + free (rev); + fclose (fp); + } else { + HerculesGitHash[0] = HERC_UNKNOWN_VER; + } + + if (! (*HerculesGitHash)) { + HerculesGitHash[0] = HERC_UNKNOWN_VER; + } + + return HerculesGitHash; } - // Warning if executed as superuser (root) -void usercheck(void) -{ +void usercheck(void) { #ifndef _WIN32 if (geteuid() == 0) { - ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n"); + ShowWarning ("You are running Hercules with root privileges, it is not necessary.\n"); } #endif } - +void core_defaults(void) { +#ifndef MINICORE + hpm_defaults(); +#endif + console_defaults(); + strlib_defaults(); + malloc_defaults(); +#ifndef MINICORE + sql_defaults(); + timer_defaults(); + db_defaults(); +#endif +} /*====================================== * CORE : MAINROUTINE *--------------------------------------*/ -int main (int argc, char **argv) -{ +int main (int argc, char **argv) { {// initialize program arguments char *p1 = SERVER_NAME = argv[0]; char *p2 = p1; - while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) - { + while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) { SERVER_NAME = ++p1; p2 = p1; } arg_c = argc; arg_v = argv; } - - malloc_init();// needed for Show* in display_title() [FlavioJS] - + core_defaults(); + + malloclib->init();// needed for Show* in display_title() [FlavioJS] + + console->display_title(); + #ifdef MINICORE // minimalist Core - display_title(); usercheck(); do_init(argc,argv); do_final(); #else// not MINICORE set_server_type(); - display_title(); usercheck(); + Sql_Init(); rathread_init(); mempool_init(); - db_init(); + DB->init(); signals_init(); - + #ifdef _WIN32 cevents_init(); #endif timer_init(); + + console->init(); + +#ifndef MINICORE + HPM->init(); +#endif + socket_init(); do_init(argc,argv); - {// Main runtime cycle int next; while (runflag != CORE_ST_STOP) { @@ -340,16 +348,20 @@ int main (int argc, char **argv) } } + console->final(); + do_final(); - +#ifndef MINICORE + HPM->final(); +#endif timer_final(); socket_final(); - db_final(); + DB->final(); mempool_final(); rathread_final(); #endif - malloc_final(); + malloclib->final(); return 0; } diff --git a/src/common/core.h b/src/common/core.h index d48962c94..8fdcdcfc3 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -1,40 +1,46 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _CORE_H_ #define _CORE_H_ +#include "../common/db.h" +#include "../common/mmo.h" +#include "../config/core.h" + +/* so that developers with --enable-debug can raise signals from any section of the code they'd like */ +#ifdef DEBUG + #include <signal.h> +#endif + extern int arg_c; extern char **arg_v; -#if defined(BUILDBOT) - extern int buildbotflag; -#endif +#define HERC_UNKNOWN_VER '\x02' /// @see E_CORE_ST extern int runflag; extern char *SERVER_NAME; -enum { - ATHENA_SERVER_NONE = 0, // not defined - ATHENA_SERVER_LOGIN = 1, // login server - ATHENA_SERVER_CHAR = 2, // char server - ATHENA_SERVER_INTER = 4, // inter server - ATHENA_SERVER_MAP = 8, // map server +enum server_types { + SERVER_TYPE_UNKNOWN = 0x0, + SERVER_TYPE_LOGIN = 0x1, + SERVER_TYPE_CHAR = 0x2, + SERVER_TYPE_MAP = 0x4, }; -extern char SERVER_TYPE; +enum server_types SERVER_TYPE; -extern int parse_console(const char* buf); -extern const char *get_svn_revision(void); +const char *get_svn_revision(void); +const char *get_git_hash (void); extern int do_init(int,char**); extern void set_server_type(void); extern void do_abort(void); extern void do_final(void); /// The main loop continues until runflag is CORE_ST_STOP -enum E_CORE_ST -{ +enum E_CORE_ST { CORE_ST_STOP = 0, CORE_ST_RUN, CORE_ST_LAST diff --git a/src/common/db.c b/src/common/db.c index 204c6d2ea..579697a99 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -1,69 +1,70 @@ /*****************************************************************************\ - * Copyright (c) Athena Dev Teams - Licensed under GNU GPL - * For more information, see LICENCE in the main folder - * - * This file is separated in five sections: - * (1) Private typedefs, enums, structures, defines and gblobal variables - * (2) Private functions - * (3) Protected functions used internally - * (4) Protected functions used in the interface of the database - * (5) Public functions - * - * The databases are structured as a hashtable of RED-BLACK trees. - * - * <B>Properties of the RED-BLACK trees being used:</B> - * 1. The value of any node is greater than the value of its left child and - * less than the value of its right child. - * 2. Every node is colored either RED or BLACK. - * 3. Every red node that is not a leaf has only black children. - * 4. Every path from the root to a leaf contains the same number of black - * nodes. - * 5. The root node is black. - * An <code>n</code> node in a RED-BLACK tree has the property that its - * height is <code>O(lg(n))</code>. - * Another important property is that after adding a node to a RED-BLACK - * tree, the tree can be readjusted in <code>O(lg(n))</code> time. - * Similarly, after deleting a node from a RED-BLACK tree, the tree can be - * readjusted in <code>O(lg(n))</code> time. - * {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/} - * - * <B>How to add new database types:</B> - * 1. Add the identifier of the new database type to the enum DBType - * 2. If not already there, add the data type of the key to the union DBKey - * 3. If the key can be considered NULL, update the function db_is_key_null - * 4. If the key can be duplicated, update the functions db_dup_key and - * db_dup_key_free - * 5. Create a comparator and update the function db_default_cmp - * 6. Create a hasher and update the function db_default_hash - * 7. If the new database type requires or does not support some options, - * update the function db_fix_options - * - * TODO: - * - create test cases to test the database system thoroughly - * - finish this header describing the database system - * - create custom database allocator - * - make the system thread friendly - * - change the structure of the database to T-Trees - * - create a db that organizes itself by splaying - * - * HISTORY: - * 2012/03/09 - Added enum for data types (int, uint, void*) - * 2008/02/19 - Fixed db_obj_get not handling deleted entries correctly. - * 2007/11/09 - Added an iterator to the database. - * 2006/12/21 - Added 1-node cache to the database. - * 2.1 (Athena build #???#) - Portability fix - * - Fixed the portability of casting to union and added the functions - * ensure and clear to the database. - * 2.0 (Athena build 4859) - Transition version - * - Almost everything recoded with a strategy similar to objects, - * database structure is maintained. - * 1.0 (up to Athena build 4706) - * - Previous database system. - * - * @version 2006/12/21 - * @author Athena Dev team - * @encoding US-ASCII - * @see #db.h +* Copyright (c) Athena Dev Teams - Licensed under GNU GPL +* For more information, see LICENCE in the main folder +* +* This file is separated in five sections: +* (1) Private typedefs, enums, structures, defines and gblobal variables +* (2) Private functions +* (3) Protected functions used internally +* (4) Protected functions used in the interface of the database +* (5) Public functions +* +* The databases are structured as a hashtable of RED-BLACK trees. +* +* <B>Properties of the RED-BLACK trees being used:</B> +* 1. The value of any node is greater than the value of its left child and +* less than the value of its right child. +* 2. Every node is colored either RED or BLACK. +* 3. Every red node that is not a leaf has only black children. +* 4. Every path from the root to a leaf contains the same number of black +* nodes. +* 5. The root node is black. +* An <code>n</code> node in a RED-BLACK tree has the property that its +* height is <code>O(lg(n))</code>. +* Another important property is that after adding a node to a RED-BLACK +* tree, the tree can be readjusted in <code>O(lg(n))</code> time. +* Similarly, after deleting a node from a RED-BLACK tree, the tree can be +* readjusted in <code>O(lg(n))</code> time. +* {@link http://www.cs.mcgill.ca/~cs251/OldCourses/1997/topic18/} +* +* <B>How to add new database types:</B> +* 1. Add the identifier of the new database type to the enum DBType +* 2. If not already there, add the data type of the key to the union DBKey +* 3. If the key can be considered NULL, update the function db_is_key_null +* 4. If the key can be duplicated, update the functions db_dup_key and +* db_dup_key_free +* 5. Create a comparator and update the function db_default_cmp +* 6. Create a hasher and update the function db_default_hash +* 7. If the new database type requires or does not support some options, +* update the function db_fix_options +* +* TODO: +* - create test cases to test the database system thoroughly +* - finish this header describing the database system +* - create custom database allocator +* - make the system thread friendly +* - change the structure of the database to T-Trees +* - create a db that organizes itself by splaying +* +* HISTORY: +* 2013/04/27 - Added ERS to speed up iterator memory allocation [Ind/Hercules] +* 2012/03/09 - Added enum for data types (int, uint, void*) +* 2008/02/19 - Fixed db_obj_get not handling deleted entries correctly. +* 2007/11/09 - Added an iterator to the database. +* 2006/12/21 - Added 1-node cache to the database. +* 2.1 (Athena build #???#) - Portability fix +* - Fixed the portability of casting to union and added the functions +* ensure and clear to the database. +* 2.0 (Athena build 4859) - Transition version +* - Almost everything recoded with a strategy similar to objects, +* database structure is maintained. +* 1.0 (up to Athena build 4706) +* - Previous database system. +* +* @version 2006/12/21 +* @author Athena Dev team +* @encoding US-ASCII +* @see #db.h \*****************************************************************************/ #include <stdio.h> #include <stdlib.h> @@ -76,58 +77,58 @@ #include "../common/strlib.h" /*****************************************************************************\ - * (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 - Struture of the database. * - * stats - Statistics about the database system. * +* (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 - Struture of the database. * +* stats - Statistics about the database system. * \*****************************************************************************/ /** - * If defined statistics about database nodes, database creating/destruction - * and function usage are keept and displayed when finalizing the database - * system. - * WARNING: This adds overhead to every database operation (not shure how much). - * @private - * @see #DBStats - * @see #stats - * @see #db_final(void) - */ +* If defined statistics about database nodes, database creating/destruction +* and function usage are keept and displayed when finalizing the database +* system. +* WARNING: This adds overhead to every database operation (not shure how much). +* @private +* @see #DBStats +* @see #stats +* @see #db_final(void) +*/ //#define DB_ENABLE_STATS /** - * Size of the hashtable in the database. - * @private - * @see DBMap_impl#ht - */ +* Size of the hashtable in the database. +* @private +* @see DBMap_impl#ht +*/ #define HASH_SIZE (256+27) /** - * The color of individual nodes. - * @private - * @see struct dbn - */ +* The color of individual nodes. +* @private +* @see struct dbn +*/ typedef enum node_color { RED, BLACK } node_color; /** - * A node in a RED-BLACK tree of the database. - * @param parent Parent node - * @param left Left child node - * @param right Right child node - * @param key Key of this database entry - * @param data Data of this database entry - * @param deleted If the node is deleted - * @param color Color of the node - * @private - * @see DBMap_impl#ht - */ +* A node in a RED-BLACK tree of the database. +* @param parent Parent node +* @param left Left child node +* @param right Right child node +* @param key Key of this database entry +* @param data Data of this database entry +* @param deleted If the node is deleted +* @param color Color of the node +* @private +* @see DBMap_impl#ht +*/ typedef struct dbn { // Tree structure struct dbn *parent; @@ -142,39 +143,39 @@ typedef struct dbn { } *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 - */ +* 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 +*/ struct db_free { DBNode node; DBNode *root; }; /** - * Complete database structure. - * @param vtable Interface of the database - * @param alloc_file File where the database was allocated - * @param alloc_line Line in the file where the database was allocated - * @param free_list Array of deleted nodes to be freed - * @param free_count Number of deleted nodes in free_list - * @param free_max Current maximum capacity of free_list - * @param free_lock Lock for freeing the nodes - * @param nodes Manager of reusable tree nodes - * @param cmp Comparator of the database - * @param hash Hasher of the database - * @param release Releaser of the database - * @param ht Hashtable of RED-BLACK trees - * @param type Type of the database - * @param options Options of the database - * @param item_count Number of items in the database - * @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) - */ +* Complete database structure. +* @param vtable Interface of the database +* @param alloc_file File where the database was allocated +* @param alloc_line Line in the file where the database was allocated +* @param free_list Array of deleted nodes to be freed +* @param free_count Number of deleted nodes in free_list +* @param free_max Current maximum capacity of free_list +* @param free_lock Lock for freeing the nodes +* @param nodes Manager of reusable tree nodes +* @param cmp Comparator of the database +* @param hash Hasher of the database +* @param release Releaser of the database +* @param ht Hashtable of RED-BLACK trees +* @param type Type of the database +* @param options Options of the database +* @param item_count Number of items in the database +* @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) +*/ typedef struct DBMap_impl { // Database interface struct DBMap vtable; @@ -201,16 +202,16 @@ typedef struct DBMap_impl { } DBMap_impl; /** - * Complete iterator structure. - * @param vtable Interface of the iterator - * @param db Parent database - * @param ht_index Current index of the hashtable - * @param node Current node - * @private - * @see #DBIterator - * @see #DBMap_impl - * @see #DBNode - */ +* Complete iterator structure. +* @param vtable Interface of the iterator +* @param db Parent database +* @param ht_index Current index of the hashtable +* @param node Current node +* @private +* @see #DBIterator +* @see #DBMap_impl +* @see #DBNode +*/ typedef struct DBIterator_impl { // Iterator interface struct DBIterator vtable; @@ -221,11 +222,11 @@ typedef struct DBIterator_impl { #if defined(DB_ENABLE_STATS) /** - * Structure with what is counted when the database statistics are enabled. - * @private - * @see #DB_ENABLE_STATS - * @see #stats - */ +* Structure with what is counted when the database statistics are enabled. +* @private +* @see #DB_ENABLE_STATS +* @see #stats +*/ static struct db_stats { // Node alloc/free uint32 db_node_alloc; @@ -319,31 +320,35 @@ static struct db_stats { #define DB_COUNTSTAT(token) #endif /* !defined(DB_ENABLE_STATS) */ +/* [Ind/Hercules] */ +struct eri *db_iterator_ers; +struct eri *db_alloc_ers; + /*****************************************************************************\ - * (2) Section of private functions used by the database system. * - * db_rotate_left - Rotate a tree node to the left. * - * db_rotate_right - Rotate a tree node to the right. * - * db_rebalance - Rebalance the tree. * - * db_rebalance_erase - Rebalance the tree after a BLACK node was erased. * - * db_is_key_null - Returns not 0 if the key is considered NULL. * - * db_dup_key - Duplicate a key for internal use. * - * db_dup_key_free - Free the duplicated key. * - * db_free_add - Add a node to the free_list of a database. * - * db_free_remove - Remove a node from the free_list of a database. * - * db_free_lock - Increment the free_lock of a database. * - * db_free_unlock - Decrement the free_lock of a database. * - * If it was the last lock, frees the nodes in free_list. * - * NOTE: Keeps the database trees balanced. * +* (2) Section of private functions used by the database system. * +* db_rotate_left - Rotate a tree node to the left. * +* db_rotate_right - Rotate a tree node to the right. * +* db_rebalance - Rebalance the tree. * +* db_rebalance_erase - Rebalance the tree after a BLACK node was erased. * +* db_is_key_null - Returns not 0 if the key is considered NULL. * +* db_dup_key - Duplicate a key for internal use. * +* db_dup_key_free - Free the duplicated key. * +* db_free_add - Add a node to the free_list of a database. * +* db_free_remove - Remove a node from the free_list of a database. * +* db_free_lock - Increment the free_lock of a database. * +* db_free_unlock - Decrement the free_lock of a database. * +* If it was the last lock, frees the nodes in free_list. * +* NOTE: Keeps the database trees balanced. * \*****************************************************************************/ /** - * Rotate a node to the left. - * @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 *) - */ +* Rotate a node to the left. +* @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 *) +*/ static void db_rotate_left(DBNode node, DBNode *root) { DBNode y = node->right; @@ -368,13 +373,13 @@ static void db_rotate_left(DBNode node, DBNode *root) } /** - * Rotate a node to the right - * @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 *) - */ +* Rotate a node to the right +* @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 *) +*/ static void db_rotate_right(DBNode node, DBNode *root) { DBNode y = node->left; @@ -399,15 +404,15 @@ static void db_rotate_right(DBNode node, DBNode *root) } /** - * Rebalance the RED-BLACK tree. - * Called when the node and it's parent are both RED. - * @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) - */ +* Rebalance the RED-BLACK tree. +* Called when the node and it's parent are both RED. +* @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) +*/ static void db_rebalance(DBNode node, DBNode *root) { DBNode y; @@ -462,14 +467,14 @@ static void db_rebalance(DBNode node, DBNode *root) } /** - * Erase a node from the RED-BLACK tree, keeping the tree balanced. - * @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*) - */ +* Erase a node from the RED-BLACK tree, keeping the tree balanced. +* @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*) +*/ static void db_rebalance_erase(DBNode node, DBNode *root) { DBNode y = node; @@ -505,7 +510,7 @@ static void db_rebalance_erase(DBNode node, DBNode *root) // put the right of 'node' in 'y' y->right = node->right; node->right->parent = y; - // 'y' is a direct child of 'node' + // 'y' is a direct child of 'node' } else { x_parent = y; } @@ -553,9 +558,9 @@ static void db_rebalance_erase(DBNode node, DBNode *root) } if ((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; } else { if (w->right == NULL || w->right->color == BLACK) { if (w->left) w->left->color = BLACK; @@ -579,9 +584,9 @@ static void db_rebalance_erase(DBNode node, DBNode *root) } if ((w->right == NULL || w->right->color == BLACK) && (w->left == NULL || w->left->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; } else { if (w->left == NULL || w->left->color == BLACK) { if (w->right) w->right->color = BLACK; @@ -602,39 +607,39 @@ static void db_rebalance_erase(DBNode node, DBNode *root) } /** - * Returns not 0 if the key is considered to be NULL. - * @param type Type of database - * @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) - */ +* Returns not 0 if the key is considered to be NULL. +* @param type Type of database +* @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) +*/ static int db_is_key_null(DBType type, DBKey key) { DB_COUNTSTAT(db_is_key_null); switch (type) { - case DB_STRING: - case DB_ISTRING: - return (key.str == NULL); + case DB_STRING: + case DB_ISTRING: + return (key.str == NULL); - default: // Not a pointer - return 0; + default: // Not a pointer + return 0; } } /** - * Duplicate the key used in the database. - * @param db Database the key is being used in - * @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) - */ +* Duplicate the key used in the database. +* @param db Database the key is being used in +* @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) +*/ static DBKey db_dup_key(DBMap_impl* db, DBKey key) { char *str; @@ -642,56 +647,56 @@ static DBKey db_dup_key(DBMap_impl* db, DBKey key) 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); - memcpy(str, key.str, len); - str[len] = '\0'; - key.str = str; - return key; - - default: - return key; + case DB_STRING: + case DB_ISTRING: + len = strnlen(key.str, db->maxlen); + str = (char*)aMalloc(len + 1); + memcpy(str, key.str, len); + str[len] = '\0'; + key.str = str; + return key; + + default: + return key; } } /** - * Free a key duplicated by db_dup_key. - * @param db Database the key is being used in - * @param key Key to be freed - * @private - * @see #db_dup_key(DBMap_impl*,DBKey) - */ +* Free a key duplicated by db_dup_key. +* @param db Database the key is being used in +* @param key Key to be freed +* @private +* @see #db_dup_key(DBMap_impl*,DBKey) +*/ static void db_dup_key_free(DBMap_impl* db, DBKey key) { DB_COUNTSTAT(db_dup_key_free); switch (db->type) { - case DB_STRING: - case DB_ISTRING: - aFree((char*)key.str); - return; + case DB_STRING: + case DB_ISTRING: + aFree((char*)key.str); + return; - default: - return; + default: + return; } } /** - * Add a node to the free_list of the database. - * Marks the node as deleted. - * If the key isn't duplicated, the key is duplicated and released. - * @param db Target database - * @param root Root of the tree from the node - * @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) - */ +* Add a node to the free_list of the database. +* Marks the node as deleted. +* If the key isn't duplicated, the key is duplicated and released. +* @param db Target database +* @param root Root of the tree from the node +* @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) +*/ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) { DBKey old_key; @@ -699,8 +704,8 @@ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) DB_COUNTSTAT(db_free_add); if (db->free_lock == (unsigned int)~0) { ShowFatalError("db_free_add: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); exit(EXIT_FAILURE); } if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed @@ -713,8 +718,8 @@ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) if (db->free_max <= db->free_count) { if (db->free_count == (unsigned int)~0) { ShowFatalError("db_free_add: free_count overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); exit(EXIT_FAILURE); } db->free_max = (unsigned int)~0; @@ -729,18 +734,18 @@ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) } /** - * Remove a node from the free_list of the database. - * Marks the node as not deleted. - * NOTE: Frees the duplicated key of the node. - * @param db Target database - * @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) - */ +* Remove a node from the free_list of the database. +* Marks the node as not deleted. +* NOTE: Frees the duplicated key of the node. +* @param db Target database +* @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) +*/ static void db_free_remove(DBMap_impl* db, DBNode node) { unsigned int i; @@ -764,35 +769,35 @@ 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*) - */ +* Increment the free_lock of the database. +* @param db Target database +* @private +* @see DBMap_impl#free_lock +* @see #db_unlock(DBMap_impl*) +*/ static void db_free_lock(DBMap_impl* db) { DB_COUNTSTAT(db_free_lock); if (db->free_lock == (unsigned int)~0) { ShowFatalError("db_free_lock: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); exit(EXIT_FAILURE); } db->free_lock++; } /** - * Decrement the free_lock of the database. - * If it was the last lock, frees the nodes of the database. - * Keeps the tree balanced. - * 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*) - */ +* Decrement the free_lock of the database. +* If it was the last lock, frees the nodes of the database. +* Keeps the tree balanced. +* 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*) +*/ static void db_free_unlock(DBMap_impl* db) { unsigned int i; @@ -800,8 +805,8 @@ static void db_free_unlock(DBMap_impl* db) DB_COUNTSTAT(db_free_unlock); if (db->free_lock == 0) { ShowWarning("db_free_unlock: free_lock was already 0\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); } else { db->free_lock--; } @@ -818,36 +823,36 @@ static void db_free_unlock(DBMap_impl* db) } /*****************************************************************************\ - * (3) Section of protected functions used internally. * - * NOTE: the protected functions used in the database interface are in the * - * next section. * - * db_int_cmp - Default comparator for DB_INT databases. * - * db_uint_cmp - Default comparator for DB_UINT databases. * - * db_string_cmp - Default comparator for DB_STRING databases. * - * db_istring_cmp - Default comparator for DB_ISTRING databases. * - * db_int_hash - Default hasher for DB_INT databases. * - * db_uint_hash - Default hasher for DB_UINT databases. * - * db_string_hash - Default hasher for DB_STRING databases. * - * db_istring_hash - Default hasher for DB_ISTRING databases. * - * db_release_nothing - Releaser that releases nothing. * - * db_release_key - Releaser that only releases the key. * - * db_release_data - Releaser that only releases the data. * - * db_release_both - Releaser that releases key and data. * +* (3) Section of protected functions used internally. * +* NOTE: the protected functions used in the database interface are in the * +* next section. * +* db_int_cmp - Default comparator for DB_INT databases. * +* db_uint_cmp - Default comparator for DB_UINT databases. * +* db_string_cmp - Default comparator for DB_STRING databases. * +* db_istring_cmp - Default comparator for DB_ISTRING databases. * +* db_int_hash - Default hasher for DB_INT databases. * +* db_uint_hash - Default hasher for DB_UINT databases. * +* db_string_hash - Default hasher for DB_STRING databases. * +* db_istring_hash - Default hasher for DB_ISTRING databases. * +* db_release_nothing - Releaser that releases nothing. * +* db_release_key - Releaser that only releases the key. * +* db_release_data - Releaser that only releases the data. * +* db_release_both - Releaser that releases key and data. * \*****************************************************************************/ /** - * Default comparator for DB_INT databases. - * Compares key1 to key2. - * Return 0 if equal, negative if lower and positive if higher. - * <code>maxlen</code> is ignored. - * @param key1 Key to be compared - * @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 #DBComparator - * @see #db_default_cmp(DBType) - */ +* Default comparator for DB_INT databases. +* Compares key1 to key2. +* Return 0 if equal, negative if lower and positive if higher. +* <code>maxlen</code> is ignored. +* @param key1 Key to be compared +* @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 #DBComparator +* @see #db_default_cmp(DBType) +*/ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { (void)maxlen;//not used @@ -858,18 +863,18 @@ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) } /** - * Default comparator for DB_UINT databases. - * Compares key1 to key2. - * Return 0 if equal, negative if lower and positive if higher. - * <code>maxlen</code> is ignored. - * @param key1 Key to be compared - * @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 #DBComparator - * @see #db_default_cmp(DBType) - */ +* Default comparator for DB_UINT databases. +* Compares key1 to key2. +* Return 0 if equal, negative if lower and positive if higher. +* <code>maxlen</code> is ignored. +* @param key1 Key to be compared +* @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 #DBComparator +* @see #db_default_cmp(DBType) +*/ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { (void)maxlen;//not used @@ -880,17 +885,17 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) } /** - * Default comparator for DB_STRING databases. - * Compares key1 to key2. - * Return 0 if equal, negative if lower and positive if higher. - * @param key1 Key to be compared - * @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 #DBComparator - * @see #db_default_cmp(DBType) - */ +* Default comparator for DB_STRING databases. +* Compares key1 to key2. +* Return 0 if equal, negative if lower and positive if higher. +* @param key1 Key to be compared +* @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 #DBComparator +* @see #db_default_cmp(DBType) +*/ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { DB_COUNTSTAT(db_string_cmp); @@ -898,17 +903,17 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) } /** - * Default comparator for DB_ISTRING databases. - * Compares key1 to key2 case insensitively. - * Return 0 if equal, negative if lower and positive if higher. - * @param key1 Key to be compared - * @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 #DBComparator - * @see #db_default_cmp(DBType) - */ +* Default comparator for DB_ISTRING databases. +* Compares key1 to key2 case insensitively. +* Return 0 if equal, negative if lower and positive if higher. +* @param key1 Key to be compared +* @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 #DBComparator +* @see #db_default_cmp(DBType) +*/ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { DB_COUNTSTAT(db_istring_cmp); @@ -916,16 +921,16 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) } /** - * Default hasher for DB_INT databases. - * Returns the value of the key as an unsigned int. - * <code>maxlen</code> is ignored. - * @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 #DBHasher - * @see #db_default_hash(DBType) - */ +* Default hasher for DB_INT databases. +* Returns the value of the key as an unsigned int. +* <code>maxlen</code> is ignored. +* @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 #DBHasher +* @see #db_default_hash(DBType) +*/ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) { (void)maxlen;//not used @@ -934,16 +939,16 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) } /** - * Default hasher for DB_UINT databases. - * Just returns the value of the key. - * <code>maxlen</code> is ignored. - * @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 #DBHasher - * @see #db_default_hash(DBType) - */ +* Default hasher for DB_UINT databases. +* Just returns the value of the key. +* <code>maxlen</code> is ignored. +* @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 #DBHasher +* @see #db_default_hash(DBType) +*/ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) { (void)maxlen;//not used @@ -952,14 +957,14 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) } /** - * Default hasher for DB_STRING databases. - * @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 #DBHasher - * @see #db_default_hash(DBType) - */ +* Default hasher for DB_STRING databases. +* @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 #DBHasher +* @see #db_default_hash(DBType) +*/ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) { const char *k = key.str; @@ -979,13 +984,13 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) } /** - * Default hasher for DB_ISTRING databases. - * @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) - */ +* Default hasher for DB_ISTRING databases. +* @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) +*/ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) { const char *k = key.str; @@ -1005,14 +1010,14 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) } /** - * Releaser that releases nothing. - * @param key Key of the database entry - * @param data Data of the database entry - * @param which What is being requested to be released - * @protected - * @see #DBReleaser - * @see #db_default_releaser(DBType,DBOptions) - */ +* Releaser that releases nothing. +* @param key Key of the database entry +* @param data Data of the database entry +* @param which What is being requested to be released +* @protected +* @see #DBReleaser +* @see #db_default_releaser(DBType,DBOptions) +*/ static void db_release_nothing(DBKey key, DBData data, DBRelease which) { (void)key;(void)data;(void)which;//not used @@ -1020,14 +1025,14 @@ static void db_release_nothing(DBKey key, DBData data, DBRelease which) } /** - * Releaser that only releases the key. - * @param key Key of the database entry - * @param data Data of the database entry - * @param which What is being requested to be released - * @protected - * @see #DBReleaser - * @see #db_default_release(DBType,DBOptions) - */ +* Releaser that only releases the key. +* @param key Key of the database entry +* @param data Data of the database entry +* @param which What is being requested to be released +* @protected +* @see #DBReleaser +* @see #db_default_release(DBType,DBOptions) +*/ static void db_release_key(DBKey key, DBData data, DBRelease which) { (void)data;//not used @@ -1036,16 +1041,16 @@ static void db_release_key(DBKey key, DBData data, DBRelease which) } /** - * Releaser that only releases the data. - * @param key Key of the database entry - * @param data Data of the database entry - * @param which What is being requested to be released - * @protected - * @see #DBData - * @see #DBRelease - * @see #DBReleaser - * @see #db_default_release(DBType,DBOptions) - */ +* Releaser that only releases the data. +* @param key Key of the database entry +* @param data Data of the database entry +* @param which What is being requested to be released +* @protected +* @see #DBData +* @see #DBRelease +* @see #DBReleaser +* @see #db_default_release(DBType,DBOptions) +*/ static void db_release_data(DBKey key, DBData data, DBRelease which) { (void)key;//not used @@ -1054,17 +1059,17 @@ static void db_release_data(DBKey key, DBData data, DBRelease which) } /** - * Releaser that releases both key and data. - * @param key Key of the database entry - * @param data Data of the database entry - * @param which What is being requested to be released - * @protected - * @see #DBKey - * @see #DBData - * @see #DBRelease - * @see #DBReleaser - * @see #db_default_release(DBType,DBOptions) - */ +* Releaser that releases both key and data. +* @param key Key of the database entry +* @param data Data of the database entry +* @param which What is being requested to be released +* @protected +* @see #DBKey +* @see #DBData +* @see #DBRelease +* @see #DBReleaser +* @see #db_default_release(DBType,DBOptions) +*/ static void db_release_both(DBKey key, DBData data, DBRelease which) { DB_COUNTSTAT(db_release_both); @@ -1073,52 +1078,52 @@ static void db_release_both(DBKey key, DBData data, DBRelease which) } /*****************************************************************************\ - * (4) Section with protected functions used in the interface of the * - * database and interface of the iterator. * - * dbit_obj_first - Fetches the first entry from the database. * - * dbit_obj_last - Fetches the last entry from the database. * - * dbit_obj_next - Fetches the next entry from the database. * - * dbit_obj_prev - Fetches the previous entry from the database. * - * dbit_obj_exists - Returns true if the current entry exists. * - * dbit_obj_remove - Remove the current entry from the database. * - * dbit_obj_destroy - Destroys the iterator, unlocking the database and * - * freeing used memory. * - * db_obj_iterator - Return a new database iterator. * - * db_obj_exists - Checks if an entry exists. * - * db_obj_get - Get the data identified by the key. * - * db_obj_vgetall - Get the data of the matched entries. * - * db_obj_getall - Get the data of the matched entries. * - * db_obj_vensure - Get the data identified by the key, creating if it * - * doesn't exist yet. * - * db_obj_ensure - Get the data identified by the key, creating if it * - * doesn't exist yet. * - * db_obj_put - Put data identified by the key in the database. * - * db_obj_remove - Remove an entry from the database. * - * db_obj_vforeach - Apply a function to every entry in the database. * - * db_obj_foreach - Apply a function to every entry in the database. * - * db_obj_vclear - Remove all entries from the database. * - * db_obj_clear - Remove all entries from the database. * - * db_obj_vdestroy - Destroy the database, freeing all the used memory. * - * db_obj_destroy - Destroy the database, freeing all the used memory. * - * db_obj_size - Return the size of the database. * - * db_obj_type - Return the type of the database. * - * db_obj_options - Return the options of the database. * +* (4) Section with protected functions used in the interface of the * +* database and interface of the iterator. * +* dbit_obj_first - Fetches the first entry from the database. * +* dbit_obj_last - Fetches the last entry from the database. * +* dbit_obj_next - Fetches the next entry from the database. * +* dbit_obj_prev - Fetches the previous entry from the database. * +* dbit_obj_exists - Returns true if the current entry exists. * +* dbit_obj_remove - Remove the current entry from the database. * +* dbit_obj_destroy - Destroys the iterator, unlocking the database and * +* freeing used memory. * +* db_obj_iterator - Return a new database iterator. * +* db_obj_exists - Checks if an entry exists. * +* db_obj_get - Get the data identified by the key. * +* db_obj_vgetall - Get the data of the matched entries. * +* db_obj_getall - Get the data of the matched entries. * +* db_obj_vensure - Get the data identified by the key, creating if it * +* doesn't exist yet. * +* db_obj_ensure - Get the data identified by the key, creating if it * +* doesn't exist yet. * +* db_obj_put - Put data identified by the key in the database. * +* db_obj_remove - Remove an entry from the database. * +* db_obj_vforeach - Apply a function to every entry in the database. * +* db_obj_foreach - Apply a function to every entry in the database. * +* db_obj_vclear - Remove all entries from the database. * +* db_obj_clear - Remove all entries from the database. * +* db_obj_vdestroy - Destroy the database, freeing all the used memory. * +* db_obj_destroy - Destroy the database, freeing all the used memory. * +* db_obj_size - Return the size of the database. * +* db_obj_type - Return the type of the database. * +* db_obj_options - Return the options of the database. * \*****************************************************************************/ /** - * Fetches the first entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - * @see DBIterator#first - */ +* Fetches the first entry in the database. +* Returns the data of the entry. +* Puts the key in out_key, if out_key is not NULL. +* @param self Iterator +* @param out_key Key of the entry +* @return Data of the entry +* @protected +* @see DBIterator#first +*/ DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) { DBIterator_impl* it = (DBIterator_impl*)self; - + DB_COUNTSTAT(dbit_first); // position before the first entry it->ht_index = -1; @@ -1128,19 +1133,19 @@ DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) } /** - * Fetches the last entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - * @see DBIterator#last - */ +* Fetches the last entry in the database. +* Returns the data of the entry. +* Puts the key in out_key, if out_key is not NULL. +* @param self Iterator +* @param out_key Key of the entry +* @return Data of the entry +* @protected +* @see DBIterator#last +*/ DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) { DBIterator_impl* it = (DBIterator_impl*)self; - + DB_COUNTSTAT(dbit_last); // position after the last entry it->ht_index = HASH_SIZE; @@ -1150,15 +1155,15 @@ DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) } /** - * Fetches the next entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - * @see DBIterator#next - */ +* Fetches the next entry in the database. +* Returns the data of the entry. +* Puts the key in out_key, if out_key is not NULL. +* @param self Iterator +* @param out_key Key of the entry +* @return Data of the entry +* @protected +* @see DBIterator#next +*/ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) { DBIterator_impl* it = (DBIterator_impl*)self; @@ -1226,15 +1231,15 @@ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) } /** - * Fetches the previous entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - * @see DBIterator#prev - */ +* Fetches the previous entry in the database. +* Returns the data of the entry. +* Puts the key in out_key, if out_key is not NULL. +* @param self Iterator +* @param out_key Key of the entry +* @return Data of the entry +* @protected +* @see DBIterator#prev +*/ DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) { DBIterator_impl* it = (DBIterator_impl*)self; @@ -1262,7 +1267,7 @@ DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) node = &fake; } - + while( node ) {// next node if( node->left ) @@ -1303,14 +1308,14 @@ DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) } /** - * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if - * the iterator is done. - * @param self Iterator - * @return true if the entry exists - * @protected - * @see DBIterator#exists - */ +* Returns true if the fetched entry exists. +* The databases entries might have NULL data, so use this to to test if +* the iterator is done. +* @param self Iterator +* @return true if the entry exists +* @protected +* @see DBIterator#exists +*/ bool dbit_obj_exists(DBIterator* self) { DBIterator_impl* it = (DBIterator_impl*)self; @@ -1320,17 +1325,17 @@ 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 - * 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 DBIterator#remove - */ +* Removes the current entry from the database. +* NOTE: {@link 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 DBIterator#remove +*/ int dbit_obj_remove(DBIterator* self, DBData *out_data) { DBIterator_impl* it = (DBIterator_impl*)self; @@ -1354,10 +1359,10 @@ int dbit_obj_remove(DBIterator* self, DBData *out_data) } /** - * Destroys this iterator and unlocks the database. - * @param self Iterator - * @protected - */ +* Destroys this iterator and unlocks the database. +* @param self Iterator +* @protected +*/ void dbit_obj_destroy(DBIterator* self) { DBIterator_impl* it = (DBIterator_impl*)self; @@ -1366,25 +1371,25 @@ void dbit_obj_destroy(DBIterator* self) // unlock the database db_free_unlock(it->db); // free iterator - aFree(self); + ers_free(db_iterator_ers,self); } /** - * Returns a new iterator for this database. - * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal - * memory when unlocked, so destroy the iterator as soon as possible. - * @param self Database - * @return New iterator - * @protected - */ +* Returns a new iterator for this database. +* The iterator keeps the database locked until it is destroyed. +* The database will keep functioning normally but will only free internal +* memory when unlocked, so destroy the iterator as soon as possible. +* @param self Database +* @return New iterator +* @protected +*/ static DBIterator* db_obj_iterator(DBMap* self) { DBMap_impl* db = (DBMap_impl*)self; DBIterator_impl* it; DB_COUNTSTAT(db_iterator); - CREATE(it, struct DBIterator_impl, 1); + it = ers_alloc(db_iterator_ers, struct DBIterator_impl); /* Interface of the iterator **/ it->vtable.first = dbit_obj_first; it->vtable.last = dbit_obj_last; @@ -1403,13 +1408,13 @@ static DBIterator* db_obj_iterator(DBMap* self) } /** - * Returns true if the entry exists. - * @param self Interface of the database - * @param key Key that identifies the entry - * @return true is the entry exists - * @protected - * @see DBMap#exists - */ +* Returns true if the entry exists. +* @param self Interface of the database +* @param key Key that identifies the entry +* @return true is the entry exists +* @protected +* @see DBMap#exists +*/ static bool db_obj_exists(DBMap* self, DBKey key) { DBMap_impl* db = (DBMap_impl*)self; @@ -1454,13 +1459,13 @@ static bool db_obj_exists(DBMap* self, DBKey key) } /** - * Get the data of the entry identified by the key. - * @param self Interface of the database - * @param key Key that identifies the entry - * @return Data of the entry or NULL if not found - * @protected - * @see DBMap#get - */ +* Get the data of the entry identified by the key. +* @param self Interface of the database +* @param key Key that identifies the entry +* @return Data of the entry or NULL if not found +* @protected +* @see DBMap#get +*/ static DBData* db_obj_get(DBMap* self, DBKey key) { DBMap_impl* db = (DBMap_impl*)self; @@ -1506,21 +1511,21 @@ static DBData* db_obj_get(DBMap* self, DBKey key) } /** - * 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. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than <code>max</code>, only the - * first <code>max</code> entries found are put into the buffer. - * @param self Interface of the database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see 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. +* Returns the number of entries that matched. +* NOTE: if the value returned is greater than <code>max</code>, only the +* first <code>max</code> entries found are put into the buffer. +* @param self Interface of the database +* @param buf Buffer to put the data of the matched entries +* @param max Maximum number of data entries to be put into buf +* @param match Function that matches the database entries +* @param ... Extra arguments for match +* @return The number of entries that matched +* @protected +* @see DBMap#vgetall +*/ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, va_list args) { DBMap_impl* db = (DBMap_impl*)self; @@ -1549,17 +1554,17 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, } va_end(argscopy); } - + if (node->left) { node = node->left; continue; } - + if (node->right) { node = node->right; continue; } - + while (node) { parent = node->parent; if (parent && parent->right && parent->left == node) { @@ -1576,23 +1581,23 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, } /** - * Just calls {@link 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. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than <code>max</code>, only the - * first <code>max</code> entries found are put into the buffer. - * @param self Interface of the database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#vgetall - * @see DBMap#getall - */ +* Just calls {@link 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. +* Returns the number of entries that matched. +* NOTE: if the value returned is greater than <code>max</code>, only the +* first <code>max</code> entries found are put into the buffer. +* @param self Interface of the database +* @param buf Buffer to put the data of the matched entries +* @param max Maximum number of data entries to be put into buf +* @param match Function that matches the database entries +* @param ... Extra arguments for match +* @return The number of entries that matched +* @protected +* @see DBMap#vgetall +* @see DBMap#getall +*/ static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, ...) { va_list args; @@ -1608,17 +1613,17 @@ static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, D } /** - * 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>. - * @param self Interface of the database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param args Extra arguments for create - * @return Data of the entry - * @protected - * @see 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>. +* @param self Interface of the database +* @param key Key that identifies the entry +* @param create Function used to create the data if the entry doesn't exist +* @param args Extra arguments for create +* @return Data of the entry +* @protected +* @see DBMap#vensure +*/ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args) { DBMap_impl* db = (DBMap_impl*)self; @@ -1661,9 +1666,9 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li va_list argscopy; if (db->item_count == UINT32_MAX) { ShowError("db_vensure: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return NULL; + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return NULL; } DB_COUNTSTAT(db_node_alloc); node = ers_alloc(db->nodes, struct dbn); @@ -1706,19 +1711,19 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li } /** - * 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>. - * @param self Interface of the 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 - * @see DBMap#ensure - */ +* 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>. +* @param self Interface of the 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 +* @see DBMap#ensure +*/ static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) { va_list args; @@ -1734,18 +1739,18 @@ static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) } /** - * Put the data identified by the key in the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: Uses the new key, the old one is released. - * @param self Interface of the database - * @param key Key that identifies the data - * @param data Data to be put in the database - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - * @see #db_malloc_dbn(void) - * @see DBMap#put - */ +* Put the data identified by the key in the database. +* Puts the previous data in out_data, if out_data is not NULL. +* NOTE: Uses the new key, the old one is released. +* @param self Interface of the database +* @param key Key that identifies the data +* @param data Data to be put in the database +* @param out_data Previous data if the entry exists +* @return 1 if if the entry already exists, 0 otherwise +* @protected +* @see #db_malloc_dbn(void) +* @see DBMap#put +*/ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) { DBMap_impl* db = (DBMap_impl*)self; @@ -1758,8 +1763,8 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) if (db == NULL) return 0; // nullpo candidate if (db->global_lock) { ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); return 0; // nullpo candidate } if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { @@ -1773,8 +1778,8 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) if (db->item_count == UINT32_MAX) { ShowError("db_put: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); return 0; } // search for an equal node @@ -1840,17 +1845,17 @@ 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. - * NOTE: The key (of the database) is released in {@link #db_free_add(DBMap_impl*,DBNode,DBNode *)}. - * @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 - */ +* Remove an entry from the database. +* Puts the previous data in out_data, if out_data is not NULL. +* NOTE: The key (of the database) is released in {@link #db_free_add(DBMap_impl*,DBNode,DBNode *)}. +* @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 +*/ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) { DBMap_impl* db = (DBMap_impl*)self; @@ -1862,8 +1867,8 @@ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) if (db == NULL) return 0; // nullpo candidate if (db->global_lock) { ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); return 0; // nullpo candidate } if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { @@ -1897,15 +1902,15 @@ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) } /** - * Apply <code>func</code> to every entry in the database. - * Returns the sum of values returned by func. - * @param self Interface of the database - * @param func Function to be applied - * @param args Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see 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 +* @param func Function to be applied +* @param args Extra arguments for func +* @return Sum of the values returned by func +* @protected +* @see DBMap#vforeach +*/ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) { DBMap_impl* db = (DBMap_impl*)self; @@ -1955,17 +1960,17 @@ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) } /** - * Just calls {@link 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 - * @param func Function to be applyed - * @param ... Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#vforeach - * @see DBMap#foreach - */ +* Just calls {@link 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 +* @param func Function to be applyed +* @param ... Extra arguments for func +* @return Sum of the values returned by func +* @protected +* @see DBMap#vforeach +* @see DBMap#foreach +*/ static int db_obj_foreach(DBMap* self, DBApply func, ...) { va_list args; @@ -1981,17 +1986,17 @@ static int db_obj_foreach(DBMap* self, DBApply func, ...) } /** - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Interface of the database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vclear - */ +* Removes all entries from the database. +* Before deleting an entry, func is applied to it. +* Releases the key and the data. +* Returns the sum of values returned by func, if it exists. +* @param self Interface of the database +* @param func Function to be applied to every entry before deleting +* @param args Extra arguments for func +* @return Sum of values returned by func +* @protected +* @see DBMap#vclear +*/ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) { DBMap_impl* db = (DBMap_impl*)self; @@ -2051,21 +2056,21 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) } /** - * Just calls {@link DBMap#vclear}. - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Interface of the database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vclear - * @see DBMap#clear - */ +* Just calls {@link DBMap#vclear}. +* Removes all entries from the database. +* Before deleting an entry, func is applied to it. +* Releases the key and the data. +* Returns the sum of values returned by func, if it exists. +* NOTE: This locks the database globally. Any attempt to insert or remove +* a database entry will give an error and be aborted (except for clearing). +* @param self Interface of the database +* @param func Function to be applied to every entry before deleting +* @param ... Extra arguments for func +* @return Sum of values returned by func +* @protected +* @see DBMap#vclear +* @see DBMap#clear +*/ static int db_obj_clear(DBMap* self, DBApply func, ...) { va_list args; @@ -2081,18 +2086,18 @@ static int db_obj_clear(DBMap* self, DBApply func, ...) } /** - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Interface of the database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vdestroy - */ +* Finalize the database, feeing all the memory it uses. +* Before deleting an entry, func is applied to it. +* Returns the sum of values returned by func, if it exists. +* NOTE: This locks the database globally. Any attempt to insert or remove +* a database entry will give an error and be aborted (except for clearing). +* @param self Interface of the database +* @param func Function to be applied to every entry before deleting +* @param args Extra arguments for func +* @return Sum of values returned by func +* @protected +* @see DBMap#vdestroy +*/ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) { DBMap_impl* db = (DBMap_impl*)self; @@ -2102,21 +2107,21 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) if (db == NULL) return 0; // nullpo candidate if (db->global_lock) { ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); return 0; } if (db->free_lock) ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" - "Database allocated at %s:%d\n", - db->free_lock, db->alloc_file, db->alloc_line); + "Database allocated at %s:%d\n", + db->free_lock, db->alloc_file, db->alloc_line); #ifdef DB_ENABLE_STATS switch (db->type) { - case DB_INT: DB_COUNTSTAT(db_int_destroy); break; - case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break; - case DB_STRING: DB_COUNTSTAT(db_string_destroy); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break; + case DB_INT: DB_COUNTSTAT(db_int_destroy); break; + case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break; + case DB_STRING: DB_COUNTSTAT(db_string_destroy); break; + case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break; } #endif /* DB_ENABLE_STATS */ db_free_lock(db); @@ -2127,26 +2132,26 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) db->free_max = 0; ers_destroy(db->nodes); db_free_unlock(db); - aFree(db); + ers_free(db_alloc_ers, db); return sum; } /** - * Just calls {@link 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. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vdestroy - * @see DBMap#destroy - */ +* Just calls {@link 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. +* Returns the sum of values returned by func, if it exists. +* NOTE: This locks the database globally. Any attempt to insert or remove +* a database entry will give an error and be aborted. +* @param self Database +* @param func Function to be applied to every entry before deleting +* @param ... Extra arguments for func +* @return Sum of values returned by func +* @protected +* @see DBMap#vdestroy +* @see DBMap#destroy +*/ static int db_obj_destroy(DBMap* self, DBApply func, ...) { va_list args; @@ -2162,13 +2167,13 @@ static int db_obj_destroy(DBMap* self, DBApply func, ...) } /** - * Return the size of the database (number of items in the database). - * @param self Interface of the database - * @return Size of the database - * @protected - * @see DBMap_impl#item_count - * @see DBMap#size - */ +* Return the size of the database (number of items in the database). +* @param self Interface of the database +* @return Size of the database +* @protected +* @see DBMap_impl#item_count +* @see DBMap#size +*/ static unsigned int db_obj_size(DBMap* self) { DBMap_impl* db = (DBMap_impl*)self; @@ -2185,13 +2190,13 @@ static unsigned int db_obj_size(DBMap* self) } /** - * Return the type of database. - * @param self Interface of the database - * @return Type of the database - * @protected - * @see DBMap_impl#type - * @see DBMap#type - */ +* Return the type of database. +* @param self Interface of the database +* @return Type of the database +* @protected +* @see DBMap_impl#type +* @see DBMap#type +*/ static DBType db_obj_type(DBMap* self) { DBMap_impl* db = (DBMap_impl*)self; @@ -2208,13 +2213,13 @@ static DBType db_obj_type(DBMap* self) } /** - * Return the options of the database. - * @param self Interface of the database - * @return Options of the database - * @protected - * @see DBMap_impl#options - * @see DBMap#options - */ +* Return the options of the database. +* @param self Interface of the database +* @return Options of the database +* @protected +* @see DBMap_impl#options +* @see DBMap#options +*/ static DBOptions db_obj_options(DBMap* self) { DBMap_impl* db = (DBMap_impl*)self; @@ -2231,120 +2236,121 @@ static DBOptions db_obj_options(DBMap* self) } /*****************************************************************************\ - * (5) Section with public functions. - * db_fix_options - Apply database type restrictions to the options. - * db_default_cmp - Get the default comparator for a type of database. - * db_default_hash - Get the default hasher for a type of database. - * 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 certains 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_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_init - Initializes the database system. - * db_final - Finalizes the database system. +* (5) Section with public functions. +* db_fix_options - Apply database type restrictions to the options. +* db_default_cmp - Get the default comparator for a type of database. +* db_default_hash - Get the default hasher for a type of database. +* 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 certains 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_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_init - Initializes the database system. +* db_final - Finalizes the database system. \*****************************************************************************/ /** - * Returns the fixed options according to the database type. - * Sets required options and unsets unsupported options. - * For numeric databases DB_OPT_DUP_KEY and DB_OPT_RELEASE_KEY are unset. - * @param type Type of the database - * @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) - */ +* Returns the fixed options according to the database type. +* Sets required options and unsets unsupported options. +* For numeric databases DB_OPT_DUP_KEY and DB_OPT_RELEASE_KEY are unset. +* @param type Type of the database +* @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) +*/ DBOptions db_fix_options(DBType type, DBOptions options) { DB_COUNTSTAT(db_fix_options); switch (type) { - case DB_INT: - case DB_UINT: // Numeric database, do nothing with the keys - return (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); - case DB_STRING: - case DB_ISTRING: // String databases, no fix required - return options; + case DB_INT: + case DB_UINT: // Numeric database, do nothing with the keys + return (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); + case DB_STRING: + case DB_ISTRING: // String databases, no fix required + return options; } } + /** - * Returns the default comparator for the specified type of database. - * @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) - */ +* Returns the default comparator for the specified type of database. +* @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) +*/ DBComparator db_default_cmp(DBType type) { DB_COUNTSTAT(db_default_cmp); switch (type) { - case DB_INT: return &db_int_cmp; - case DB_UINT: return &db_uint_cmp; - case DB_STRING: return &db_string_cmp; - case DB_ISTRING: return &db_istring_cmp; - default: - ShowError("db_default_cmp: Unknown database type %u\n", type); - return NULL; + case DB_INT: return &db_int_cmp; + case DB_UINT: return &db_uint_cmp; + case DB_STRING: return &db_string_cmp; + case DB_ISTRING: return &db_istring_cmp; + default: + ShowError("db_default_cmp: Unknown database type %u\n", type); + return NULL; } } /** - * 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 #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) - */ +* 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 #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) +*/ DBHasher db_default_hash(DBType type) { DB_COUNTSTAT(db_default_hash); switch (type) { - case DB_INT: return &db_int_hash; - case DB_UINT: return &db_uint_hash; - case DB_STRING: return &db_string_hash; - case DB_ISTRING: return &db_istring_hash; - default: - ShowError("db_default_hash: Unknown database type %u\n", type); - return NULL; + case DB_INT: return &db_int_hash; + case DB_UINT: return &db_uint_hash; + case DB_STRING: return &db_string_hash; + case DB_ISTRING: return &db_istring_hash; + default: + ShowError("db_default_hash: Unknown database type %u\n", type); + return NULL; } } /** - * 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. - * @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) - */ +* 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. +* @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) +*/ DBReleaser db_default_release(DBType type, DBOptions options) { DB_COUNTSTAT(db_default_release); - options = db_fix_options(type, options); + options = DB->fix_options(type, options); if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) return &db_release_both; // Release both key and data @@ -2356,45 +2362,45 @@ DBReleaser db_default_release(DBType type, DBOptions options) } /** - * Returns the releaser that releases the specified release 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) - */ +* Returns the releaser that releases the specified release 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) +*/ DBReleaser db_custom_release(DBRelease which) { DB_COUNTSTAT(db_custom_release); switch (which) { - case DB_RELEASE_NOTHING: return &db_release_nothing; - case DB_RELEASE_KEY: return &db_release_key; - case DB_RELEASE_DATA: return &db_release_data; - case DB_RELEASE_BOTH: return &db_release_both; - default: - ShowError("db_custom_release: Unknown release options %u\n", which); - return NULL; + case DB_RELEASE_NOTHING: return &db_release_nothing; + case DB_RELEASE_KEY: return &db_release_key; + case DB_RELEASE_DATA: return &db_release_data; + case DB_RELEASE_BOTH: return &db_release_both; + default: + ShowError("db_custom_release: Unknown release options %u\n", which); + return NULL; } } /** - * Allocate a new database of the specified type. - * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} - * 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 - * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string - * 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) - */ +* Allocate a new database of the specified type. +* NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} +* 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 +* @param options Options of the database +* @param maxlen Maximum length of the string to be used as key in string +* 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) +*/ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) { DBMap_impl* db; @@ -2403,15 +2409,15 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi #ifdef DB_ENABLE_STATS DB_COUNTSTAT(db_alloc); switch (type) { - case DB_INT: DB_COUNTSTAT(db_int_alloc); break; - case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break; - case DB_STRING: DB_COUNTSTAT(db_string_alloc); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; + case DB_INT: DB_COUNTSTAT(db_int_alloc); break; + case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break; + case DB_STRING: DB_COUNTSTAT(db_string_alloc); break; + case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; } #endif /* DB_ENABLE_STATS */ - CREATE(db, struct DBMap_impl, 1); + db = ers_alloc(db_alloc_ers, struct DBMap_impl); - options = db_fix_options(type, options); + options = DB->fix_options(type, options); /* Interface of the database */ db->vtable.iterator = db_obj_iterator; db->vtable.exists = db_obj_exists; @@ -2441,9 +2447,9 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi db->free_lock = 0; /* Other */ db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); - db->cmp = db_default_cmp(type); - db->hash = db_default_hash(type); - db->release = db_default_release(type, options); + db->cmp = DB->default_cmp(type); + db->hash = DB->default_hash(type); + db->release = DB->default_release(type, options); for (i = 0; i < HASH_SIZE; i++) db->ht[i] = NULL; db->cache = NULL; @@ -2460,11 +2466,11 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi } /** - * Manual cast from 'int' to the union DBKey. - * @param key Key to be casted - * @return The key as a DBKey union - * @public - */ +* Manual cast from 'int' to the union DBKey. +* @param key Key to be casted +* @return The key as a DBKey union +* @public +*/ DBKey db_i2key(int key) { DBKey ret; @@ -2475,11 +2481,11 @@ DBKey db_i2key(int key) } /** - * Manual cast from 'unsigned int' to the union DBKey. - * @param key Key to be casted - * @return The key as a DBKey union - * @public - */ +* Manual cast from 'unsigned int' to the union DBKey. +* @param key Key to be casted +* @return The key as a DBKey union +* @public +*/ DBKey db_ui2key(unsigned int key) { DBKey ret; @@ -2490,11 +2496,11 @@ DBKey db_ui2key(unsigned int key) } /** - * Manual cast from 'const char *' to the union DBKey. - * @param key Key to be casted - * @return The key as a DBKey union - * @public - */ +* Manual cast from 'const char *' to the union DBKey. +* @param key Key to be casted +* @return The key as a DBKey union +* @public +*/ DBKey db_str2key(const char *key) { DBKey ret; @@ -2505,11 +2511,11 @@ DBKey db_str2key(const char *key) } /** - * Manual cast from 'int' to the struct DBData. - * @param data Data to be casted - * @return The data as a DBData struct - * @public - */ +* Manual cast from 'int' to the struct DBData. +* @param data Data to be casted +* @return The data as a DBData struct +* @public +*/ DBData db_i2data(int data) { DBData ret; @@ -2521,11 +2527,11 @@ DBData db_i2data(int data) } /** - * Manual cast from 'unsigned int' to the struct DBData. - * @param data Data to be casted - * @return The data as a DBData struct - * @public - */ +* Manual cast from 'unsigned int' to the struct DBData. +* @param data Data to be casted +* @return The data as a DBData struct +* @public +*/ DBData db_ui2data(unsigned int data) { DBData ret; @@ -2537,11 +2543,11 @@ DBData db_ui2data(unsigned int data) } /** - * Manual cast from 'void *' to the struct DBData. - * @param data Data to be casted - * @return The data as a DBData struct - * @public - */ +* Manual cast from 'void *' to the struct DBData. +* @param data Data to be casted +* @return The data as a DBData struct +* @public +*/ DBData db_ptr2data(void *data) { DBData ret; @@ -2553,12 +2559,12 @@ DBData db_ptr2data(void *data) } /** - * Gets int type data from struct DBData. - * If data is not int type, returns 0. - * @param data Data - * @return Integer value of the data. - * @public - */ +* Gets int type data from struct DBData. +* If data is not int type, returns 0. +* @param data Data +* @return Integer value of the data. +* @public +*/ int db_data2i(DBData *data) { DB_COUNTSTAT(db_data2i); @@ -2568,12 +2574,12 @@ int db_data2i(DBData *data) } /** - * Gets unsigned int type data from struct DBData. - * If data is not unsigned int type, returns 0. - * @param data Data - * @return Unsigned int value of the data. - * @public - */ +* Gets unsigned int type data from struct DBData. +* If data is not unsigned int type, returns 0. +* @param data Data +* @return Unsigned int value of the data. +* @public +*/ unsigned int db_data2ui(DBData *data) { DB_COUNTSTAT(db_data2ui); @@ -2583,12 +2589,12 @@ unsigned int db_data2ui(DBData *data) } /** - * Gets void* type data from struct DBData. - * If data is not void* type, returns NULL. - * @param data Data - * @return Void* value of the data. - * @public - */ +* Gets void* type data from struct DBData. +* If data is not void* type, returns NULL. +* @param data Data +* @return Void* value of the data. +* @public +*/ void* db_data2ptr(DBData *data) { DB_COUNTSTAT(db_data2ptr); @@ -2598,104 +2604,107 @@ void* db_data2ptr(DBData *data) } /** - * Initializes the database system. - * @public - * @see #db_final(void) - */ -void db_init(void) -{ +* Initializes the database system. +* @public +* @see #db_final(void) +*/ +void db_init(void) { + db_iterator_ers = ers_new(sizeof(struct DBIterator_impl),"db.c::db_iterator_ers",ERS_OPT_NONE); + db_alloc_ers = ers_new(sizeof(struct DBMap_impl),"db.c::db_alloc_ers",ERS_OPT_NONE); DB_COUNTSTAT(db_init); } /** - * Finalizes the database system. - * @public - * @see #db_init(void) - */ +* Finalizes the database system. +* @public +* @see #db_init(void) +*/ void db_final(void) { #ifdef DB_ENABLE_STATS DB_COUNTSTAT(db_final); ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" - "allocated %u, freed %u\n", - stats.db_node_alloc, stats.db_node_free); + "allocated %u, freed %u\n", + stats.db_node_alloc, stats.db_node_free); ShowInfo(CL_WHITE"Database types"CL_RESET":\n" - "DB_INT : allocated %10u, destroyed %10u\n" - "DB_UINT : allocated %10u, destroyed %10u\n" - "DB_STRING : allocated %10u, destroyed %10u\n" - "DB_ISTRING : allocated %10u, destroyed %10u\n", - stats.db_int_alloc, stats.db_int_destroy, - stats.db_uint_alloc, stats.db_uint_destroy, - stats.db_string_alloc, stats.db_string_destroy, - stats.db_istring_alloc, stats.db_istring_destroy); + "DB_INT : allocated %10u, destroyed %10u\n" + "DB_UINT : allocated %10u, destroyed %10u\n" + "DB_STRING : allocated %10u, destroyed %10u\n" + "DB_ISTRING : allocated %10u, destroyed %10u\n", + stats.db_int_alloc, stats.db_int_destroy, + stats.db_uint_alloc, stats.db_uint_destroy, + stats.db_string_alloc, stats.db_string_destroy, + stats.db_istring_alloc, stats.db_istring_destroy); ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" - "db_rotate_left %10u, db_rotate_right %10u,\n" - "db_rebalance %10u, db_rebalance_erase %10u,\n" - "db_is_key_null %10u,\n" - "db_dup_key %10u, db_dup_key_free %10u,\n" - "db_free_add %10u, db_free_remove %10u,\n" - "db_free_lock %10u, db_free_unlock %10u,\n" - "db_int_cmp %10u, db_uint_cmp %10u,\n" - "db_string_cmp %10u, db_istring_cmp %10u,\n" - "db_int_hash %10u, db_uint_hash %10u,\n" - "db_string_hash %10u, db_istring_hash %10u,\n" - "db_release_nothing %10u, db_release_key %10u,\n" - "db_release_data %10u, db_release_both %10u,\n" - "dbit_first %10u, dbit_last %10u,\n" - "dbit_next %10u, dbit_prev %10u,\n" - "dbit_exists %10u, dbit_remove %10u,\n" - "dbit_destroy %10u, db_iterator %10u,\n" - "db_exits %10u, db_get %10u,\n" - "db_getall %10u, db_vgetall %10u,\n" - "db_ensure %10u, db_vensure %10u,\n" - "db_put %10u, db_remove %10u,\n" - "db_foreach %10u, db_vforeach %10u,\n" - "db_clear %10u, db_vclear %10u,\n" - "db_destroy %10u, db_vdestroy %10u,\n" - "db_size %10u, db_type %10u,\n" - "db_options %10u, db_fix_options %10u,\n" - "db_default_cmp %10u, db_default_hash %10u,\n" - "db_default_release %10u, db_custom_release %10u,\n" - "db_alloc %10u, db_i2key %10u,\n" - "db_ui2key %10u, db_str2key %10u,\n" - "db_i2data %10u, db_ui2data %10u,\n" - "db_ptr2data %10u, db_data2i %10u,\n" - "db_data2ui %10u, db_data2ptr %10u,\n" - "db_init %10u, db_final %10u\n", - stats.db_rotate_left, stats.db_rotate_right, - stats.db_rebalance, stats.db_rebalance_erase, - stats.db_is_key_null, - stats.db_dup_key, stats.db_dup_key_free, - stats.db_free_add, stats.db_free_remove, - stats.db_free_lock, stats.db_free_unlock, - stats.db_int_cmp, stats.db_uint_cmp, - stats.db_string_cmp, stats.db_istring_cmp, - stats.db_int_hash, stats.db_uint_hash, - stats.db_string_hash, stats.db_istring_hash, - stats.db_release_nothing, stats.db_release_key, - stats.db_release_data, stats.db_release_both, - stats.dbit_first, stats.dbit_last, - stats.dbit_next, stats.dbit_prev, - stats.dbit_exists, stats.dbit_remove, - stats.dbit_destroy, stats.db_iterator, - stats.db_exists, stats.db_get, - stats.db_getall, stats.db_vgetall, - stats.db_ensure, stats.db_vensure, - stats.db_put, stats.db_remove, - stats.db_foreach, stats.db_vforeach, - stats.db_clear, stats.db_vclear, - stats.db_destroy, stats.db_vdestroy, - stats.db_size, stats.db_type, - stats.db_options, stats.db_fix_options, - stats.db_default_cmp, stats.db_default_hash, - stats.db_default_release, stats.db_custom_release, - stats.db_alloc, stats.db_i2key, - stats.db_ui2key, stats.db_str2key, - stats.db_i2data, stats.db_ui2data, - stats.db_ptr2data, stats.db_data2i, - stats.db_data2ui, stats.db_data2ptr, - stats.db_init, stats.db_final); + "db_rotate_left %10u, db_rotate_right %10u,\n" + "db_rebalance %10u, db_rebalance_erase %10u,\n" + "db_is_key_null %10u,\n" + "db_dup_key %10u, db_dup_key_free %10u,\n" + "db_free_add %10u, db_free_remove %10u,\n" + "db_free_lock %10u, db_free_unlock %10u,\n" + "db_int_cmp %10u, db_uint_cmp %10u,\n" + "db_string_cmp %10u, db_istring_cmp %10u,\n" + "db_int_hash %10u, db_uint_hash %10u,\n" + "db_string_hash %10u, db_istring_hash %10u,\n" + "db_release_nothing %10u, db_release_key %10u,\n" + "db_release_data %10u, db_release_both %10u,\n" + "dbit_first %10u, dbit_last %10u,\n" + "dbit_next %10u, dbit_prev %10u,\n" + "dbit_exists %10u, dbit_remove %10u,\n" + "dbit_destroy %10u, db_iterator %10u,\n" + "db_exits %10u, db_get %10u,\n" + "db_getall %10u, db_vgetall %10u,\n" + "db_ensure %10u, db_vensure %10u,\n" + "db_put %10u, db_remove %10u,\n" + "db_foreach %10u, db_vforeach %10u,\n" + "db_clear %10u, db_vclear %10u,\n" + "db_destroy %10u, db_vdestroy %10u,\n" + "db_size %10u, db_type %10u,\n" + "db_options %10u, db_fix_options %10u,\n" + "db_default_cmp %10u, db_default_hash %10u,\n" + "db_default_release %10u, db_custom_release %10u,\n" + "db_alloc %10u, db_i2key %10u,\n" + "db_ui2key %10u, db_str2key %10u,\n" + "db_i2data %10u, db_ui2data %10u,\n" + "db_ptr2data %10u, db_data2i %10u,\n" + "db_data2ui %10u, db_data2ptr %10u,\n" + "db_init %10u, db_final %10u\n", + stats.db_rotate_left, stats.db_rotate_right, + stats.db_rebalance, stats.db_rebalance_erase, + stats.db_is_key_null, + stats.db_dup_key, stats.db_dup_key_free, + stats.db_free_add, stats.db_free_remove, + stats.db_free_lock, stats.db_free_unlock, + stats.db_int_cmp, stats.db_uint_cmp, + stats.db_string_cmp, stats.db_istring_cmp, + stats.db_int_hash, stats.db_uint_hash, + stats.db_string_hash, stats.db_istring_hash, + stats.db_release_nothing, stats.db_release_key, + stats.db_release_data, stats.db_release_both, + stats.dbit_first, stats.dbit_last, + stats.dbit_next, stats.dbit_prev, + stats.dbit_exists, stats.dbit_remove, + stats.dbit_destroy, stats.db_iterator, + stats.db_exists, stats.db_get, + stats.db_getall, stats.db_vgetall, + stats.db_ensure, stats.db_vensure, + stats.db_put, stats.db_remove, + stats.db_foreach, stats.db_vforeach, + stats.db_clear, stats.db_vclear, + stats.db_destroy, stats.db_vdestroy, + stats.db_size, stats.db_type, + stats.db_options, stats.db_fix_options, + stats.db_default_cmp, stats.db_default_hash, + stats.db_default_release, stats.db_custom_release, + stats.db_alloc, stats.db_i2key, + stats.db_ui2key, stats.db_str2key, + stats.db_i2data, stats.db_ui2data, + stats.db_ptr2data, stats.db_data2i, + stats.db_data2ui, stats.db_data2ptr, + stats.db_init, stats.db_final); #endif /* DB_ENABLE_STATS */ + ers_destroy(db_iterator_ers); + ers_destroy(db_alloc_ers); } // Link DB System - jAthena @@ -2820,3 +2829,25 @@ void linkdb_final( struct linkdb_node** head ) } *head = NULL; } + +void db_defaults(void) +{ + DB = &DB_s; + DB->alloc = db_alloc; + DB->custom_release = db_custom_release; + DB->data2i = db_data2i; + DB->data2ptr = db_data2ptr; + DB->data2ui = db_data2ui; + DB->default_cmp = db_default_cmp; + DB->default_hash = db_default_hash; + DB->default_release = db_default_release; + DB->final = db_final; + DB->fix_options = db_fix_options; + DB->i2data = db_i2data; + DB->i2key = db_i2key; + DB->init = db_init; + DB->ptr2data = db_ptr2data; + DB->str2key = db_str2key; + DB->ui2data = db_ui2data; + DB->ui2key = db_ui2key; +}
\ No newline at end of file diff --git a/src/common/db.h b/src/common/db.h index 4fe6a93d6..f1f6146be 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -599,73 +599,73 @@ struct DBMap { // For easy access to the common functions. #define db_exists(db,k) ( (db)->exists((db),(k)) ) -#define idb_exists(db,k) ( (db)->exists((db),db_i2key(k)) ) -#define uidb_exists(db,k) ( (db)->exists((db),db_ui2key(k)) ) -#define strdb_exists(db,k) ( (db)->exists((db),db_str2key(k)) ) +#define idb_exists(db,k) ( (db)->exists((db),DB->i2key(k)) ) +#define uidb_exists(db,k) ( (db)->exists((db),DB->ui2key(k)) ) +#define strdb_exists(db,k) ( (db)->exists((db),DB->str2key(k)) ) // Get pointer-type data from DBMaps of various key types -#define db_get(db,k) ( db_data2ptr((db)->get((db),(k))) ) -#define idb_get(db,k) ( db_data2ptr((db)->get((db),db_i2key(k))) ) -#define uidb_get(db,k) ( db_data2ptr((db)->get((db),db_ui2key(k))) ) -#define strdb_get(db,k) ( db_data2ptr((db)->get((db),db_str2key(k))) ) +#define db_get(db,k) ( DB->data2ptr((db)->get((db),(k))) ) +#define idb_get(db,k) ( DB->data2ptr((db)->get((db),DB->i2key(k))) ) +#define uidb_get(db,k) ( DB->data2ptr((db)->get((db),DB->ui2key(k))) ) +#define strdb_get(db,k) ( DB->data2ptr((db)->get((db),DB->str2key(k))) ) // Get int-type data from DBMaps of various key types -#define db_iget(db,k) ( db_data2i((db)->get((db),(k))) ) -#define idb_iget(db,k) ( db_data2i((db)->get((db),db_i2key(k))) ) -#define uidb_iget(db,k) ( db_data2i((db)->get((db),db_ui2key(k))) ) -#define strdb_iget(db,k) ( db_data2i((db)->get((db),db_str2key(k))) ) +#define db_iget(db,k) ( DB->data2i((db)->get((db),(k))) ) +#define idb_iget(db,k) ( DB->data2i((db)->get((db),DB->i2key(k))) ) +#define uidb_iget(db,k) ( DB->data2i((db)->get((db),DB->ui2key(k))) ) +#define strdb_iget(db,k) ( DB->data2i((db)->get((db),DB->str2key(k))) ) // Get uint-type data from DBMaps of various key types -#define db_uiget(db,k) ( db_data2ui((db)->get((db),(k))) ) -#define idb_uiget(db,k) ( db_data2ui((db)->get((db),db_i2key(k))) ) -#define uidb_uiget(db,k) ( db_data2ui((db)->get((db),db_ui2key(k))) ) -#define strdb_uiget(db,k) ( db_data2ui((db)->get((db),db_str2key(k))) ) +#define db_uiget(db,k) ( DB->data2ui((db)->get((db),(k))) ) +#define idb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->i2key(k))) ) +#define uidb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->ui2key(k))) ) +#define strdb_uiget(db,k) ( DB->data2ui((db)->get((db),DB->str2key(k))) ) // Put pointer-type data into DBMaps of various key types -#define db_put(db,k,d) ( (db)->put((db),(k),db_ptr2data(d),NULL) ) -#define idb_put(db,k,d) ( (db)->put((db),db_i2key(k),db_ptr2data(d),NULL) ) -#define uidb_put(db,k,d) ( (db)->put((db),db_ui2key(k),db_ptr2data(d),NULL) ) -#define strdb_put(db,k,d) ( (db)->put((db),db_str2key(k),db_ptr2data(d),NULL) ) +#define db_put(db,k,d) ( (db)->put((db),(k),DB->ptr2data(d),NULL) ) +#define idb_put(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ptr2data(d),NULL) ) +#define uidb_put(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ptr2data(d),NULL) ) +#define strdb_put(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ptr2data(d),NULL) ) // Put int-type data into DBMaps of various key types -#define db_iput(db,k,d) ( (db)->put((db),(k),db_i2data(d),NULL) ) -#define idb_iput(db,k,d) ( (db)->put((db),db_i2key(k),db_i2data(d),NULL) ) -#define uidb_iput(db,k,d) ( (db)->put((db),db_ui2key(k),db_i2data(d),NULL) ) -#define strdb_iput(db,k,d) ( (db)->put((db),db_str2key(k),db_i2data(d),NULL) ) +#define db_iput(db,k,d) ( (db)->put((db),(k),DB->i2data(d),NULL) ) +#define idb_iput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->i2data(d),NULL) ) +#define uidb_iput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->i2data(d),NULL) ) +#define strdb_iput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->i2data(d),NULL) ) // Put uint-type data into DBMaps of various key types -#define db_uiput(db,k,d) ( (db)->put((db),(k),db_ui2data(d),NULL) ) -#define idb_uiput(db,k,d) ( (db)->put((db),db_i2key(k),db_ui2data(d),NULL) ) -#define uidb_uiput(db,k,d) ( (db)->put((db),db_ui2key(k),db_ui2data(d),NULL) ) -#define strdb_uiput(db,k,d) ( (db)->put((db),db_str2key(k),db_ui2data(d),NULL) ) +#define db_uiput(db,k,d) ( (db)->put((db),(k),DB->ui2data(d),NULL) ) +#define idb_uiput(db,k,d) ( (db)->put((db),DB->i2key(k),DB->ui2data(d),NULL) ) +#define uidb_uiput(db,k,d) ( (db)->put((db),DB->ui2key(k),DB->ui2data(d),NULL) ) +#define strdb_uiput(db,k,d) ( (db)->put((db),DB->str2key(k),DB->ui2data(d),NULL) ) // Remove entry from DBMaps of various key types #define db_remove(db,k) ( (db)->remove((db),(k),NULL) ) -#define idb_remove(db,k) ( (db)->remove((db),db_i2key(k),NULL) ) -#define uidb_remove(db,k) ( (db)->remove((db),db_ui2key(k),NULL) ) -#define strdb_remove(db,k) ( (db)->remove((db),db_str2key(k),NULL) ) +#define idb_remove(db,k) ( (db)->remove((db),DB->i2key(k),NULL) ) +#define uidb_remove(db,k) ( (db)->remove((db),DB->ui2key(k),NULL) ) +#define strdb_remove(db,k) ( (db)->remove((db),DB->str2key(k),NULL) ) //These are discarding the possible vargs you could send to the function, so those //that require vargs must not use these defines. -#define db_ensure(db,k,f) ( db_data2ptr((db)->ensure((db),(k),(f))) ) -#define idb_ensure(db,k,f) ( db_data2ptr((db)->ensure((db),db_i2key(k),(f))) ) -#define uidb_ensure(db,k,f) ( db_data2ptr((db)->ensure((db),db_ui2key(k),(f))) ) -#define strdb_ensure(db,k,f) ( db_data2ptr((db)->ensure((db),db_str2key(k),(f))) ) +#define db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),(k),(f))) ) +#define idb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->i2key(k),(f))) ) +#define uidb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->ui2key(k),(f))) ) +#define strdb_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->str2key(k),(f))) ) // Database creation and destruction macros -#define idb_alloc(opt) db_alloc(__FILE__,__LINE__,DB_INT,(opt),sizeof(int)) -#define uidb_alloc(opt) db_alloc(__FILE__,__LINE__,DB_UINT,(opt),sizeof(unsigned int)) -#define strdb_alloc(opt,maxlen) db_alloc(__FILE__,__LINE__,DB_STRING,(opt),(maxlen)) -#define stridb_alloc(opt,maxlen) db_alloc(__FILE__,__LINE__,DB_ISTRING,(opt),(maxlen)) +#define idb_alloc(opt) DB->alloc(__FILE__,__LINE__,DB_INT,(opt),sizeof(int)) +#define uidb_alloc(opt) DB->alloc(__FILE__,__LINE__,DB_UINT,(opt),sizeof(unsigned int)) +#define strdb_alloc(opt,maxlen) DB->alloc(__FILE__,__LINE__,DB_STRING,(opt),(maxlen)) +#define stridb_alloc(opt,maxlen) DB->alloc(__FILE__,__LINE__,DB_ISTRING,(opt),(maxlen)) #define db_destroy(db) ( (db)->destroy((db),NULL) ) // Other macros #define db_clear(db) ( (db)->clear(db,NULL) ) #define db_size(db) ( (db)->size(db) ) #define db_iterator(db) ( (db)->iterator(db) ) -#define dbi_first(dbi) ( db_data2ptr((dbi)->first(dbi,NULL)) ) -#define dbi_last(dbi) ( db_data2ptr((dbi)->last(dbi,NULL)) ) -#define dbi_next(dbi) ( db_data2ptr((dbi)->next(dbi,NULL)) ) -#define dbi_prev(dbi) ( db_data2ptr((dbi)->prev(dbi,NULL)) ) +#define dbi_first(dbi) ( DB->data2ptr((dbi)->first(dbi,NULL)) ) +#define dbi_last(dbi) ( DB->data2ptr((dbi)->last(dbi,NULL)) ) +#define dbi_next(dbi) ( DB->data2ptr((dbi)->next(dbi,NULL)) ) +#define dbi_prev(dbi) ( DB->data2ptr((dbi)->prev(dbi,NULL)) ) #define dbi_remove(dbi) ( (dbi)->remove(dbi,NULL) ) #define dbi_exists(dbi) ( (dbi)->exists(dbi) ) #define dbi_destroy(dbi) ( (dbi)->destroy(dbi) ) @@ -692,6 +692,7 @@ struct DBMap { * db_final - Finalizes the database system. * \*****************************************************************************/ +struct db_interface { /** * Returns the fixed options according to the database type. * Sets required options and unsets unsupported options. @@ -704,7 +705,7 @@ struct DBMap { * @see #DBOptions * @see #db_default_release(DBType,DBOptions) */ -DBOptions db_fix_options(DBType type, DBOptions options); +DBOptions (*fix_options) (DBType type, DBOptions options); /** * Returns the default comparator for the type of database. @@ -714,7 +715,7 @@ DBOptions db_fix_options(DBType type, DBOptions options); * @see #DBType * @see #DBComparator */ -DBComparator db_default_cmp(DBType type); +DBComparator (*default_cmp) (DBType type); /** * Returns the default hasher for the specified type of database. @@ -724,7 +725,7 @@ DBComparator db_default_cmp(DBType type); * @see #DBType * @see #DBHasher */ -DBHasher db_default_hash(DBType type); +DBHasher (*default_hash) (DBType type); /** * Returns the default releaser for the specified type of database with the @@ -741,7 +742,7 @@ DBHasher db_default_hash(DBType type); * @see #db_fix_options(DBType,DBOptions) * @see #db_custom_release(DBRelease) */ -DBReleaser db_default_release(DBType type, DBOptions options); +DBReleaser (*default_release) (DBType type, DBOptions options); /** * Returns the releaser that behaves as <code>which</code> specifies. @@ -752,7 +753,7 @@ DBReleaser db_default_release(DBType type, DBOptions options); * @see #DBReleaser * @see #db_default_release(DBType,DBOptions) */ -DBReleaser db_custom_release(DBRelease which); +DBReleaser (*custom_release) (DBRelease which); /** * Allocate a new database of the specified type. @@ -775,7 +776,7 @@ DBReleaser db_custom_release(DBRelease which); * @see #db_default_release(DBType,DBOptions) * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); +DBMap* (*alloc) (const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); /** * Manual cast from 'int' to the union DBKey. @@ -783,7 +784,7 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi * @return The key as a DBKey union * @public */ -DBKey db_i2key(int key); +DBKey (*i2key) (int key); /** * Manual cast from 'unsigned int' to the union DBKey. @@ -791,7 +792,7 @@ DBKey db_i2key(int key); * @return The key as a DBKey union * @public */ -DBKey db_ui2key(unsigned int key); +DBKey (*ui2key) (unsigned int key); /** * Manual cast from 'unsigned char *' to the union DBKey. @@ -799,7 +800,7 @@ DBKey db_ui2key(unsigned int key); * @return The key as a DBKey union * @public */ -DBKey db_str2key(const char *key); +DBKey (*str2key) (const char *key); /** * Manual cast from 'int' to the struct DBData. @@ -807,7 +808,7 @@ DBKey db_str2key(const char *key); * @return The data as a DBData struct * @public */ -DBData db_i2data(int data); +DBData (*i2data) (int data); /** * Manual cast from 'unsigned int' to the struct DBData. @@ -815,7 +816,7 @@ DBData db_i2data(int data); * @return The data as a DBData struct * @public */ -DBData db_ui2data(unsigned int data); +DBData (*ui2data) (unsigned int data); /** * Manual cast from 'void *' to the struct DBData. @@ -823,7 +824,7 @@ DBData db_ui2data(unsigned int data); * @return The data as a DBData struct * @public */ -DBData db_ptr2data(void *data); +DBData (*ptr2data) (void *data); /** * Gets int type data from struct DBData. @@ -832,7 +833,7 @@ DBData db_ptr2data(void *data); * @return Integer value of the data. * @public */ -int db_data2i(DBData *data); +int (*data2i) (DBData *data); /** * Gets unsigned int type data from struct DBData. @@ -841,7 +842,7 @@ int db_data2i(DBData *data); * @return Unsigned int value of the data. * @public */ -unsigned int db_data2ui(DBData *data); +unsigned int (*data2ui) (DBData *data); /** * Gets void* type data from struct DBData. @@ -850,14 +851,14 @@ unsigned int db_data2ui(DBData *data); * @return Void* value of the data. * @public */ -void* db_data2ptr(DBData *data); +void* (*data2ptr) (DBData *data); /** * Initialize the database system. * @public * @see #db_final(void) */ -void db_init(void); +void (*init) (void); /** * Finalize the database system. @@ -865,8 +866,12 @@ void db_init(void); * @public * @see #db_init(void) */ -void db_final(void); +void (*final) (void); +} DB_s; +struct db_interface *DB; + +void db_defaults(void); // Link DB System - From jAthena struct linkdb_node { struct linkdb_node *next; diff --git a/src/common/ers.c b/src/common/ers.c index b94b0888d..13e54b393 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -1,7 +1,7 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams /*****************************************************************************\ - * Copyright (c) Athena Dev Teams - Licensed under GNU GPL * - * For more information, see LICENCE in the main folder * - * * * <H1>Entry Reusage System</H1> * * * * There are several root entry managers, each with a different entry size. * @@ -48,8 +48,7 @@ #ifndef DISABLE_ERS -#define ERS_ROOT_SIZE 256 -#define ERS_BLOCK_ENTRIES 4096 +#define ERS_BLOCK_ENTRIES 2048 struct ers_list { @@ -278,7 +277,16 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options) void ers_report(void) { - // FIXME: Someone use this? Is it really needed? + ers_cache_t *cache; + int i = 0; + for (cache = CacheList; cache; cache = cache->Next) { + ShowMessage(CL_BOLD"[Entry manager #%u report]\n"CL_NORMAL, ++i); + ShowMessage("\tinstances : %u\n", cache->ReferenceCount); + ShowMessage("\tblock array size : %u\n", cache->ObjectSize); + ShowMessage("\tallocated blocks : %u\n", cache->Free+cache->Used); + ShowMessage("\tentries being used : %u\n", cache->Used); + ShowMessage("\tunused entries : %u\n", cache->Free); + } } void ers_force_destroy_all(void) diff --git a/src/common/grfio.c b/src/common/grfio.c index 8f430cfb9..bf66dba52 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/des.h" @@ -250,8 +251,12 @@ int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned /// zlib compress -int encode_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) { + if( *destLen == 0 ) /* [Ind/Hercules] */ + *destLen = compressBound(sourceLen); + if( dest == NULL ) { /* [Ind/Hercules] */ + CREATE(dest, unsigned char, *destLen); + } return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); } @@ -393,12 +398,12 @@ void* grfio_reads(const char* fname, int* size) FILELIST* entry = filelist_find(fname); if( entry == NULL || entry->gentry <= 0 ) {// LocalFileCheck char lfname[256]; - int declen; FILE* in; grfio_localpath_create(lfname, sizeof(lfname), ( entry && entry->fnd ) ? entry->fnd : fname); in = fopen(lfname, "rb"); if( in != NULL ) { + int declen; fseek(in,0,SEEK_END); declen = ftell(in); fseek(in,0,SEEK_SET); @@ -475,14 +480,14 @@ static char* decode_filename(unsigned char* buf, int len) /// @return true if the file should undergo full mode 0 decryption, and true otherwise. static bool isFullEncrypt(const char* fname) { - static const char extensions[4][5] = { ".gnd", ".gat", ".act", ".str" }; - size_t i; - const char* ext = strrchr(fname, '.'); - if( ext != NULL ) + 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 ) return false; + } return true; } @@ -492,7 +497,7 @@ static bool isFullEncrypt(const char* fname) /// @param gentry index of the grf file name in the gentry_table static int grfio_entryread(const char* grfname, int gentry) { - long grf_size,list_size; + long grf_size; unsigned char grf_header[0x2e]; int entry,entrys,ofs,grf_version; unsigned char *grf_filelist; @@ -518,6 +523,7 @@ static int grfio_entryread(const char* grfname, int gentry) grf_version = getlong(grf_header+0x2a) >> 8; if( grf_version == 0x01 ) {// ****** Grf version 01xx ****** + long list_size; list_size = grf_size - ftell(fp); grf_filelist = (unsigned char *) aMalloc(list_size); if(fread(grf_filelist,1,list_size,fp) != list_size) { ShowError("Couldn't read all grf_filelist element of %s \n", grfname); } @@ -678,7 +684,7 @@ static bool grfio_parse_restable_row(const char* row) static void grfio_resourcecheck(void) { char restable[256]; - char *ptr, *buf; + char *buf; int size; FILE* fp; int i = 0; @@ -705,6 +711,7 @@ static void grfio_resourcecheck(void) buf = (char *)grfio_reads("data\\resnametable.txt", &size); if( buf != NULL ) { + char *ptr; buf[size] = '\0'; ptr = buf; diff --git a/src/common/malloc.c b/src/common/malloc.c index 9976a28d5..77eef2508 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/malloc.h" #include "../common/core.h" @@ -129,49 +130,49 @@ void aFree_(void *p, const char *file, int line, const char *func) /* USE_MEMMGR */ /* - * ƒƒ‚ƒŠƒ}ƒl[ƒWƒƒ - * malloc , free ‚̈—‚ðŒø—¦“I‚Éo—ˆ‚é‚悤‚É‚µ‚½‚à‚ÌB - * •¡ŽG‚Ȉ—‚ðs‚Á‚Ä‚¢‚é‚Ì‚ÅAŽáŠ±d‚‚È‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB - * - * ƒf[ƒ^\‘¢‚È‚Çià–¾‰ºŽè‚Å‚·‚¢‚Ü‚¹‚ñ^^; j - * Eƒƒ‚ƒŠ‚ð•¡”‚ÌuƒuƒƒbƒNv‚É•ª‚¯‚ÄA‚³‚ç‚ɃuƒƒbƒN‚ð•¡”‚Ìuƒ†ƒjƒbƒgv - * ‚É•ª‚¯‚Ä‚¢‚Ü‚·Bƒ†ƒjƒbƒg‚̃TƒCƒY‚ÍA‚PƒuƒƒbƒN‚Ì—e—Ê‚ð•¡”ŒÂ‚É‹Ï“™”z•ª - * ‚µ‚½‚à‚Ì‚Å‚·B‚½‚Æ‚¦‚ÎA‚Pƒ†ƒjƒbƒg32KB‚Ìê‡AƒuƒƒbƒN‚P‚‚Í32Byte‚̃† - * ƒjƒbƒg‚ªA1024ŒÂW‚Ü‚Á‚Äo—ˆ‚Ä‚¢‚½‚èA64Byte‚̃†ƒjƒbƒg‚ª 512ŒÂW‚Ü‚Á‚Ä - * o—ˆ‚Ä‚¢‚½‚肵‚Ü‚·Bipadding,unit_head ‚ðœ‚j - * - * EƒuƒƒbƒN“¯Žm‚̓Šƒ“ƒNƒŠƒXƒg(block_prev,block_next) ‚ł‚Ȃª‚èA“¯‚¶ƒTƒC - * ƒY‚ðŽ‚ƒuƒƒbƒN“¯Žm‚àƒŠƒ“ƒNƒŠƒXƒg(hash_prev,hash_nect) ‚Å‚Â‚È - * ‚ª‚Á‚Ä‚¢‚Ü‚·B‚»‚ê‚É‚æ‚èA•s—v‚Æ‚È‚Á‚½ƒƒ‚ƒŠ‚ÌÄ—˜—p‚ªŒø—¦“I‚És‚¦‚Ü‚·B - */ - -/* ƒuƒƒbƒN‚̃Aƒ‰ƒCƒƒ“ƒg */ +* Memory manager +* able to handle malloc and free efficiently +* Since the complex processing, I might be slightly heavier. +* +* (I'm sorry for the poor description ^ ^;) such as data structures +* Divided into "blocks" of a plurality of memory, "unit" of a plurality of blocks further +* I have to divide. Size of the unit, a plurality of distribution equal to the capacity of one block +* That's what you have. For example, if one unit of 32KB, one block 1 Yu 32Byte +* Knit, or are able to gather 1024, gathered 512 units 64Byte +* I can be or have. (Excluding padding, the unit_head) +* +* Lead-linked list (block_prev, block_next) in each other is the same size block +* Linked list (hash_prev, hash_nect) even among such one in the block with the figure +* I like to have. Thus, reuse of memory no longer needed can be performed efficiently. +*/ + +/* Alignment of the block */ #define BLOCK_ALIGNMENT1 16 #define BLOCK_ALIGNMENT2 64 -/* ƒuƒƒbƒN‚É“ü‚éƒf[ƒ^—Ê */ +/* Amount of data entering a block */ #define BLOCK_DATA_COUNT1 128 #define BLOCK_DATA_COUNT2 608 -/* ƒuƒƒbƒN‚Ì‘å‚«‚³: 16*128 + 64*576 = 40KB */ +/* The size of the block: 16*128 + 64*576 = 40KB */ #define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) #define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) #define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) -/* ˆê“x‚ÉŠm•Û‚·‚éƒuƒƒbƒN‚Ì”B */ +/* The number of blocks to be allocated at a time. */ #define BLOCK_ALLOC 104 -/* ƒuƒƒbƒN */ +/* block */ struct block { - struct block* block_next; /* ŽŸ‚ÉŠm•Û‚µ‚½—̈æ */ - struct block* unfill_prev; /* ŽŸ‚Ì–„‚Ü‚Á‚Ä‚¢‚È‚¢—̈æ */ - struct block* unfill_next; /* ŽŸ‚Ì–„‚Ü‚Á‚Ä‚¢‚È‚¢—̈æ */ - unsigned short unit_size; /* ƒ†ƒjƒbƒg‚Ì‘å‚«‚³ */ - unsigned short unit_hash; /* ƒ†ƒjƒbƒg‚̃nƒbƒVƒ… */ - unsigned short unit_count; /* ƒ†ƒjƒbƒg‚̌” */ - unsigned short unit_used; /* Žg—pƒ†ƒjƒbƒg” */ - unsigned short unit_unfill; /* –¢Žg—pƒ†ƒjƒbƒg‚ÌêŠ */ - unsigned short unit_maxused; /* Žg—pƒ†ƒjƒbƒg‚ÌÅ‘å’l */ + struct block* block_next; /* Then the allocated area */ + struct block* unfill_prev; /* The previous area not filled */ + struct block* unfill_next; /* The next area not filled */ + unsigned short unit_size; /* The size of the unit */ + unsigned short unit_hash; /* The hash of the unit */ + unsigned short unit_count; /* The number of units */ + unsigned short unit_used; /* The number of used units */ + unsigned short unit_unfill; /* The number of unused units */ + unsigned short unit_maxused; /* The maximum value of units used */ char data[ BLOCK_DATA_SIZE ]; }; @@ -186,7 +187,7 @@ struct unit_head { static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; static struct block* block_first, *block_last, block_head; -/* ƒƒ‚ƒŠ‚ðŽg‚¢‰ñ‚¹‚È‚¢—̈æ—p‚̃f[ƒ^ */ +/* Data for areas that do not use the memory be turned */ struct unit_head_large { size_t size; struct unit_head_large* prev; @@ -209,9 +210,9 @@ static unsigned short size2hash( size_t size ) return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; } else if( size <= BLOCK_DATA_SIZE ){ return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 - + BLOCK_DATA_COUNT1; + + BLOCK_DATA_COUNT1; } else { - return 0xffff; // ƒuƒƒbƒN’·‚ð’´‚¦‚éê‡‚Í hash ‚É‚µ‚È‚¢ + return 0xffff; // If it exceeds the block length hash I do not } } @@ -234,14 +235,14 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) ShowError("_mmalloc: %d\n", size); return NULL; } - + if(size == 0) { return NULL; } memmgr_usage_bytes += size; - /* ƒuƒƒbƒN’·‚ð’´‚¦‚é—̈æ‚ÌŠm•Û‚É‚ÍAmalloc() ‚ð—p‚¢‚é */ - /* ‚»‚ÌÛAunit_head.block ‚É NULL ‚ð‘ã“ü‚µ‚Ä‹æ•Ê‚·‚é */ + /* To ensure the area that exceeds the length of the block, using malloc () to */ + /* At that time, the distinction by assigning NULL to unit_head.block */ if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); if(p != NULL) { @@ -266,7 +267,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) } } - /* “¯ˆêƒTƒCƒY‚̃uƒƒbƒN‚ªŠm•Û‚³‚ê‚Ä‚¢‚È‚¢ŽžAV‚½‚ÉŠm•Û‚·‚é */ + /* When a block of the same size is not ensured, to ensure a new */ if(hash_unfill[size_hash]) { block = hash_unfill[size_hash]; } else { @@ -274,7 +275,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) } if( block->unit_unfill == 0xFFFF ) { - // freeςݗ̈悪Žc‚Á‚Ä‚¢‚È‚¢ + // there are no more free space that memmgr_assert(block->unit_used < block->unit_count); memmgr_assert(block->unit_used == block->unit_maxused); head = block2unit(block, block->unit_maxused); @@ -287,7 +288,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) } if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { - // ƒ†ƒjƒbƒg‚ðŽg‚¢‰Ê‚½‚µ‚½‚Ì‚ÅAunfillƒŠƒXƒg‚©‚çíœ + // Since I ran out of the unit, removed from the list unfill if( block->unfill_prev == &block_head) { hash_unfill[ size_hash ] = block->unfill_next; } else { @@ -331,7 +332,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) { - void *p = _mmalloc(num * size,file,line,func); + void *p = malloclib->malloc(num * size,file,line,func); memset(p,0,num * size); return p; } @@ -340,7 +341,7 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c { size_t old_size; if(memblock == NULL) { - return _mmalloc(size,file,line,func); + return malloclib->malloc(size,file,line,func); } old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; @@ -348,15 +349,15 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; } if(old_size > size) { - // ƒTƒCƒYk¬ -> ‚»‚Ì‚Ü‚Ü•Ô‚·iŽè”²‚«j + // Size reduction - return> as it is (negligence) return memblock; } else { - // ƒTƒCƒYŠg‘å - void *p = _mmalloc(size,file,line,func); + // Size Large + void *p = malloclib->malloc(size,file,line,func); if(p != NULL) { memcpy(p,memblock,old_size); } - _mfree(memblock,file,line,func); + malloclib->free(memblock,file,line,func); return p; } } @@ -367,7 +368,7 @@ char* _mstrdup(const char *p, const char *file, int line, const char *func ) return NULL; } else { size_t len = strlen(p); - char *string = (char *)_mmalloc(len + 1,file,line,func); + char *string = (char *)malloclib->malloc(len + 1,file,line,func); memcpy(string,p,len+1); return string; } @@ -382,7 +383,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); if(head->size == 0) { - /* malloc() ‚Å’¼‚ÉŠm•Û‚³‚ꂽ—̈æ */ + /* area that is directly secured by malloc () */ struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); if( *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) @@ -407,7 +408,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) FREE(head_large,file,line,func); } } else { - /* ƒ†ƒjƒbƒg‰ð•ú */ + /* Release unit */ struct block *block = head->block; if( (char*)head - (char*)block > sizeof(struct block) ) { ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); @@ -425,11 +426,11 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) #endif memmgr_assert( block->unit_used > 0 ); if(--block->unit_used == 0) { - /* ƒuƒƒbƒN‚̉ð•ú */ + /* Release of the block */ block_free(block); } else { if( block->unfill_prev == NULL) { - // unfill ƒŠƒXƒg‚ɒljÁ + // add to unfill list if( hash_unfill[ block->unit_hash ] ) { hash_unfill[ block->unit_hash ]->unfill_prev = block; } @@ -444,17 +445,17 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) } } -/* ƒuƒƒbƒN‚ðŠm•Û‚·‚é */ +/* Allocating blocks */ static struct block* block_malloc(unsigned short hash) { int i; struct block *p; if(hash_unfill[0] != NULL) { - /* ƒuƒƒbƒN—p‚̗̈æ‚ÍŠm•ÛÏ‚Ý */ + /* Space for the block has already been secured */ p = hash_unfill[0]; hash_unfill[0] = hash_unfill[0]->unfill_next; } else { - /* ƒuƒƒbƒN—p‚̗̈æ‚ðV‚½‚ÉŠm•Û‚·‚é */ + /* Newly allocated space for the block */ p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); if(p == NULL) { ShowFatalError("Memory manager::block_alloc failed.\n"); @@ -462,17 +463,17 @@ static struct block* block_malloc(unsigned short hash) } if(block_first == NULL) { - /* ‰‰ñŠm•Û */ + /* First ensure */ block_first = p; } else { block_last->block_next = p; } block_last = &p[BLOCK_ALLOC - 1]; block_last->block_next = NULL; - /* ƒuƒƒbƒN‚ð˜AŒ‹‚³‚¹‚é */ + /* Linking the block */ for(i=0;i<BLOCK_ALLOC;i++) { if(i != 0) { - // p[0] ‚Í‚±‚ê‚©‚çŽg‚¤‚̂ŃŠƒ“ƒN‚ɂ͉Á‚¦‚È‚¢ + // I do not add the link p [0], so we will use p[i].unfill_next = hash_unfill[0]; hash_unfill[0] = &p[i]; p[i].unfill_prev = NULL; @@ -484,7 +485,7 @@ static struct block* block_malloc(unsigned short hash) } } - // unfill ‚ɒljÁ + // Add to unfill memmgr_assert(hash_unfill[ hash ] == NULL); hash_unfill[ hash ] = p; p->unfill_prev = &block_head; @@ -530,18 +531,20 @@ static FILE *log_fp; static void memmgr_log (char *buf) { - if( !log_fp ) - { + if( !log_fp ) { time_t raw; struct tm* t; + const char* svn = get_svn_revision(); + const char* git = get_git_hash(); log_fp = fopen(memmer_logfile,"at"); if (!log_fp) log_fp = stdout; time(&raw); t = localtime(&raw); - fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", - (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (rev %s).\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, + git[0] != HERC_UNKNOWN_VER ? git : svn[0] != HERC_UNKNOWN_VER ? svn : "Unknown"); } fprintf(log_fp, "%s", buf); return; @@ -618,7 +621,7 @@ static void memmgr_final (void) memmgr_log (buf); #endif /* LOG_MEMMGR */ // get block pointer and free it [celest] - _mfree(ptr, ALC_MARK); + malloclib->free(ptr, ALC_MARK); } } } @@ -660,9 +663,9 @@ static void memmgr_init (void) /*====================================== - * Initialise - *-------------------------------------- - */ +* Initialise +*-------------------------------------- +*/ /// Tests the memory for errors and memory leaks. @@ -716,3 +719,28 @@ void malloc_init (void) memmgr_init (); #endif } + +void malloc_defaults() +{ + malloclib = &malloclib_s; + malloclib->init = malloc_init; + malloclib->final = malloc_final; + malloclib->memory_check = malloc_memory_check; + malloclib->usage = malloc_usage; + malloclib->verify_ptr = malloc_verify_ptr; + +// Athena's built-in Memory Manager +#ifdef USE_MEMMGR + malloclib->malloc = _mmalloc; + malloclib->calloc = _mcalloc; + malloclib->realloc = _mrealloc; + malloclib->strdup = _mstrdup; + malloclib->free = _mfree; +#else + malloclib->malloc = aMalloc_; + malloclib->calloc = aCalloc_; + malloclib->realloc = aRealloc_; + malloclib->strdup = aStrdup_; + malloclib->free = aFree_; +#endif +} diff --git a/src/common/malloc.h b/src/common/malloc.h index 6b4e8e5c4..2e745481f 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -22,9 +22,6 @@ ////////////////////////////////////////////////////////////////////// -// Athena's built-in Memory Manager -#ifdef USE_MEMMGR - // Enable memory manager logging by default #define LOG_MEMMGR @@ -33,46 +30,24 @@ #undef LOG_MEMMGR #endif -# define aMalloc(n) _mmalloc(n,ALC_MARK) -# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) -# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) -# define aStrdup(p) _mstrdup(p,ALC_MARK) -# define aFree(p) _mfree(p,ALC_MARK) - - void* _mmalloc (size_t size, const char *file, int line, const char *func); - void* _mcalloc (size_t num, size_t size, const char *file, int line, const char *func); - void* _mrealloc (void *p, size_t size, const char *file, int line, const char *func); - char* _mstrdup (const char *p, const char *file, int line, const char *func); - void _mfree (void *p, const char *file, int line, const char *func); - -#else - -# define aMalloc(n) aMalloc_((n),ALC_MARK) -# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) -# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) -# define aStrdup(p) aStrdup_(p,ALC_MARK) -# define aFree(p) aFree_(p,ALC_MARK) - - void* aMalloc_ (size_t size, const char *file, int line, const char *func); - void* aCalloc_ (size_t num, size_t size, const char *file, int line, const char *func); - void* aRealloc_ (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); - void aFree_ (void *p, const char *file, int line, const char *func); - -#endif +# define aMalloc(n) malloclib->malloc (n,ALC_MARK) +# define aCalloc(m,n) malloclib->calloc (m,n,ALC_MARK) +# define aRealloc(p,n) malloclib->realloc (p,n,ALC_MARK) +# define aStrdup(p) malloclib->strdup (p,ALC_MARK) +# define aFree(p) malloclib->free (p,ALC_MARK) /////////////// Buffer Creation ///////////////// // Full credit for this goes to Shinomori [Ajarn] #ifdef __GNUC__ // GCC has variable length arrays - #define CREATE_BUFFER(name, type, size) type name[size] - #define DELETE_BUFFER(name) +#define CREATE_BUFFER(name, type, size) type name[size] +#define DELETE_BUFFER(name) #else // others don't, so we emulate them - #define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) - #define DELETE_BUFFER(name) aFree(name) +#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) +#define DELETE_BUFFER(name) aFree(name) #endif @@ -83,10 +58,27 @@ //////////////////////////////////////////////// -void malloc_memory_check(void); -bool malloc_verify_ptr(void* ptr); -size_t malloc_usage (void); -void malloc_init (void); -void malloc_final (void); - +//void malloc_memory_check(void); +//bool malloc_verify_ptr(void* ptr); +//size_t malloc_usage (void); +//void malloc_init (void); +//void malloc_final (void); + +void malloc_defaults(void); + +struct malloc_interface { + void* (*malloc )(size_t size, const char *file, int line, const char *func); + void* (*calloc )(size_t num, size_t size, const char *file, int line, const char *func); + void* (*realloc )(void *p, size_t size, const char *file, int line, const char *func); + char* (*strdup )(const char *p, const char *file, int line, const char *func); + void (*free ) (void *p, const char *file, int line, const char *func); + + void (*memory_check)(void); + bool (*verify_ptr)(void* ptr); + size_t (*usage) (void); + void (*init) (void); + void (*final) (void); +} malloclib_s; + +struct malloc_interface *malloclib; #endif /* _MALLOC_H_ */ diff --git a/src/common/mapindex.c b/src/common/mapindex.c index d46047833..4649e299d 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -1,10 +1,12 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/mmo.h" #include "../common/showmsg.h" #include "../common/malloc.h" #include "../common/strlib.h" +#include "../common/db.h" #include "mapindex.h" #include <string.h> @@ -20,11 +22,9 @@ int max_index = 0; char mapindex_cfgfile[80] = "db/map_index.txt"; #define mapindex_exists(id) (indexes[id].name[0] != '\0') - /// 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; @@ -37,7 +37,7 @@ const char* mapindex_getmapname(const char* string, char* output) len -= 4; // strip .gat extension len = min(len, MAP_NAME_LENGTH-1); - strncpy(dest, string, len+1); + safestrncpy(dest, string, len+1); memset(&dest[len], '\0', MAP_NAME_LENGTH-len); return dest; @@ -45,8 +45,7 @@ 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; @@ -61,7 +60,7 @@ const char* mapindex_getmapname_ext(const char* string, char* output) ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); len--; } - strncpy(dest, buf, len+1); + safestrncpy(dest, buf, len+1); if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { strcpy(&dest[len], ".gat"); @@ -75,13 +74,11 @@ const char* mapindex_getmapname_ext(const char* string, char* output) /// Adds a map to the specified index /// Returns 1 if successful, 0 oherwise -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){ - for (index = 1; index < max_index; index++) - { + for (index = 1; index < max_index; index++) { //if (strcmp(indexes[index].name,"#CLEARED#")==0) if (indexes[index].name[0] == '\0') break; @@ -105,63 +102,58 @@ int mapindex_addmap(int index, const char* name) return 0; } - if (mapindex_exists(index)) + if (mapindex_exists(index)) { ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); + strdb_remove(mapindex_db, indexes[index].name); + } safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); + strdb_iput(mapindex_db, map_name, index); if (max_index <= index) max_index = index+1; return index; } -unsigned short mapindex_name2id(const char* name) -{ - //TODO: Perhaps use a db to speed this up? [Skotlex] +unsigned short mapindex_name2id(const char* name) { int i; - char map_name[MAP_NAME_LENGTH]; + mapindex_getmapname(name, map_name); - for (i = 1; i < max_index; i++) - { - if (strcmpi(indexes[i].name,map_name)==0) - return i; - } + if( (i = strdb_iget(mapindex_db, map_name)) ) + return i; + ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); return 0; } -const char* mapindex_id2name(unsigned short id) -{ +const char* mapindex_id2name_sub(unsigned short 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.\n", id); + ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache. %s:%s:%d\n", id,file,func,line); return indexes[0].name; // dummy empty string so that the callee doesn't crash } return indexes[id].name; } -void mapindex_init(void) -{ +void mapindex_init(void) { FILE *fp; char line[1024]; int last_index = -1; int index; - char map_name[1024]; + char map_name[12]; - memset (&indexes, 0, sizeof (indexes)); - fp=fopen(mapindex_cfgfile,"r"); - if(fp==NULL){ + if( ( fp = fopen(mapindex_cfgfile,"r") ) == NULL ){ ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); exit(EXIT_FAILURE); //Server can't really run without this file. } - while(fgets(line, sizeof(line), fp)) - { + memset (&indexes, 0, sizeof (indexes)); + mapindex_db = strdb_alloc(DB_RELEASE_KEY, MAP_NAME_LENGTH); + while(fgets(line, sizeof(line), fp)) { if(line[0] == '/' && line[1] == '/') continue; - switch (sscanf(line, "%1023s\t%d", map_name, &index)) - { + switch (sscanf(line, "%12s\t%d", map_name, &index)) { case 1: //Map with no ID given, auto-assign index = last_index+1; case 2: //Map with ID given @@ -173,6 +165,10 @@ void mapindex_init(void) last_index = index; } fclose(fp); + + if( !strdb_iget(mapindex_db, MAP_DEFAULT) ) { + ShowError("mapindex_init: MAP_DEFAULT '%s' not found in cache! update mapindex.h MAP_DEFAULT var!!!\n",MAP_DEFAULT); + } } int mapindex_removemap(int index){ @@ -180,6 +176,6 @@ int mapindex_removemap(int index){ return 0; } -void mapindex_final(void) -{ +void mapindex_final(void) { + db_destroy(mapindex_db); } diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 75cb254c0..d35d9899c 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -1,9 +1,18 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _MAPINDEX_H_ #define _MAPINDEX_H_ +#include "../common/db.h" + +/* when a map index search fails, return results from what map? default:prontera */ +#define MAP_DEFAULT "prontera" +#define MAP_DEFAULT_X 150 +#define MAP_DEFAULT_Y 150 +DBMap *mapindex_db; + //File in charge of assigning a numberic ID to each map in existance for space saving when passing map info between servers. extern char mapindex_cfgfile[80]; @@ -50,7 +59,8 @@ extern char mapindex_cfgfile[80]; const char* mapindex_getmapname(const char* string, char* output); const char* mapindex_getmapname_ext(const char* string, char* output); unsigned short mapindex_name2id(const char*); -const char* mapindex_id2name(unsigned short); +#define mapindex_id2name(n) mapindex_id2name_sub(n,__FILE__, __LINE__, __func__) +const char* mapindex_id2name_sub(unsigned short,const char *file, int line, const char *func); void mapindex_init(void); void mapindex_final(void); diff --git a/src/common/mmo.h b/src/common/mmo.h index 493f87691..d45dea212 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -1,10 +1,12 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _MMO_H_ #define _MMO_H_ #include "cbasetypes.h" +#include "../common/db.h" #include <time.h> // server->client protocol version @@ -46,10 +48,12 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120410 - //#define PACKETVER 20111116 + #define PACKETVER 20120418 #endif +/// comment following line if your client is NOT ragexeRE (required because of conflicting packets in ragexe vs ragexeRE) +#define PACKETVER_RE + //Remove/Comment this line to disable sc_data saving. [Skotlex] #define ENABLE_SC_SAVING //Remove/Comment this line to disable server-side hot-key saving support [Skotlex] @@ -79,7 +83,8 @@ #define MAX_ZENY 1000000000 #define MAX_FAME 1000000000 #define MAX_CART 100 -#define MAX_SKILL 3100 +#define MAX_SKILL 1477 +#define MAX_SKILL_ID 10015 //[Ind/Hercules] max used skill id #define GLOBAL_REG_NUM 256 // max permanent character variables per char #define ACCOUNT_REG_NUM 64 // max permanent local account variables per account #define ACCOUNT_REG2_NUM 16 // max permanent global account variables per account @@ -98,8 +103,9 @@ #define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 #define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] -#define MAX_QUEST_DB 2200 //Max quests that the server will load +#define MAX_QUEST_DB 2400 //Max quests that the server will load #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] // for produce #define MIN_ATTRIBUTE 0 @@ -152,7 +158,7 @@ //Mercenary System #define MC_SKILLBASE 8201 #define MAX_MERCSKILL 40 -#define MAX_MERCENARY_CLASS 44 +#define MAX_MERCENARY_CLASS 61 //Elemental System #define MAX_ELEMENTALSKILL 42 @@ -219,6 +225,12 @@ enum e_skill_flag //... }; +enum e_mmo_charstatus_opt { + OPT_NONE = 0x0, + OPT_SHOW_EQUIP = 0x1, + OPT_ALLOW_PARTY = 0x2, +}; + struct s_skill { unsigned short id; unsigned char lv; @@ -378,8 +390,9 @@ struct mmo_charstatus { #ifdef HOTKEY_SAVING struct hotkey hotkeys[MAX_HOTKEYS]; #endif - bool show_equip; - short rename; + bool show_equip, allow_party; + unsigned short rename; + unsigned short slotchange; time_t delete_date; }; @@ -510,8 +523,10 @@ struct guild { struct guild_alliance alliance[MAX_GUILDALLIANCE]; struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; struct guild_skill skill[MAX_GUILDSKILL]; - + + /* TODO: still used for something?|: */ unsigned short save_flag; // for TXT saving + void *channel; }; struct guild_castle { diff --git a/src/common/netbuffer.c b/src/common/netbuffer.c index 57742d612..60a299aa9 100644 --- a/src/common/netbuffer.c +++ b/src/common/netbuffer.c @@ -52,10 +52,10 @@ void netbuffer_init(){ // Set localsection name according to running serverype. switch(SERVER_TYPE){ - case ATHENA_SERVER_LOGIN: strcpy(localsection, "login-netbuffer"); break; - case ATHENA_SERVER_CHAR: strcpy(localsection, "char-netbuffer"); break; - case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; - case ATHENA_SERVER_MAP: strcpy(localsection, "map-netbuffer"); break; + case SERVER_TYPE_LOGIN: strcpy(localsection, "login-netbuffer"); break; + case SERVER_TYPE_CHAR: strcpy(localsection, "char-netbuffer"); break; + //case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; + case SERVER_TYPE_MAP: strcpy(localsection, "map-netbuffer"); break; default: strcpy(localsection, "unsupported_type"); break; } diff --git a/src/common/raconf.c b/src/common/raconf.c index 2703560ff..f7d1284b7 100644 --- a/src/common/raconf.c +++ b/src/common/raconf.c @@ -41,12 +41,11 @@ struct conf_value{ static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ struct conf_value *v; - char *p; - size_t sz; +/* size_t sz; sz = sizeof(struct conf_value); if(val_len >= sizeof(v->strval)) - sz += (val_len - sizeof(v->strval) + 1); + sz += (val_len - sizeof(v->strval) + 1);*/ v = (struct conf_value*)aCalloc(1, sizeof(struct conf_value)); if(v == NULL){ @@ -106,6 +105,7 @@ static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ }else if( *val >='0' && *val <= '9'){ // begins with normal digit, so assume its dec. // is it float? bool is_float = false; + char *p; for(p = val; *p != '\0'; p++){ if(*p == '.'){ diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 609ae3c50..2a3146d35 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/strlib.h" // StringBuf @@ -77,9 +78,9 @@ int console_msg_log = 0;//[Ind] msg error logging } \ else \ {/* dynamic buffer */ \ - buf.d_ = StringBuf_Malloc(); \ - buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ - buf.v_ = StringBuf_Value(buf.d_); \ + buf.d_ = StrBuf->Malloc(); \ + buf.l_ = StrBuf->Vprintf(buf.d_, fmt, args); \ + buf.v_ = StrBuf->Value(buf.d_); \ ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ } \ //define BUFVPRINTF @@ -90,7 +91,7 @@ int console_msg_log = 0;//[Ind] msg error logging #define FREEBUF(buf) \ if( buf.d_ ) \ { \ - StringBuf_Free(buf.d_); \ + StrBuf->Free(buf.d_); \ buf.d_ = NULL; \ } \ buf.v_ = NULL; \ @@ -687,22 +688,12 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap) ShowError("Empty string passed to _vShowMessage().\n"); return 1; } - /** - * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. - **/ -#if defined(BUILDBOT) - if( flag == MSG_WARNING || - flag == MSG_ERROR || - flag == MSG_SQL ) { - buildbotflag = 1; - } -#endif if( ( flag == MSG_WARNING && console_msg_log&1 ) || ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] FILE *log = NULL; - if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { + if( (log = fopen(SERVER_TYPE == SERVER_TYPE_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { char timestring[255]; time_t curtime; time(&curtime); @@ -864,13 +855,13 @@ void ShowConfigWarning(config_setting_t *config, const char *string, ...) { StringBuf buf; va_list ap; - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, string); - StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); + StrBuf->Init(&buf); + StrBuf->AppendStr(&buf, string); + StrBuf->Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); va_start(ap, string); - _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); + _vShowMessage(MSG_WARNING, StrBuf->Value(&buf), ap); va_end(ap); - StringBuf_Destroy(&buf); + StrBuf->Destroy(&buf); } void ShowDebug(const char *string, ...) { va_list ap; diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 0d6cb5c9f..a88985770 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -1,11 +1,13 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _SHOWMSG_H_ #define _SHOWMSG_H_ -#include "libconfig.h" - +#ifndef _HPMi_H_ + #include "libconfig.h" +#endif // for help with the console colors look here: // http://www.edoceo.com/liberum/?doc=printf-with-color // some code explanation (used here): @@ -85,15 +87,17 @@ enum msg_type { }; extern void ClearScreen(void); -extern void ShowMessage(const char *, ...); -extern void ShowStatus(const char *, ...); -extern void ShowSQL(const char *, ...); -extern void ShowInfo(const char *, ...); -extern void ShowNotice(const char *, ...); -extern void ShowWarning(const char *, ...); -extern void ShowDebug(const char *, ...); -extern void ShowError(const char *, ...); -extern void ShowFatalError(const char *, ...); -extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); +#ifndef _HPMi_H_ + extern void ShowMessage(const char *, ...); + extern void ShowStatus(const char *, ...); + extern void ShowSQL(const char *, ...); + extern void ShowInfo(const char *, ...); + extern void ShowNotice(const char *, ...); + extern void ShowWarning(const char *, ...); + extern void ShowDebug(const char *, ...); + extern void ShowError(const char *, ...); + extern void ShowFatalError(const char *, ...); + extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); +#endif #endif /* _SHOWMSG_H_ */ diff --git a/src/common/socket.c b/src/common/socket.c index 6977d4257..5126d231b 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/mmo.h" @@ -812,7 +813,7 @@ int do_sockets(int next) continue; // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) - if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { + if (session[i]->rdata_size == session[i]->max_rdata) { set_eof(i); continue; } @@ -1017,14 +1018,14 @@ int access_ipmask(const char* str, AccessControl* acc) { uint32 ip; uint32 mask; - unsigned int a[4]; - unsigned int m[4]; - int n; if( strcmp(str,"all") == 0 ) { ip = 0; mask = 0; } else { + unsigned int a[4]; + unsigned int m[4]; + int n; if( ((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4 ) || // not an ip @@ -1337,7 +1338,6 @@ void socket_init(void) ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); } - bool session_isValid(int fd) { return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL ); @@ -1377,6 +1377,72 @@ uint16 ntows(uint16 netshort) return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); } +/* [Ind/Hercules] - socket_datasync */ +void socket_datasync(int fd, bool send) { + struct { + unsigned int length;/* short is not enough for some */ + } data_list[] = { + { sizeof(struct mmo_charstatus) }, + { sizeof(struct quest) }, + { sizeof(struct item) }, + { sizeof(struct point) }, + { sizeof(struct s_skill) }, + { sizeof(struct global_reg) }, + { sizeof(struct accreg) }, + { sizeof(struct status_change_data) }, + { sizeof(struct storage_data) }, + { sizeof(struct guild_storage) }, + { sizeof(struct s_pet) }, + { sizeof(struct s_mercenary) }, + { sizeof(struct s_homunculus) }, + { sizeof(struct s_elemental) }, + { sizeof(struct s_friend) }, + { sizeof(struct mail_message) }, + { sizeof(struct mail_data) }, + { sizeof(struct registry) }, + { sizeof(struct party_member) }, + { sizeof(struct party) }, + { sizeof(struct guild_member) }, + { sizeof(struct guild_position) }, + { sizeof(struct guild_alliance) }, + { sizeof(struct guild_expulsion) }, + { sizeof(struct guild_skill) }, + { sizeof(struct guild) }, + { sizeof(struct guild_castle) }, + { sizeof(struct fame_list) }, + }; + unsigned short i; + unsigned int alen = ARRAYLENGTH(data_list); + if( send ) { + unsigned short p_len = ( alen * 4 ) + 4; + WFIFOHEAD(fd, p_len); + + WFIFOW(fd, 0) = 0x2b0a; + WFIFOW(fd, 2) = p_len; + + for( i = 0; i < alen; i++ ) { + WFIFOL(fd, 4 + ( i * 4 ) ) = data_list[i].length; + } + + WFIFOSET(fd, p_len); + } else { + for( i = 0; i < alen; i++ ) { + if( RFIFOL(fd, 4 + (i * 4) ) != data_list[i].length ) { + /* force the other to go wrong too so both are taken down */ + WFIFOHEAD(fd, 8); + WFIFOW(fd, 0) = 0x2b0a; + WFIFOW(fd, 2) = 8; + WFIFOL(fd, 4) = 0; + WFIFOSET(fd, 8); + flush_fifo(fd); + /* shut down */ + ShowFatalError("Servers are out of sync! recompile from scratch (%d)\n",i); + exit(EXIT_FAILURE); + } + } + } +} + #ifdef SEND_SHORTLIST // Add a fd to the shortlist so that it'll be recognized as a fd that needs // sending or eof handling. diff --git a/src/common/socket.h b/src/common/socket.h index 7c0e02f5d..4879cb109 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -145,6 +145,9 @@ extern int naddr_; // # of ip addresses void set_eof(int fd); +/* [Ind/Hercules] - socket_datasync */ +void socket_datasync(int fd, bool send); + /// Use a shortlist of sockets instead of iterating all sessions for sockets /// that have data to send or need eof handling. /// Adapted to use a static array instead of a linked list. diff --git a/src/common/sql.c b/src/common/sql.c index 800aa89b0..391211183 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/malloc.h" @@ -15,11 +16,13 @@ #include <string.h>// strlen/strnlen/memcpy/memset #include <stdlib.h>// strtoul +void hercules_mysql_error_handler(unsigned int ecode); +int mysql_reconnect_type; +unsigned int mysql_reconnect_count; /// Sql handle -struct Sql -{ +struct Sql { StringBuf buf; MYSQL handle; MYSQL_RES* result; @@ -32,8 +35,7 @@ struct Sql // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. -struct s_column_length -{ +struct s_column_length { uint32* out_length; unsigned long length; }; @@ -42,8 +44,7 @@ typedef struct s_column_length s_column_length; /// Sql statement -struct SqlStmt -{ +struct SqlStmt { StringBuf buf; MYSQL_STMT* stmt; MYSQL_BIND* params; @@ -70,11 +71,11 @@ Sql* Sql_Malloc(void) CREATE(self, Sql, 1); mysql_init(&self->handle); - StringBuf_Init(&self->buf); + StrBuf->Init(&self->buf); self->lengths = NULL; self->result = NULL; self->keepalive = INVALID_TIMER; - + self->handle.reconnect = 1; return self; } @@ -88,7 +89,7 @@ int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* hos if( self == NULL ) return SQL_ERROR; - StringBuf_Clear(&self->buf); + StrBuf->Clear(&self->buf); if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) { ShowSQL("%s\n", mysql_error(&self->handle)); @@ -110,18 +111,16 @@ 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) { - if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) - { + if( self && out_timeout && SQL_SUCCESS == SQL->Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) { char* data; size_t len; - if( SQL_SUCCESS == Sql_NextRow(self) && - SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) - { + if( SQL_SUCCESS == SQL->NextRow(self) && + SQL_SUCCESS == SQL->GetData(self, 1, &data, &len) ) { *out_timeout = (uint32)strtoul(data, NULL, 10); - Sql_FreeResult(self); + SQL->FreeResult(self); return SQL_SUCCESS; } - Sql_FreeResult(self); + SQL->FreeResult(self); } return SQL_ERROR; } @@ -135,12 +134,11 @@ int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_l size_t len; size_t off = 0; - if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) + if( self == NULL || SQL_ERROR == SQL->Query(self, "EXPLAIN `%s`", table) ) return SQL_ERROR; out_buf[off] = '\0'; - while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) - { + while( SQL_SUCCESS == SQL->NextRow(self) && SQL_SUCCESS == SQL->GetData(self, 0, &data, &len) ) { len = strnlen(data, len); if( off + len + 2 > buf_len ) { @@ -153,7 +151,7 @@ int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_l out_buf[off++] = sep; } out_buf[off] = '\0'; - Sql_FreeResult(self); + SQL->FreeResult(self); return SQL_SUCCESS; } @@ -246,7 +244,7 @@ int Sql_Query(Sql* self, const char* query, ...) va_list args; va_start(args, query); - res = Sql_QueryV(self, query, args); + res = SQL->QueryV(self, query, args); va_end(args); return res; @@ -260,18 +258,20 @@ int Sql_QueryV(Sql* self, const char* query, va_list args) if( self == NULL ) return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + SQL->FreeResult(self); + StrBuf->Clear(&self->buf); + StrBuf->Vprintf(&self->buf, query, args); + if( mysql_real_query(&self->handle, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + hercules_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } self->result = mysql_store_result(&self->handle); if( mysql_errno(&self->handle) != 0 ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + hercules_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } return SQL_SUCCESS; @@ -285,18 +285,20 @@ int Sql_QueryStr(Sql* self, const char* query) if( self == NULL ) return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + SQL->FreeResult(self); + StrBuf->Clear(&self->buf); + StrBuf->AppendStr(&self->buf, query); + if( mysql_real_query(&self->handle, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + hercules_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } self->result = mysql_store_result(&self->handle); if( mysql_errno(&self->handle) != 0 ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + hercules_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } return SQL_SUCCESS; @@ -336,13 +338,10 @@ uint64 Sql_NumRows(Sql* self) /// Fetches the next row. -int Sql_NextRow(Sql* self) -{ - if( self && self->result ) - { +int Sql_NextRow(Sql* self) { + if( self && self->result ) { self->row = mysql_fetch_row(self->result); - if( self->row ) - { + if( self->row ) { self->lengths = mysql_fetch_lengths(self->result); return SQL_SUCCESS; } @@ -358,15 +357,11 @@ 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) { - if( self && self->row ) - { - if( col < Sql_NumColumns(self) ) - { + if( self && self->row ) { + if( col < SQL->NumColumns(self) ) { if( out_buf ) *out_buf = self->row[col]; if( out_len ) *out_len = (size_t)self->lengths[col]; - } - else - {// out of range - ignore + } else {// out of range - ignore if( out_buf ) *out_buf = NULL; if( out_len ) *out_len = 0; } @@ -378,10 +373,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) -{ - if( self && self->result ) - { +void Sql_FreeResult(Sql* self) { + if( self && self->result ) { mysql_free_result(self->result); self->result = NULL; self->row = NULL; @@ -396,8 +389,8 @@ void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug { if( self == NULL ) ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else if( StrBuf->Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StrBuf->Value(&self->buf)); else ShowDebug("at %s:%lu\n", debug_file, debug_line); } @@ -409,8 +402,8 @@ void Sql_Free(Sql* self) { if( self ) { - Sql_FreeResult(self); - StringBuf_Destroy(&self->buf); + SQL->FreeResult(self); + StrBuf->Destroy(&self->buf); if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); aFree(self); } @@ -582,8 +575,7 @@ static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) /// Allocates and initializes a new SqlStmt handle. -SqlStmt* SqlStmt_Malloc(Sql* sql) -{ +SqlStmt* SqlStmt_Malloc(Sql* sql) { SqlStmt* self; MYSQL_STMT* stmt; @@ -591,13 +583,12 @@ SqlStmt* SqlStmt_Malloc(Sql* sql) return NULL; stmt = mysql_stmt_init(&sql->handle); - if( stmt == NULL ) - { + if( stmt == NULL ) { ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); return NULL; } CREATE(self, SqlStmt, 1); - StringBuf_Init(&self->buf); + StrBuf->Init(&self->buf); self->stmt = stmt; self->params = NULL; self->columns = NULL; @@ -634,11 +625,12 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) return SQL_ERROR; SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + StrBuf->Clear(&self->buf); + StrBuf->Vprintf(&self->buf, query, args); + if( mysql_stmt_prepare(self->stmt, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + hercules_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_params = false; @@ -655,11 +647,12 @@ int SqlStmt_PrepareStr(SqlStmt* self, const char* query) return SQL_ERROR; SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + StrBuf->Clear(&self->buf); + StrBuf->AppendStr(&self->buf, query); + if( mysql_stmt_prepare(self->stmt, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + hercules_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_params = false; @@ -721,12 +714,14 @@ int SqlStmt_Execute(SqlStmt* self) mysql_stmt_execute(self->stmt) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + hercules_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_columns = false; if( mysql_stmt_store_result(self->stmt) )// store all the data { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + hercules_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } @@ -868,6 +863,7 @@ int SqlStmt_NextRow(SqlStmt* self) if( err ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + hercules_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } @@ -920,8 +916,8 @@ void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned lo { if( self == NULL ) ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else if( StrBuf->Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StrBuf->Value(&self->buf)); else ShowDebug("at %s:%lu\n", debug_file, debug_line); } @@ -934,7 +930,7 @@ void SqlStmt_Free(SqlStmt* self) if( self ) { SqlStmt_FreeResult(self); - StringBuf_Destroy(&self->buf); + StrBuf->Destroy(&self->buf); mysql_stmt_close(self->stmt); if( self->params ) aFree(self->params); @@ -946,3 +942,136 @@ 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; + switch( ecode ) { + case 2003:/* Can't connect to MySQL (this error only happens here when failing to reconnect) */ + if( mysql_reconnect_type == 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); + } + } + break; + } +} +void Sql_inter_server_read(const char* cfgName, bool first) { + int i; + 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; + } + + while(fgets(line, sizeof(line), fp)) { + i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); + if(i != 2) + continue; + + 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); + } + fclose(fp); + + return; +} + +void Sql_HerculesUpdateCheck(Sql* self) { + char line[22];// "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1 + FILE* ifp;/* index fp */ + unsigned int performed = 0; + + if( !( ifp = fopen("sql-files/upgrades/index.txt", "r") ) ) { + ShowError("SQL upgrade index was not found!\n"); + return; + } + + while(fgets(line, sizeof(line), ifp)) { + char path[41];// "sql-files/upgrades/" (19) + "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1 + char timestamp[11];// "1360186680" (10) + 1 + FILE* ufp;/* upgrade fp */ + + if( line[0] == '\n' || ( line[0] == '/' && line[1] == '/' ) )/* skip \n and "//" comments */ + continue; + + sprintf(path,"sql-files/upgrades/%s",line); + + if( !( ufp = fopen(path, "r") ) ) { + ShowError("SQL upgrade file %s was not found!\n",path); + continue; + } + + if( fgetc(ufp) != '#' ) + continue; + + fseek (ufp,1,SEEK_SET);/* woo. skip the # */ + + if( fgets(timestamp,sizeof(timestamp),ufp) ) { + unsigned int timestampui = atol(timestamp); + if( SQL_ERROR == SQL->Query(self, "SELECT 1 FROM `sql_updates` WHERE `timestamp` = '%u' LIMIT 1", timestampui) ) + Sql_ShowDebug(self); + if( Sql_NumRows(self) != 1 ) { + ShowSQL("'"CL_WHITE"%s"CL_RESET"' wasn't applied to the database\n",path); + performed++; + } + } + + fclose(ufp); + } + + fclose(ifp); + + if( performed ) { + ShowSQL("If you did apply these updates or would like to be skip, insert a new entry in your sql_updates table with the timestamp of each file\n"); + } +} + +void Sql_Init(void) { + Sql_inter_server_read("conf/inter-server.conf",true); +} +void sql_defaults(void) { + SQL = &sql_s; + + SQL->Connect = Sql_Connect; + SQL->GetTimeout = Sql_GetTimeout; + SQL->GetColumnNames = Sql_GetColumnNames; + SQL->SetEncoding = Sql_SetEncoding; + SQL->Ping = Sql_Ping; + SQL->EscapeString = Sql_EscapeString; + SQL->EscapeStringLen = Sql_EscapeStringLen; + SQL->Query = Sql_Query; + SQL->QueryV = Sql_QueryV; + SQL->QueryStr = Sql_QueryStr; + SQL->LastInsertId = Sql_LastInsertId; + SQL->NumColumns = Sql_NumColumns; + SQL->NumRows = Sql_NumRows; + SQL->NextRow = Sql_NextRow; + SQL->GetData = Sql_GetData; + SQL->FreeResult = Sql_FreeResult; + SQL->ShowDebug_ = Sql_ShowDebug_; + SQL->Free = Sql_Free; + SQL->Malloc = Sql_Malloc; +} diff --git a/src/common/sql.h b/src/common/sql.h index 898e2c778..d5a0eda2c 100644 --- a/src/common/sql.h +++ b/src/common/sql.h @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _COMMON_SQL_H_ #define _COMMON_SQL_H_ @@ -21,8 +22,7 @@ /// Data type identifier. /// String, enum and blob data types need the buffer length specified. -enum SqlDataType -{ +enum SqlDataType { SQLDT_NULL, // fixed size SQLDT_INT8, @@ -63,149 +63,96 @@ typedef enum SqlDataType SqlDataType; typedef struct Sql Sql; typedef struct SqlStmt SqlStmt; - -/// Allocates and initializes a new Sql handle. -struct Sql* Sql_Malloc(void); - - - -/// Establishes a connection. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int Sql_Connect(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 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. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetColumnNames(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 Sql_SetEncoding(Sql* self, const char* encoding); - - - -/// Pings the connection. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int Sql_Ping(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 Sql_EscapeString(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 Sql_EscapeStringLen(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 Sql_Query(Sql* self, const char* query, ...); - - - -/// Executes a query. -/// Any previous result is freed. -/// The query is constructed as if it was svprintf. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryV(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 Sql_QueryStr(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 Sql_LastInsertId(Sql* self); - - - -/// Returns the number of columns in each row of the result. -/// -/// @return Number of columns -uint32 Sql_NumColumns(Sql* self); - - - -/// Returns the number of rows in the result. -/// -/// @return Number of rows -uint64 Sql_NumRows(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 Sql_NextRow(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 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); - - +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); + /// Retrieves the timeout of the connection. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*GetTimeout) (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); + /// Changes the encoding of the connection. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*SetEncoding) (Sql* self, const char* encoding); + /// Pings the connection. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*Ping) (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); + /// 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); + /// 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, ...); + /// 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); + /// 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); + /// 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); + /// Returns the number of columns in each row of the result. + /// + /// @return Number of columns + uint32 (*NumColumns) (Sql* self); + /// Returns the number of rows in the result. + /// + /// @return Number of rows + uint64 (*NumRows) (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); + /// 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); + /// Frees the result of the query. + void (*FreeResult) (Sql* self); + /// Shows debug information (last query). + void (*ShowDebug_) (Sql* self, const char* debug_file, const unsigned long debug_line); + /// Frees a Sql handle returned by Sql_Malloc. + void (*Free) (Sql* self); + /// Allocates and initializes a new Sql handle. + struct Sql *(*Malloc) (void); +} sql_s; + +struct sql_interface *SQL; + +void sql_defaults(void); #if defined(SQL_REMOVE_SHOWDEBUG) -#define Sql_ShowDebug(self) (void)0 + #define Sql_ShowDebug(self) (void)0 #else -#define Sql_ShowDebug(self) Sql_ShowDebug_(self, __FILE__, __LINE__) + #define Sql_ShowDebug(self) SQL->ShowDebug_(self, __FILE__, __LINE__) #endif -/// Shows debug information (last query). -void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line); - - - -/// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql* self); - - /////////////////////////////////////////////////////////////////////////////// // Prepared Statements @@ -220,8 +167,6 @@ void Sql_Free(Sql* self); // 1) SELECT col FROM table WHERE id=? // 2) INSERT INTO table(col1,col2) VALUES(?,?) - - /// Allocates and initializes a new SqlStmt handle. /// It uses the connection of the parent Sql handle. /// Queries in Sql and SqlStmt are independent and don't affect each other. @@ -238,8 +183,6 @@ struct SqlStmt* SqlStmt_Malloc(Sql* sql); /// @return SQL_SUCCESS or SQL_ERROR int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); - - /// Prepares the statement. /// Any previous result is freed and all parameter bindings are removed. /// The query is constructed as if it was svprintf. @@ -324,12 +267,12 @@ int SqlStmt_NextRow(SqlStmt* self); /// Frees the result of the statement execution. void SqlStmt_FreeResult(SqlStmt* self); - +void Sql_HerculesUpdateCheck(Sql* self); #if defined(SQL_REMOVE_SHOWDEBUG) -#define SqlStmt_ShowDebug(self) (void)0 + #define SqlStmt_ShowDebug(self) (void)0 #else -#define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) + #define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (with statement). void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line); @@ -339,6 +282,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 Sql_Init(void); #endif /* _COMMON_SQL_H_ */ diff --git a/src/common/strlib.c b/src/common/strlib.c index dfacbf136..686b2e47d 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -1,9 +1,11 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/malloc.h" #include "../common/showmsg.h" +#define STRLIB_C #include "strlib.h" #include <stdio.h> @@ -14,8 +16,7 @@ #define J_MAX_MALLOC_SIZE 65535 // escapes a string in-place (' -> \' , \ -> \\ , % -> _) -char* jstrescape (char* pt) -{ +char* jstrescape (char* pt) { //copy from here char *ptr; int i = 0, j = 0; @@ -220,8 +221,7 @@ const char* stristr(const char* haystack, const char* needle) } #ifdef __WIN32 -char* _strtok_r(char *s1, const char *s2, char **lasts) -{ +char* _strtok_r(char *s1, const char *s2, char **lasts) { char *ret; if (s1 == NULL) @@ -618,8 +618,7 @@ int sv_parse_next(struct s_svstate* sv) /// @param npos Size of the pos array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) -{ +int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) { struct s_svstate sv; int count; @@ -637,8 +636,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i // parse count = 0; if( npos > 0 ) out_pos[0] = startoff; - while( !sv.done ) - { + while( !sv.done ) { ++count; if( sv_parse_next(&sv) <= 0 ) return -1;// error @@ -668,8 +666,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// @param nfields Size of the field array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) -{ +int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) { int pos[1024]; int i; int done; @@ -681,30 +678,21 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in // next line end = str + pos[1]; - if( end[0] == '\0' ) - { + if( end[0] == '\0' ) { *out_fields = end; - } - else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) - { + } else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) { if( !(opt&SV_KEEP_TERMINATOR) ) end[0] = '\0'; *out_fields = end + 1; - } - else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) - { + } else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) { if( !(opt&SV_KEEP_TERMINATOR) ) end[0] = end[1] = '\0'; *out_fields = end + 2; - } - else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) - { + } else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) { if( !(opt&SV_KEEP_TERMINATOR) ) end[0] = '\0'; *out_fields = end + 1; - } - else - { + } else { ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); return -1;// error } @@ -714,10 +702,8 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in // fields i = 2; done = 0; - while( done < ret && nfields > 0 ) - { - if( i < ARRAYLENGTH(pos) ) - {// split field + while( done < ret && nfields > 0 ) { + if( i < ARRAYLENGTH(pos) ) { // split field *out_fields = str + pos[i]; end = str + pos[i+1]; *end = '\0'; @@ -726,9 +712,7 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in ++done; ++out_fields; --nfields; - } - else - {// get more fields + } else { // get more fields sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); i = 2; } @@ -748,65 +732,59 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in /// @param len Length of the source string /// @param escapes Extra characters to be escaped /// @return Length of the escaped string -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) -{ +size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) { size_t i; size_t j; if( out_dest == NULL ) return 0;// nothing to do - if( src == NULL ) - {// nothing to escape + if( src == NULL ) { // nothing to escape *out_dest = 0; return 0; } if( escapes == NULL ) escapes = ""; - for( i = 0, j = 0; i < len; ++i ) - { - switch( src[i] ) - { - case '\0':// octal 0 - out_dest[j++] = '\\'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - break; - case '\r':// carriage return - out_dest[j++] = '\\'; - out_dest[j++] = 'r'; - break; - case '\n':// line feed - out_dest[j++] = '\\'; - out_dest[j++] = 'n'; - break; - case '\\':// escape character - out_dest[j++] = '\\'; - out_dest[j++] = '\\'; - break; - default: - if( strchr(escapes,src[i]) ) - {// escape + for( i = 0, j = 0; i < len; ++i ) { + switch( src[i] ) { + case '\0':// octal 0 out_dest[j++] = '\\'; - switch( src[i] ) - { - case '\a': out_dest[j++] = 'a'; break; - case '\b': out_dest[j++] = 'b'; break; - case '\t': out_dest[j++] = 't'; break; - case '\v': out_dest[j++] = 'v'; break; - case '\f': out_dest[j++] = 'f'; 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)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); - break; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + break; + case '\r':// carriage return + out_dest[j++] = '\\'; + out_dest[j++] = 'r'; + break; + case '\n':// line feed + out_dest[j++] = '\\'; + out_dest[j++] = 'n'; + break; + case '\\':// escape character + out_dest[j++] = '\\'; + out_dest[j++] = '\\'; + break; + default: + if( strchr(escapes,src[i]) ) {// escape + out_dest[j++] = '\\'; + switch( src[i] ) { + case '\a': out_dest[j++] = 'a'; break; + case '\b': out_dest[j++] = 'b'; break; + case '\t': out_dest[j++] = 't'; break; + case '\v': out_dest[j++] = 'v'; break; + case '\f': out_dest[j++] = 'f'; 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)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); + break; + } } - } - else - out_dest[j++] = src[i]; - break; + else + out_dest[j++] = src[i]; + break; } } out_dest[j] = 0; @@ -821,8 +799,7 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca /// @param src Source string /// @param len Length of the source string /// @return Length of the escaped string -size_t sv_unescape_c(char* out_dest, const char* src, size_t len) -{ +size_t sv_unescape_c(char* out_dest, const char* src, size_t len) { static unsigned char low2hex[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? @@ -844,71 +821,58 @@ size_t sv_unescape_c(char* out_dest, const char* src, size_t len) size_t i; size_t j; - for( i = 0, j = 0; i < len; ) - { - if( src[i] == '\\' ) - { + for( i = 0, j = 0; i < len; ) { + if( src[i] == '\\' ) { ++i;// '\\' if( i >= len ) ShowWarning("sv_unescape_c: empty escape sequence\n"); - else if( src[i] == 'x' ) - {// hex escape sequence + else if( src[i] == 'x' ) {// hex escape sequence unsigned char c = 0; unsigned char inrange = 1; ++i;// 'x' - if( i >= len || !ISXDIGIT(src[i]) ) - { + if( i >= len || !ISXDIGIT(src[i]) ) { ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); continue; } - do{ - if( c > 0x0F && inrange ) - { + do { + if( c > 0x0F && inrange ) { ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); inrange = 0; } c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit ++i; - }while( i < len && ISXDIGIT(src[i]) ); + } while( i < len && ISXDIGIT(src[i]) ); out_dest[j++] = (char)c; - } - else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) - {// octal escape sequence (255=0377) + } else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) {// octal escape sequence (255=0377) unsigned char c = src[i]-'0'; ++i;// '0', '1', '2' or '3' - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { + if( i < len && src[i] >= '0' && src[i] <= '7' ) { c = (c<<3)|(src[i]-'0'); ++i;// octal digit } - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { + if( i < len && src[i] >= '0' && src[i] <= '7' ) { c = (c<<3)|(src[i]-'0'); ++i;// octal digit } out_dest[j++] = (char)c; - } - else - {// other escape sequence + } else { // other escape sequence if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL ) ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); - switch( src[i] ) - { - case 'a': out_dest[j++] = '\a'; break; - case 'b': out_dest[j++] = '\b'; break; - case 't': out_dest[j++] = '\t'; break; - case 'n': out_dest[j++] = '\n'; break; - case 'v': out_dest[j++] = '\v'; break; - case 'f': out_dest[j++] = '\f'; break; - case 'r': out_dest[j++] = '\r'; break; - case '?': out_dest[j++] = '\?'; break; - default: out_dest[j++] = src[i]; break; + switch( src[i] ) { + case 'a': out_dest[j++] = '\a'; break; + case 'b': out_dest[j++] = '\b'; break; + case 't': out_dest[j++] = '\t'; break; + case 'n': out_dest[j++] = '\n'; break; + case 'v': out_dest[j++] = '\v'; break; + case 'f': out_dest[j++] = '\f'; break; + case 'r': out_dest[j++] = '\r'; break; + case '?': out_dest[j++] = '\?'; break; + default: out_dest[j++] = src[i]; break; } ++i;// escaped character } - } - else + } else out_dest[j++] = src[i++];// normal character } out_dest[j] = 0; @@ -916,31 +880,28 @@ size_t sv_unescape_c(char* out_dest, const char* src, size_t len) } /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p) -{ - if( p && *p == '\\' ) - { +const char* skip_escaped_c(const char* p) { + if( p && *p == '\\' ) { ++p; - switch( *p ) - { - case 'x':// hexadecimal - ++p; - while( ISXDIGIT(*p) ) - ++p; - break; - case '0': - case '1': - case '2': - case '3':// octal - ++p; - if( *p >= '0' && *p <= '7' ) + switch( *p ) { + case 'x':// hexadecimal ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - break; - default: - if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) + while( ISXDIGIT(*p) ) + ++p; + break; + case '0': + case '1': + case '2': + case '3':// octal ++p; + if( *p >= '0' && *p <= '7' ) + ++p; + if( *p >= '0' && *p <= '7' ) + ++p; + break; + default: + if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) + ++p; } } return p; @@ -958,8 +919,7 @@ const char* skip_escaped_c(const char* p) /// @param maxcols Maximum number of columns of a valid row /// @param parseproc User-supplied row processing function /// @return true on success, false if file could not be opened -bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)) -{ +bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)) { FILE* fp; int lines = 0; int entries = 0; @@ -971,9 +931,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc snprintf(path, sizeof(path), "%s/%s", directory, filename); // open file - fp = fopen(path, "r"); - if( fp == NULL ) - { + if( (fp = fopen(path, "r")) == NULL ) { ShowError("sv_readdb: can't read %s\n", path); return false; } @@ -983,12 +941,10 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc fields = (char**)aMalloc(fields_length*sizeof(char*)); // process rows one by one - while( fgets(line, sizeof(line), fp) ) - { + while( fgets(line, sizeof(line), fp) ) { lines++; - if( ( match = strstr(line, "//") ) != NULL ) - {// strip comments + if( ( match = strstr(line, "//") ) != NULL ) {// strip comments match[0] = 0; } @@ -998,25 +954,21 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - if( columns < mincols ) - { + if( columns < mincols ) { ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); continue; // not enough columns } - if( columns > maxcols ) - { + if( columns > maxcols ) { ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols ); continue; // too many columns } - if( entries == maxrows ) - { + if( entries == maxrows ) { ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); break; } // parse this row - if( !parseproc(fields+1, columns, entries) ) - { + if( !parseproc(fields+1, columns, entries) ) { ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); continue; // invalid row contents } @@ -1039,41 +991,36 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc // @author MouseJstr (original) /// Allocates a StringBuf -StringBuf* StringBuf_Malloc() -{ +StringBuf* StringBuf_Malloc(void) { StringBuf* self; CREATE(self, StringBuf, 1); - StringBuf_Init(self); + StrBuf->Init(self); return self; } /// Initializes a previously allocated StringBuf -void StringBuf_Init(StringBuf* self) -{ +void StringBuf_Init(StringBuf* self) { self->max_ = 1024; self->ptr_ = self->buf_ = (char*)aMalloc(self->max_ + 1); } /// Appends the result of printf to the StringBuf -int StringBuf_Printf(StringBuf* self, const char* fmt, ...) -{ +int StringBuf_Printf(StringBuf* self, const char* fmt, ...) { int len; va_list ap; va_start(ap, fmt); - len = StringBuf_Vprintf(self, fmt, ap); + len = StrBuf->Vprintf(self, fmt, ap); va_end(ap); return len; } /// Appends the result of vprintf to the StringBuf -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) -{ +int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) { int n, size, off; - for(;;) - { + for(;;) { va_list apcopy; /* Try to print in the allocated space. */ size = self->max_ - (self->ptr_ - self->buf_); @@ -1081,8 +1028,7 @@ int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) n = vsnprintf(self->ptr_, size, fmt, apcopy); va_end(apcopy); /* If that worked, return the length. */ - if( n > -1 && n < size ) - { + if( n > -1 && n < size ) { self->ptr_ += n; return (int)(self->ptr_ - self->buf_); } @@ -1095,13 +1041,11 @@ int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) } /// Appends the contents of another StringBuf to the StringBuf -int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) -{ +int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) { int available = self->max_ - (self->ptr_ - self->buf_); int needed = (int)(sbuf->ptr_ - sbuf->buf_); - if( needed >= available ) - { + if( needed >= available ) { int off = (int)(self->ptr_ - self->buf_); self->max_ += needed; self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); @@ -1114,13 +1058,12 @@ int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) } // Appends str to the StringBuf -int StringBuf_AppendStr(StringBuf* self, const char* str) -{ +int StringBuf_AppendStr(StringBuf* self, const char* str) { int available = self->max_ - (self->ptr_ - self->buf_); int needed = (int)strlen(str); - if( needed >= available ) - {// not enough space, expand the buffer (minimum expansion = 1024) + if( needed >= available ) { + // not enough space, expand the buffer (minimum expansion = 1024) int off = (int)(self->ptr_ - self->buf_); self->max_ += max(needed, 1024); self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); @@ -1133,35 +1076,78 @@ int StringBuf_AppendStr(StringBuf* self, const char* str) } // Returns the length of the data in the Stringbuf -int StringBuf_Length(StringBuf* self) -{ +int StringBuf_Length(StringBuf* self) { return (int)(self->ptr_ - self->buf_); } /// Returns the data in the StringBuf -char* StringBuf_Value(StringBuf* self) -{ +char* StringBuf_Value(StringBuf* self) { *self->ptr_ = '\0'; return self->buf_; } /// Clears the contents of the StringBuf -void StringBuf_Clear(StringBuf* self) -{ +void StringBuf_Clear(StringBuf* self) { self->ptr_ = self->buf_; } /// Destroys the StringBuf -void StringBuf_Destroy(StringBuf* self) -{ +void StringBuf_Destroy(StringBuf* self) { aFree(self->buf_); self->ptr_ = self->buf_ = 0; self->max_ = 0; } // Frees a StringBuf returned by StringBuf_Malloc -void StringBuf_Free(StringBuf* self) -{ - StringBuf_Destroy(self); +void StringBuf_Free(StringBuf* self) { + StrBuf->Destroy(self); aFree(self); } +void strlib_defaults(void) { + /* connect */ + strlib = &strlib_s; + StrBuf = &stringbuf_s; + sv = &sv_s; + /* link~u! */ + strlib->jstrescape = jstrescape; + strlib->jmemescapecpy = jmemescapecpy; + strlib->remove_control_chars = remove_control_chars; + strlib->trim = trim; + strlib->normalize_name = normalize_name; + strlib->stristr = stristr; + +#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) + strlib->strnlen = strnlen; +#endif + +#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 + strlib->strtoull = strtoull; +#endif + strlib->e_mail_check = e_mail_check; + strlib->config_switch = config_switch; + strlib->safestrncpy = safestrncpy; + strlib->safestrnlen = safestrnlen; + strlib->safesnprintf = safesnprintf; + strlib->strline = strline; + strlib->bin2hex = bin2hex; + + StrBuf->Malloc = StringBuf_Malloc; + StrBuf->Init = StringBuf_Init; + StrBuf->Printf = StringBuf_Printf; + StrBuf->Vprintf = StringBuf_Vprintf; + StrBuf->Append = StringBuf_Append; + StrBuf->AppendStr = StringBuf_AppendStr; + StrBuf->Length = StringBuf_Length; + StrBuf->Value = StringBuf_Value; + StrBuf->Clear = StringBuf_Clear; + StrBuf->Destroy = StringBuf_Destroy; + StrBuf->Free = StringBuf_Free; + + sv->parse_next = sv_parse_next; + sv->parse = sv_parse; + sv->split = sv_split; + sv->escape_c = sv_escape_c; + sv->unescape_c = sv_unescape_c; + sv->skip_escaped_c = skip_escaped_c; + sv->readdb = sv_readdb; +} diff --git a/src/common/strlib.h b/src/common/strlib.h index bbc2c6105..4a073c3bc 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _STRLIB_H_ #define _STRLIB_H_ @@ -11,56 +12,14 @@ #include <string.h> #undef __USE_GNU -char* jstrescape (char* pt); -char* jstrescapecpy (char* pt, const char* spt); -int jmemescapecpy (char* pt, const char* spt, int size); - -int remove_control_chars(char* str); -char* trim(char* str); -char* normalize_name(char* str,const char* delims); -const char *stristr(const char *haystack, const char *needle); - #ifdef WIN32 -#define HAVE_STRTOK_R -#define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr)) -char* _strtok_r(char* s1, const char* s2, char** lasts); -#endif - -#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) -size_t strnlen (const char* string, size_t maxlen); + #define HAVE_STRTOK_R + #define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr)) + char *_strtok_r(char* s1, const char* s2, char** lasts); #endif -#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base); -#endif - -int e_mail_check(char* email); -int config_switch(const char* str); - -/// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n); - -/// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen); - -/// Works like snprintf, but always nul-terminates the buffer. -/// Returns the size of the string (without nul-terminator) -/// or -1 if the buffer is too small. -int safesnprintf(char* buf, size_t sz, const char* fmt, ...); - -/// Returns the line of the target position in the string. -/// Lines start at 1. -int strline(const char* str, size_t pos); - -/// 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); - - /// Bitfield determining the behaviour of sv_parse and sv_split. -typedef enum e_svopt -{ +typedef enum e_svopt { // default: no escapes and no line terminator SV_NOESCAPE_NOTERMINATE = 0, // Escapes according to the C compiler. @@ -78,8 +37,7 @@ typedef enum e_svopt /// Parse state. /// The field is [start,end[ -struct s_svstate -{ +struct s_svstate { const char* str; //< string to parse int len; //< string length int off; //< current offset in the string @@ -90,66 +48,144 @@ struct s_svstate bool done; //< if all the text has been parsed }; -/// Parses a single field in a delim-separated string. -/// The delimiter after the field is skipped. -/// -/// @param sv Parse state -/// @return 1 if a field was parsed, 0 if done, -1 on error. -int sv_parse_next(struct s_svstate* sv); - -/// Parses a delim-separated string. -/// Starts parsing at startoff and fills the pos array with position pairs. -/// out_pos[0] and out_pos[1] are the start and end of line. -/// Other position pairs are the start and end of fields. -/// Returns the number of fields found or -1 if an error occurs. -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt); - -/// Splits a delim-separated string. -/// WARNING: this function modifies the input string -/// Starts splitting at startoff and fills the out_fields array. -/// out_fields[0] is the start of the next line. -/// Other entries are the start of fields (nul-teminated). -/// Returns the number of fields found or -1 if an error occurs. -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt); - -/// Escapes src to out_dest according to the format of the C compiler. -/// Returns the length of the escaped string. -/// out_dest should be len*4+1 in size. -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes); - -/// Unescapes src to out_dest according to the format of the C compiler. -/// Returns the length of the unescaped string. -/// out_dest should be len+1 in size and can be the same buffer as src. -size_t sv_unescape_c(char* out_dest, const char* src, size_t len); - -/// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p); - -/// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row. -/// Tracks the progress of the operation (current line number, number of successfully processed rows). -/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read. -bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)); - /// StringBuf - dynamic string -struct StringBuf -{ +struct StringBuf { char *buf_; char *ptr_; unsigned int max_; }; typedef struct StringBuf StringBuf; -StringBuf* StringBuf_Malloc(void); -void StringBuf_Init(StringBuf* self); -int StringBuf_Printf(StringBuf* self, const char* fmt, ...); -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list args); -int StringBuf_Append(StringBuf* self, const StringBuf *sbuf); -int StringBuf_AppendStr(StringBuf* self, const char* str); -int StringBuf_Length(StringBuf* self); -char* StringBuf_Value(StringBuf* self); -void StringBuf_Clear(StringBuf* self); -void StringBuf_Destroy(StringBuf* self); -void StringBuf_Free(StringBuf* self); - +struct strlib_interface { + char *(*jstrescape) (char* pt); + char *(*jstrescapecpy) (char* pt, const char* spt); + int (*jmemescapecpy) (char* pt, const char* spt, int size); + int (*remove_control_chars) (char* str); + char *(*trim) (char* str); + char *(*normalize_name) (char* str,const char* delims); + const char *(*stristr) (const char *haystack, const char *needle); + +#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) + size_t (*strnlen) (const char* string, size_t maxlen); +#endif + +#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 + uint64 (*strtoull) (const char* str, char** endptr, int base); +#endif + + int (*e_mail_check) (char* email); + int (*config_switch) (const char* str); + + /// strncpy that always nul-terminates the string + char *(*safestrncpy) (char* dst, const char* src, size_t n); + + /// doesn't crash on null pointer + size_t (*safestrnlen) (const char* string, size_t maxlen); + + /// Works like snprintf, but always nul-terminates the buffer. + /// Returns the size of the string (without nul-terminator) + /// or -1 if the buffer is too small. + int (*safesnprintf) (char* buf, size_t sz, const char* fmt, ...); + + /// Returns the line of the target position in the string. + /// Lines start at 1. + int (*strline) (const char* str, size_t pos); + + /// 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); +} strlib_s; + +struct strlib_interface *strlib; + +struct stringbuf_interface { + StringBuf* (*Malloc) (void); + void (*Init) (StringBuf* self); + int (*Printf) (StringBuf* self, const char* fmt, ...); + int (*Vprintf) (StringBuf* self, const char* fmt, va_list args); + int (*Append) (StringBuf* self, const StringBuf *sbuf); + int (*AppendStr) (StringBuf* self, const char* str); + int (*Length) (StringBuf* self); + char* (*Value) (StringBuf* self); + void (*Clear) (StringBuf* self); + void (*Destroy) (StringBuf* self); + void (*Free) (StringBuf* self); +} stringbuf_s; + +struct stringbuf_interface *StrBuf; + +struct sv_interface { + /// Parses a single field in a delim-separated string. + /// The delimiter after the field is skipped. + /// + /// @param sv Parse state + /// @return 1 if a field was parsed, 0 if done, -1 on error. + int (*parse_next) (struct s_svstate* sv); + + /// Parses a delim-separated string. + /// Starts parsing at startoff and fills the pos array with position pairs. + /// out_pos[0] and out_pos[1] are the start and end of line. + /// Other position pairs are the start and end of fields. + /// Returns the number of fields found or -1 if an error occurs. + int (*parse) (const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt); + + /// Splits a delim-separated string. + /// WARNING: this function modifies the input string + /// Starts splitting at startoff and fills the out_fields array. + /// out_fields[0] is the start of the next line. + /// Other entries are the start of fields (nul-teminated). + /// Returns the number of fields found or -1 if an error occurs. + int (*split) (char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt); + + /// Escapes src to out_dest according to the format of the C compiler. + /// Returns the length of the escaped string. + /// out_dest should be len*4+1 in size. + size_t (*escape_c) (char* out_dest, const char* src, size_t len, const char* escapes); + + /// Unescapes src to out_dest according to the format of the C compiler. + /// Returns the length of the unescaped string. + /// out_dest should be len+1 in size and can be the same buffer as src. + size_t (*unescape_c) (char* out_dest, const char* src, size_t len); + + /// Skips a C escape sequence (starting with '\\'). + const char* (*skip_escaped_c) (const char* p); + + /// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row. + /// Tracks the progress of the operation (current line number, number of successfully processed rows). + /// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read. + bool (*readdb) (const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)); +} sv_s; + +struct sv_interface *sv; + +void strlib_defaults(void); + +/* the purpose of these macros is simply to not make calling them be an annoyance */ +#ifndef STRLIB_C + #define jstrescape(pt) strlib->jstrescape(pt) + #define jstrescapecpy(pt,spt) strlib->jstrescapecpy(pt,spt) + #define jmemescapecpy(pt,spt,size) strlib->jmemescapecpy(pt,spt,size) + #define remove_control_chars(str) strlib->remove_control_chars(str) + #define trim(str) strlib->trim(str) + #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) + #define strnln(string,maxlen) strlib->strnlen(string,maxlen) + #endif + + #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 + #define strtoull(str,endptr,base) strlib->strtoull(str,endptr,base) + #endif + + #define e_mail_check(email) strlib->e_mail_check(email) + #define config_switch(str) strlib->config_switch(str) + #define safestrncpy(dst,src,n) strlib->safestrncpy(dst,src,n) + #define safestrnlen(string,maxlen) strlib->safestrnlen(string,maxlen) + #define safesnprintf(buf,sz,fmt,...) strlib->safesnprintf(buf,sz,fmt,##__VA_ARGS__) + #define strline(str,pos) strlib->strline(str,pos) + #define bin2hex(output,input,count) strlib->bin2hex(output,input,count) +#endif /* STRLIB_C */ #endif /* _STRLIB_H_ */ diff --git a/src/common/timer.c b/src/common/timer.c index c239a9d70..edb46bd71 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #include "../common/cbasetypes.h" #include "../common/db.h" @@ -62,7 +63,7 @@ struct timer_func_list { } *tfl_root = NULL; /// Sets the name of a timer function. -int add_timer_func_list(TimerFunc func, char* name) +int timer_add_func_list(TimerFunc func, char* name) { struct timer_func_list* tfl; @@ -70,9 +71,9 @@ int add_timer_func_list(TimerFunc func, char* name) for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) {// check suspicious cases if( func == tfl->func ) - ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); + ShowWarning("timer_add_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); else if( strcmp(name,tfl->name) == 0 ) - ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); + ShowWarning("timer_add_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); } CREATE(tfl,struct timer_func_list,1); tfl->next = tfl_root; @@ -137,8 +138,7 @@ static void rdtsc_calibrate(){ #endif /// platform-abstracted tick retrieval -static unsigned int tick(void) -{ +static unsigned int tick(void) { #if defined(WIN32) return GetTickCount(); #elif defined(ENABLE_RDTSC) @@ -163,28 +163,25 @@ static unsigned int tick(void) static unsigned int gettick_cache; static int gettick_count = 1; -unsigned int gettick_nocache(void) -{ +unsigned int timer_gettick_nocache(void) { gettick_count = TICK_CACHE; gettick_cache = tick(); return gettick_cache; } -unsigned int gettick(void) -{ +unsigned int timer_gettick(void) { return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache; } ////////////////////////////// #else ////////////////////////////// // tick doesn't get cached -unsigned int gettick_nocache(void) +unsigned int timer_gettick_nocache(void) { return tick(); } -unsigned int gettick(void) -{ +unsigned int timer_gettick(void) { return tick(); } ////////////////////////////////////////////////////////////////////////// @@ -196,8 +193,7 @@ unsigned int gettick(void) *--------------------------------------*/ /// Adds a timer to the timer_heap -static void push_timer_heap(int tid) -{ +static void push_timer_heap(int tid) { BHEAP_ENSURE(timer_heap, 1, 256); BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); } @@ -207,8 +203,7 @@ static void push_timer_heap(int tid) *--------------------------*/ /// Returns a free timer id. -static int acquire_timer(void) -{ +static int acquire_timer(void) { int tid; // select a free timer @@ -240,8 +235,7 @@ static int acquire_timer(void) /// Starts a new timer that is deleted once it expires (single-use). /// Returns the timer's id. -int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data) -{ +int timer_add(unsigned int tick, TimerFunc func, int id, intptr_t data) { int tid; tid = acquire_timer(); @@ -258,13 +252,12 @@ int add_timer(unsigned int 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 add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval) +int timer_add_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval) { int tid; - if( interval < 1 ) - { - ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); + if( interval < 1 ) { + ShowError("timer_add_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); return INVALID_TIMER; } @@ -281,24 +274,20 @@ int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, } /// Retrieves internal timer data -const struct TimerData* get_timer(int tid) -{ +const struct TimerData* timer_get(int tid) { 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 delete_timer(int tid, TimerFunc func) -{ - if( tid < 0 || tid >= timer_data_num ) - { - ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); +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)); return -1; } - if( timer_data[tid].func != func ) - { - ShowError("delete_timer 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)); + 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)); return -2; } @@ -310,22 +299,19 @@ int delete_timer(int tid, TimerFunc func) /// Adjusts a timer's expiration time. /// Returns the new tick value, or -1 if it fails. -int addtick_timer(int tid, unsigned int tick) -{ +int timer_addtick(int tid, unsigned int tick) { return settick_timer(tid, timer_data[tid].tick+tick); } /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). /// Returns the new tick value, or -1 if it fails. -int settick_timer(int tid, unsigned int tick) -{ +int timer_settick(int tid, unsigned int tick) { size_t i; // search timer position ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); - if( i == BHEAP_LENGTH(timer_heap) ) - { - ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + if( i == BHEAP_LENGTH(timer_heap) ) { + ShowError("timer_settick: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); return -1; } @@ -344,13 +330,11 @@ int settick_timer(int tid, unsigned int tick) /// Executes all expired timers. /// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). -int do_timer(unsigned int tick) -{ +int do_timer(unsigned int tick) { int diff = TIMER_MAX_INTERVAL; // return value // process all timers one by one - while( BHEAP_LENGTH(timer_heap) ) - { + while( BHEAP_LENGTH(timer_heap) ) { int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) diff = DIFF_TICK(timer_data[tid].tick, tick); @@ -361,8 +345,7 @@ int do_timer(unsigned int tick) BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); timer_data[tid].type |= TIMER_REMOVE_HEAP; - if( timer_data[tid].func ) - { + if( timer_data[tid].func ) { if( diff < -1000 ) // timer was delayed for more than 1 second, use current tick instead timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); @@ -371,29 +354,27 @@ int do_timer(unsigned int tick) } // in the case the function didn't change anything... - if( timer_data[tid].type & TIMER_REMOVE_HEAP ) - { + if( timer_data[tid].type & TIMER_REMOVE_HEAP ) { timer_data[tid].type &= ~TIMER_REMOVE_HEAP; - switch( timer_data[tid].type ) - { - default: - case TIMER_ONCE_AUTODEL: - timer_data[tid].type = 0; - if (free_timer_list_pos >= free_timer_list_max) { - free_timer_list_max += 256; - RECREATE(free_timer_list,int,free_timer_list_max); - memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); - } - free_timer_list[free_timer_list_pos++] = tid; - break; - case TIMER_INTERVAL: - if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 ) - timer_data[tid].tick = tick + timer_data[tid].interval; - else - timer_data[tid].tick += timer_data[tid].interval; - push_timer_heap(tid); - break; + switch( timer_data[tid].type ) { + default: + case TIMER_ONCE_AUTODEL: + timer_data[tid].type = 0; + if (free_timer_list_pos >= free_timer_list_max) { + free_timer_list_max += 256; + RECREATE(free_timer_list,int,free_timer_list_max); + memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); + } + free_timer_list[free_timer_list_pos++] = tid; + break; + case TIMER_INTERVAL: + if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 ) + timer_data[tid].tick = tick + timer_data[tid].interval; + else + timer_data[tid].tick += timer_data[tid].interval; + push_timer_heap(tid); + break; } } } @@ -401,8 +382,7 @@ int do_timer(unsigned int tick) return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); } -unsigned long get_uptime(void) -{ +unsigned long timer_get_uptime(void) { return (unsigned long)difftime(time(NULL), start_time); } @@ -415,8 +395,7 @@ void timer_init(void) time(&start_time); } -void timer_final(void) -{ +void timer_final(void) { struct timer_func_list *tfl; struct timer_func_list *next; @@ -430,3 +409,15 @@ void timer_final(void) BHEAP_CLEAR(timer_heap); if (free_timer_list) aFree(free_timer_list); } +void timer_defaults(void) { + gettick = timer_gettick; + gettick_nocache = timer_gettick_nocache; + add_timer = timer_add; + add_timer_interval = timer_add_interval; + add_timer_func_list = timer_add_func_list; + get_timer = timer_get; + delete_timer = timer_do_delete; + addtick_timer = timer_addtick; + settick_timer = timer_settick; + get_uptime = timer_get_uptime; +} diff --git a/src/common/timer.h b/src/common/timer.h index d45c73d12..902679f51 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _TIMER_H_ #define _TIMER_H_ @@ -35,23 +36,26 @@ struct TimerData { // Function prototype declaration -unsigned int gettick(void); -unsigned int gettick_nocache(void); +int do_timer(unsigned int tick); +void timer_init(void); +void timer_final(void); -int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data); -int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); -const struct TimerData* get_timer(int tid); -int delete_timer(int tid, TimerFunc func); +/* Hercules Renewal Phase One */ +unsigned int (*gettick) (void); +unsigned int (*gettick_nocache) (void); -int addtick_timer(int tid, unsigned int tick); -int settick_timer(int tid, unsigned int tick); +int (*add_timer) (unsigned int tick, TimerFunc func, int id, intptr_t data); +int (*add_timer_interval) (unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); +const struct TimerData *(*get_timer) (int tid); +int (*delete_timer) (int tid, TimerFunc func); -int add_timer_func_list(TimerFunc func, char* name); +int (*addtick_timer) (int tid, unsigned int tick); +int (*settick_timer) (int tid, unsigned int tick); -unsigned long get_uptime(void); +int (*add_timer_func_list) (TimerFunc func, char* name); -int do_timer(unsigned int tick); -void timer_init(void); -void timer_final(void); +unsigned long (*get_uptime) (void); + +void timer_defaults(void); #endif /* _TIMER_H_ */ |