summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/HPM.c353
-rw-r--r--src/common/HPM.h68
-rw-r--r--src/common/HPMDataCheck.h130
-rw-r--r--src/common/HPMi.h123
-rw-r--r--src/common/Makefile.in36
-rw-r--r--src/common/atomic.h11
-rw-r--r--src/common/cbasetypes.h59
-rw-r--r--src/common/conf.c169
-rw-r--r--src/common/conf.h98
-rw-r--r--src/common/console.c6
-rw-r--r--src/common/console.h8
-rw-r--r--src/common/core.c35
-rw-r--r--src/common/core.h6
-rw-r--r--src/common/db.c186
-rw-r--r--src/common/db.h152
-rw-r--r--src/common/des.h6
-rw-r--r--src/common/ers.c27
-rw-r--r--src/common/ers.h29
-rw-r--r--src/common/grfio.c23
-rw-r--r--src/common/grfio.h8
-rw-r--r--src/common/malloc.c99
-rw-r--r--src/common/malloc.h24
-rw-r--r--src/common/mapindex.c88
-rw-r--r--src/common/mapindex.h59
-rw-r--r--src/common/md5calc.h6
-rw-r--r--src/common/mempool.c10
-rw-r--r--src/common/mmo.h145
-rw-r--r--src/common/mutex.h6
-rw-r--r--src/common/netbuffer.h10
-rw-r--r--src/common/network.c2
-rw-r--r--src/common/nullpo.c99
-rw-r--r--src/common/nullpo.h307
-rw-r--r--src/common/raconf.c29
-rw-r--r--src/common/random.c12
-rw-r--r--src/common/random.h6
-rw-r--r--src/common/showmsg.c111
-rw-r--r--src/common/showmsg.h14
-rw-r--r--src/common/socket.c188
-rw-r--r--src/common/socket.h170
-rw-r--r--src/common/spinlock.h10
-rw-r--r--src/common/sql.c9
-rw-r--r--src/common/sql.h14
-rw-r--r--src/common/strlib.c53
-rw-r--r--src/common/strlib.h47
-rw-r--r--src/common/thread.h6
-rw-r--r--src/common/timer.c102
-rw-r--r--src/common/timer.h31
-rw-r--r--src/common/utils.c11
-rw-r--r--src/common/utils.h10
49 files changed, 2099 insertions, 1112 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c
index 8be9298f9..bd2ce93ab 100644
--- a/src/common/HPM.c
+++ b/src/common/HPM.c
@@ -108,6 +108,7 @@ bool hplugin_populate(struct hplugin *plugin, const char *filename) {
return true;
}
+#undef HPM_POP
struct hplugin *hplugin_load(const char* filename) {
struct hplugin *plugin;
struct hplugin_info *info;
@@ -115,6 +116,8 @@ struct hplugin *hplugin_load(const char* filename) {
bool anyEvent = false;
void **import_symbol_ref;
Sql **sql_handle;
+ unsigned int *HPMDataCheckLen;
+ struct s_HPMDataCheck *HPMDataCheck;
if( HPM->exists(filename) ) {
ShowWarning("HPM:plugin_load: attempting to load duplicate '"CL_WHITE"%s"CL_RESET"', skipping...\n", filename);
@@ -190,6 +193,9 @@ struct hplugin *hplugin_load(const char* filename) {
if( ( plugin->hpi->event[HPET_POST_FINAL] = plugin_import(plugin->dll, "server_post_final",void (*)(void)) ) )
anyEvent = true;
+ if( ( plugin->hpi->event[HPET_PRE_INIT] = plugin_import(plugin->dll, "server_preinit",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);
@@ -199,17 +205,37 @@ struct hplugin *hplugin_load(const char* filename) {
if( !HPM->populate(plugin,filename) )
return NULL;
+ if( !( HPMDataCheckLen = plugin_import(plugin->dll, "HPMDataCheckLen", unsigned int *) ) ) {
+ ShowWarning("HPM:plugin_load: failed to retrieve 'HPMDataCheckLen' for '"CL_WHITE"%s"CL_RESET"', most likely not including HPMDataCheck.h, skipping...\n", filename);
+ HPM->unload(plugin);
+ return NULL;
+ }
+
+ if( !( HPMDataCheck = plugin_import(plugin->dll, "HPMDataCheck", struct s_HPMDataCheck *) ) ) {
+ ShowWarning("HPM:plugin_load: failed to retrieve 'HPMDataCheck' for '"CL_WHITE"%s"CL_RESET"', most likely not including HPMDataCheck.h, skipping...\n", filename);
+ HPM->unload(plugin);
+ return NULL;
+ }
+
+ if( HPM->DataCheck && !HPM->DataCheck(HPMDataCheck,*HPMDataCheckLen,plugin->info->name) ) {
+ ShowWarning("HPM:plugin_load: '"CL_WHITE"%s"CL_RESET"' failed DataCheck, out of sync from the core (recompile plugin), skipping...\n", filename);
+ HPM->unload(plugin);
+ return NULL;
+ }
+
/* id */
- plugin->hpi->pid = plugin->idx;
+ plugin->hpi->pid = plugin->idx;
/* core */
- plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand",plugin->idx);
- plugin->hpi->addPacket = HPM->import_symbol("addPacket",plugin->idx);
- plugin->hpi->addToSession = HPM->import_symbol("addToSession",plugin->idx);
- plugin->hpi->getFromSession = HPM->import_symbol("getFromSession",plugin->idx);
- plugin->hpi->removeFromSession = HPM->import_symbol("removeFromSession",plugin->idx);
- plugin->hpi->AddHook = HPM->import_symbol("AddHook",plugin->idx);
- plugin->hpi->HookStop = HPM->import_symbol("HookStop",plugin->idx);
- plugin->hpi->HookStopped = HPM->import_symbol("HookStopped",plugin->idx);
+ plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand",plugin->idx);
+ plugin->hpi->addPacket = HPM->import_symbol("addPacket",plugin->idx);
+ plugin->hpi->addToHPData = HPM->import_symbol("addToHPData",plugin->idx);
+ plugin->hpi->getFromHPData = HPM->import_symbol("getFromHPData",plugin->idx);
+ plugin->hpi->removeFromHPData = HPM->import_symbol("removeFromHPData",plugin->idx);
+ plugin->hpi->AddHook = HPM->import_symbol("AddHook",plugin->idx);
+ plugin->hpi->HookStop = HPM->import_symbol("HookStop",plugin->idx);
+ plugin->hpi->HookStopped = HPM->import_symbol("HookStopped",plugin->idx);
+ plugin->hpi->addArg = HPM->import_symbol("addArg",plugin->idx);
+ plugin->hpi->addConf = HPM->import_symbol("addConf",plugin->idx);
/* server specific */
if( HPM->load_sub )
HPM->load_sub(plugin);
@@ -247,22 +273,35 @@ void hplugins_config_read(void) {
config_t plugins_conf;
config_setting_t *plist = NULL;
const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name
+ FILE *fp;
- if (conf_read_file(&plugins_conf, config_filename))
+// uncomment once login/char support is wrapped up
+// if( !HPM->DataCheck ) {
+// ShowError("HPM:config_read: HPM->DataCheck not set! Failure\n");
+// return;
+// }
+
+ /* yes its ugly, its temporary and will be gone as soon as the new inter-server.conf is set */
+ if( (fp = fopen("conf/import/plugins.conf","r")) ) {
+ config_filename = "conf/import/plugins.conf";
+ fclose(fp);
+ }
+
+ if (libconfig->read_file(&plugins_conf, config_filename))
return;
if( HPM->symbol_defaults_sub )
HPM->symbol_defaults_sub();
- plist = config_lookup(&plugins_conf, "plugins_list");
+ plist = libconfig->lookup(&plugins_conf, "plugins_list");
if (plist != NULL) {
- int length = config_setting_length(plist), i;
+ int length = libconfig->setting_length(plist), i;
char filename[60];
for(i = 0; i < length; i++) {
- if( !strcmpi(config_setting_get_string_elem(plist,i),"HPMHooking") ) {//must load it first
+ if( !strcmpi(libconfig->setting_get_string_elem(plist,i),"HPMHooking") ) {//must load it first
struct hplugin *plugin;
- snprintf(filename, 60, "plugins/%s%s", config_setting_get_string_elem(plist,i), DLL_EXT);
+ snprintf(filename, 60, "plugins/%s%s", libconfig->setting_get_string_elem(plist,i), DLL_EXT);
if( ( plugin = HPM->load(filename) ) ) {
bool (*func)(bool *fr);
bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
@@ -276,12 +315,12 @@ void hplugins_config_read(void) {
}
}
for(i = 0; i < length; i++) {
- if( strcmpi(config_setting_get_string_elem(plist,i),"HPMHooking") ) {//now all others
- snprintf(filename, 60, "plugins/%s%s", config_setting_get_string_elem(plist,i), DLL_EXT);
+ if( strcmpi(libconfig->setting_get_string_elem(plist,i),"HPMHooking") ) {//now all others
+ snprintf(filename, 60, "plugins/%s%s", libconfig->setting_get_string_elem(plist,i), DLL_EXT);
HPM->load(filename);
}
}
- config_destroy(&plugins_conf);
+ libconfig->destroy(&plugins_conf);
}
if( HPM->plugin_count )
@@ -300,67 +339,131 @@ CPCMD(plugins) {
}
}
}
+void hplugins_grabHPData(struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr) {
+ /* record address */
+ switch( type ) {
+ /* core-handled */
+ case HPDT_SESSION:
+ ret->HPDataSRCPtr = (void**)(&((struct socket_data *)ptr)->hdata);
+ ret->hdatac = &((struct socket_data *)ptr)->hdatac;
+ break;
+ /* goes to sub */
+ default:
+ if( HPM->grabHPDataSub ) {
+ if( HPM->grabHPDataSub(ret,type,ptr) )
+ return;
+ else {
+ ShowError("HPM:HPM:grabHPData failed, unknown type %d!\n",type);
+ }
+ } else
+ ShowError("HPM:grabHPData failed, type %d needs sub-handler!\n",type);
+ ret->HPDataSRCPtr = NULL;
+ ret->hdatac = NULL;
+ return;
+ }
+}
+void hplugins_addToHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, void *data, unsigned int index, bool autofree) {
+ struct HPluginData *HPData, **HPDataSRC;
+ struct HPDataOperationStorage action;
+ unsigned int i, max;
+
+ HPM->grabHPData(&action,type,ptr);
-void hplugins_addToSession(struct socket_data *sess, void *data, unsigned int id, unsigned int type, bool autofree) {
- struct HPluginData *HPData;
- unsigned int i;
+ if( action.hdatac == NULL ) { /* woo it failed! */
+ ShowError("HPM:addToHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index);
+ return;
+ }
+
+ /* flag */
+ HPDataSRC = *(action.HPDataSRCPtr);
+ max = *(action.hdatac);
- for(i = 0; i < sess->hdatac; i++) {
- if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
- ShowError("HPM->addToSession:%s: error! attempting to insert duplicate struct of id %u and type %u\n",HPM->pid2name(id),id,type);
+ /* duplicate check */
+ for(i = 0; i < max; i++) {
+ if( HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index ) {
+ ShowError("HPM:addToHPData:%s: error! attempting to insert duplicate struct of id %u and index %u\n",HPM->pid2name(pluginID),pluginID,index);
return;
}
}
- //HPluginData is always same size, probably better to use the ERS
+ /* HPluginData is always same size, probably better to use the ERS (with reasonable chunk size e.g. 10/25/50) */
CREATE(HPData, struct HPluginData, 1);
- HPData->pluginID = id;
- HPData->type = type;
+ /* input */
+ HPData->pluginID = pluginID;
+ HPData->type = index;
HPData->flag.free = autofree ? 1 : 0;
HPData->data = data;
- RECREATE(sess->hdata,struct HPluginData *,++sess->hdatac);
- sess->hdata[sess->hdatac - 1] = HPData;
+ /* resize */
+ *(action.hdatac) += 1;
+ RECREATE(*(action.HPDataSRCPtr),struct HPluginData *,*(action.hdatac));
+
+ /* RECREATE modified the addresss */
+ HPDataSRC = *(action.HPDataSRCPtr);
+ HPDataSRC[*(action.hdatac) - 1] = HPData;
}
-void *hplugins_getFromSession(struct socket_data *sess, unsigned int id, unsigned int type) {
- unsigned int i;
+
+void *hplugins_getFromHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index) {
+ struct HPDataOperationStorage action;
+ struct HPluginData **HPDataSRC;
+ unsigned int i, max;
- for(i = 0; i < sess->hdatac; i++) {
- if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
- break;
- }
+ HPM->grabHPData(&action,type,ptr);
+
+ if( action.hdatac == NULL ) { /* woo it failed! */
+ ShowError("HPM:getFromHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index);
+ return NULL;
}
- if( i != sess->hdatac )
- return sess->hdata[i]->data;
+ /* flag */
+ HPDataSRC = *(action.HPDataSRCPtr);
+ max = *(action.hdatac);
+ for(i = 0; i < max; i++) {
+ if( HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index )
+ return HPDataSRC[i]->data;
+ }
+
return NULL;
}
-void hplugins_removeFromSession(struct socket_data *sess, unsigned int id, unsigned int type) {
- unsigned int i;
+
+void hplugins_removeFromHPData(enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index) {
+ struct HPDataOperationStorage action;
+ struct HPluginData **HPDataSRC;
+ unsigned int i, max;
+
+ HPM->grabHPData(&action,type,ptr);
+
+ if( action.hdatac == NULL ) { /* woo it failed! */
+ ShowError("HPM:removeFromHPData:%s: failed, type %d (%u|%u)\n",HPM->pid2name(pluginID),type,pluginID,index);
+ return;
+ }
- for(i = 0; i < sess->hdatac; i++) {
- if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
+ /* flag */
+ HPDataSRC = *(action.HPDataSRCPtr);
+ max = *(action.hdatac);
+
+ for(i = 0; i < max; i++) {
+ if( HPDataSRC[i]->pluginID == pluginID && HPDataSRC[i]->type == index )
break;
- }
}
- if( i != sess->hdatac ) {
+ if( i != max ) {
unsigned int cursor;
-
- aFree(sess->hdata[i]->data);
- aFree(sess->hdata[i]);
- sess->hdata[i] = NULL;
- for(i = 0, cursor = 0; i < sess->hdatac; i++) {
- if( sess->hdata[i] == NULL )
+ aFree(HPDataSRC[i]->data);/* when its removed we delete it regardless of autofree */
+ aFree(HPDataSRC[i]);
+ HPDataSRC[i] = NULL;
+
+ for(i = 0, cursor = 0; i < max; i++) {
+ if( HPDataSRC[i] == NULL )
continue;
if( i != cursor )
- sess->hdata[cursor] = sess->hdata[i];
+ HPDataSRC[cursor] = HPDataSRC[i];
cursor++;
}
- sess->hdatac = cursor;
+ *(action.hdatac) = cursor;
}
}
@@ -458,6 +561,9 @@ void* HPM_calloc(size_t num, size_t size, const char *file, int line, const char
void* HPM_realloc(void *p, size_t size, const char *file, int line, const char *func) {
return iMalloc->realloc(p,size,HPM_file2ptr(file),line,func);
}
+void* HPM_reallocz(void *p, size_t size, const char *file, int line, const char *func) {
+ return iMalloc->reallocz(p,size,HPM_file2ptr(file),line,func);
+}
char* HPM_astrdup(const char *p, const char *file, int line, const char *func) {
return iMalloc->astrdup(p,HPM_file2ptr(file),line,func);
}
@@ -471,6 +577,9 @@ bool HPM_AddHook(enum HPluginHookType type, const char *target, void *hook, unsi
/* if not check if a sub-hooking list is available (from the server) and run it by */
if( HPM->addhook_sub && HPM->addhook_sub(type,target,hook,pID) )
return true;
+
+ ShowError("HPM:AddHook: unknown Hooking Point '%s'!\n",target);
+
return false;
}
void HPM_HookStop (const char *func, unsigned int pID) {
@@ -480,6 +589,93 @@ void HPM_HookStop (const char *func, unsigned int pID) {
bool HPM_HookStopped (void) {
return HPM->force_return;
}
+/* command-line args */
+bool hpm_parse_arg(const char *arg, int *index, char *argv[], bool param) {
+ struct HPMArgData *data;
+
+ if( (data = strdb_get(HPM->arg_db,arg)) ) {
+ data->func((data->has_param && param)?argv[(*index)+1]:NULL);
+ if( data->has_param && param ) *index += 1;
+ return true;
+ }
+
+ return false;
+}
+void hpm_arg_help(void) {
+ DBIterator *iter = db_iterator(HPM->arg_db);
+ struct HPMArgData *data = NULL;
+
+ for( data = dbi_first(iter); dbi_exists(iter); data = dbi_next(iter) ) {
+ if( data->help != NULL )
+ data->help();
+ else
+ ShowInfo(" %s (%s)\t\t<no description provided>\n",data->name,HPM->pid2name(data->pluginID));
+ }
+
+ dbi_destroy(iter);
+}
+bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, void (*func) (char *param),void (*help) (void)) {
+ struct HPMArgData *data = NULL;
+
+ if( strdb_exists(HPM->arg_db, name) ) {
+ ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
+ return false;
+ }
+
+ CREATE(data, struct HPMArgData, 1);
+
+ data->pluginID = pluginID;
+ data->name = aStrdup(name);
+ data->func = func;
+ data->help = help;
+ data->has_param = has_param;
+
+ strdb_put(HPM->arg_db, data->name, data);
+
+ return true;
+}
+bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *name, void (*func) (const char *val)) {
+ struct HPConfListenStorage *conf;
+ unsigned int i;
+
+ if( type >= HPCT_MAX ) {
+ ShowError("HPM->addConf:%s: unknown point '%u' specified for config '%s'\n",HPM->pid2name(pluginID),type,name);
+ return false;
+ }
+
+ for(i = 0; i < HPM->confsc[type]; i++) {
+ if( !strcmpi(name,HPM->confs[type][i].key) ) {
+ ShowError("HPM->addConf:%s: duplicate '%s', already in use by '%s'!",HPM->pid2name(pluginID),name,HPM->pid2name(HPM->confs[type][i].pluginID));
+ return false;
+ }
+ }
+
+ RECREATE(HPM->confs[type], struct HPConfListenStorage, ++HPM->confsc[type]);
+ conf = &HPM->confs[type][HPM->confsc[type] - 1];
+
+ conf->pluginID = pluginID;
+ safestrncpy(conf->key, name, HPM_ADDCONF_LENGTH);
+ conf->func = func;
+
+ return true;
+}
+bool hplugins_parse_conf(const char *w1, const char *w2, enum HPluginConfType point) {
+ unsigned int i;
+
+ /* exists? */
+ for(i = 0; i < HPM->confsc[point]; i++) {
+ if( !strcmpi(w1,HPM->confs[point][i].key) )
+ break;
+ }
+
+ /* trigger and we're set! */
+ if( i != HPM->confsc[point] ) {
+ HPM->confs[point][i].func(w2);
+ return true;
+ }
+
+ return false;
+}
void hplugins_share_defaults(void) {
/* console */
@@ -488,12 +684,14 @@ void hplugins_share_defaults(void) {
#endif
/* our own */
HPM->share(hplugins_addpacket,"addPacket");
- HPM->share(hplugins_addToSession,"addToSession");
- HPM->share(hplugins_getFromSession,"getFromSession");
- HPM->share(hplugins_removeFromSession,"removeFromSession");
+ HPM->share(hplugins_addToHPData,"addToHPData");
+ HPM->share(hplugins_getFromHPData,"getFromHPData");
+ HPM->share(hplugins_removeFromHPData,"removeFromHPData");
HPM->share(HPM_AddHook,"AddHook");
HPM->share(HPM_HookStop,"HookStop");
HPM->share(HPM_HookStopped,"HookStopped");
+ HPM->share(hpm_add_arg,"addArg");
+ HPM->share(hplugins_addconf,"addConf");
/* core */
HPM->share(&runflag,"runflag");
HPM->share(arg_v,"arg_v");
@@ -505,11 +703,7 @@ void hplugins_share_defaults(void) {
HPM->share(DB, "DB");
HPM->share(HPMiMalloc, "iMalloc");
/* socket */
- HPM->share(RFIFOSKIP,"RFIFOSKIP");
- HPM->share(WFIFOSET,"WFIFOSET");
- HPM->share(do_close,"do_close");
- HPM->share(make_connection,"make_connection");
- //session,fd_max and addr_ are shared from within socket.c
+ HPM->share(sockt,"sockt");
/* strlib */
HPM->share(strlib,"strlib");
HPM->share(sv,"sv");
@@ -518,7 +712,8 @@ void hplugins_share_defaults(void) {
HPM->share(SQL,"SQL");
/* timer */
HPM->share(timer,"timer");
-
+ /* libconfig */
+ HPM->share(libconfig,"libconfig");
}
void hpm_init(void) {
@@ -534,6 +729,7 @@ void hpm_init(void) {
HPMiMalloc->malloc = HPM_mmalloc;
HPMiMalloc->calloc = HPM_calloc;
HPMiMalloc->realloc = HPM_realloc;
+ HPMiMalloc->reallocz = HPM_reallocz;
HPMiMalloc->astrdup = HPM_astrdup;
sscanf(HPM_VERSION, "%u.%u", &HPM->version[0], &HPM->version[1]);
@@ -548,6 +744,8 @@ void hpm_init(void) {
HPM->packetsc[i] = 0;
}
+ HPM->arg_db = strdb_alloc(DB_OPT_RELEASE_DATA, 0);
+
HPM->symbol_defaults();
#ifdef CONSOLE_INPUT
@@ -566,6 +764,14 @@ void hpm_memdown(void) {
if( HPM->fnames )
free(HPM->fnames);
+
+}
+int hpm_arg_db_clear_sub(DBKey key, DBData *data, va_list args) {
+ struct HPMArgData *a = DB->data2ptr(data);
+
+ aFree(a->name);
+
+ return 0;
}
void hpm_final(void) {
unsigned int i;
@@ -591,19 +797,39 @@ void hpm_final(void) {
aFree(HPM->packets[i]);
}
+ for( i = 0; i < HPCT_MAX; i++ ) {
+ if( HPM->confsc[i] )
+ aFree(HPM->confs[i]);
+ }
+
+ HPM->arg_db->destroy(HPM->arg_db,HPM->arg_db_clear_sub);
+
/* HPM->fnames is cleared after the memory manager goes down */
iMalloc->post_shutdown = hpm_memdown;
return;
}
void hpm_defaults(void) {
+ unsigned int i;
HPM = &HPM_s;
HPM->fnames = NULL;
HPM->fnamec = 0;
HPM->force_return = false;
HPM->hooking = false;
-
+ /* */
+ HPM->fnames = NULL;
+ HPM->fnamec = 0;
+ for(i = 0; i < hpPHP_MAX; i++) {
+ HPM->packets[i] = NULL;
+ HPM->packetsc[i] = 0;
+ }
+ for(i = 0; i < HPCT_MAX; i++) {
+ HPM->confs[i] = NULL;
+ HPM->confsc[i] = 0;
+ }
+ HPM->arg_db = NULL;
+ /* */
HPM->init = hpm_init;
HPM->final = hpm_final;
@@ -623,4 +849,11 @@ void hpm_defaults(void) {
HPM->parse_packets = hplugins_parse_packets;
HPM->load_sub = NULL;
HPM->addhook_sub = NULL;
+ HPM->arg_db_clear_sub = hpm_arg_db_clear_sub;
+ HPM->parse_arg = hpm_parse_arg;
+ HPM->arg_help = hpm_arg_help;
+ HPM->grabHPData = hplugins_grabHPData;
+ HPM->grabHPDataSub = NULL;
+ HPM->parseConf = hplugins_parse_conf;
+ HPM->DataCheck = NULL;
}
diff --git a/src/common/HPM.h b/src/common/HPM.h
index 395555948..52ad24a03 100644
--- a/src/common/HPM.h
+++ b/src/common/HPM.h
@@ -1,8 +1,8 @@
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file
-#ifndef _HPM_H_
-#define _HPM_H_
+#ifndef _COMMON_HPM_H_
+#define _COMMON_HPM_H_
#include "../common/cbasetypes.h"
#include "../common/HPMi.h"
@@ -12,29 +12,31 @@
#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 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
+ #define DLL_EXT ".dll"
+ #define DLL HINSTANCE
#else // ! WIN32
#include <dlfcn.h>
#ifdef RTLD_DEEPBIND // Certain linux ditributions require this, but it's not available everywhere
- #define plugin_open(x) dlopen(x,RTLD_NOW|RTLD_DEEPBIND)
+ #define plugin_open(x) dlopen((x),RTLD_NOW|RTLD_DEEPBIND)
#else // ! RTLD_DEEPBIND
- #define plugin_open(x) dlopen(x,RTLD_NOW)
+ #define plugin_open(x) dlopen((x),RTLD_NOW)
#endif // RTLD_DEEPBIND
- #define plugin_import(x,y,z) (z)dlsym(x,y)
- #define plugin_close(x) dlclose(x)
+ #define plugin_import(x,y,z) (z)dlsym((x),(y))
+ #define plugin_close(x) dlclose(x)
- #ifdef CYGWIN
- #define DLL_EXT ".dll"
+ #if defined CYGWIN
+ #define DLL_EXT ".dll"
+ #elif defined __DARWIN__
+ #define DLL_EXT ".dylib"
#else
- #define DLL_EXT ".so"
+ #define DLL_EXT ".so"
#endif
- #define DLL void *
+ #define DLL void *
#include <string.h> // size_t
@@ -74,6 +76,25 @@ struct HPMFileNameCache {
char *name;
};
+struct HPMArgData {
+ unsigned int pluginID;
+ char *name;/* e.g. "--my-arg","-v","--whatever" */
+ void (*help) (void);/* to display when --help is used */
+ void (*func) (char *param);/* NULL when no param is available */
+ bool has_param;/* because of the weird "--arg<space>param" instead of the "--arg=param" */
+};
+
+struct HPDataOperationStorage {
+ void **HPDataSRCPtr;
+ unsigned int *hdatac;
+};
+/* */
+struct HPConfListenStorage {
+ unsigned int pluginID;
+ char key[HPM_ADDCONF_LENGTH];
+ void (*func) (const char *val);
+};
+
/* Hercules Plugin Manager Interface */
struct HPM_interface {
/* vars */
@@ -93,6 +114,11 @@ struct HPM_interface {
/* plugin file ptr caching */
struct HPMFileNameCache *fnames;
unsigned int fnamec;
+ /* config listen */
+ struct HPConfListenStorage *confs[HPCT_MAX];
+ unsigned int confsc[HPCT_MAX];
+ /* --command-line */
+ DBMap *arg_db;
/* funcs */
void (*init) (void);
void (*final) (void);
@@ -112,10 +138,20 @@ struct HPM_interface {
unsigned char (*parse_packets) (int fd, enum HPluginPacketHookingPoints point);
void (*load_sub) (struct hplugin *plugin);
bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
+ bool (*parse_arg) (const char *arg, int* index, char *argv[], bool param);
+ void (*arg_help) (void);
+ int (*arg_db_clear_sub) (DBKey key, DBData *data, va_list args);
+ void (*grabHPData) (struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr);
+ /* for server-specific HPData e.g. map_session_data */
+ bool (*grabHPDataSub) (struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr);
+ /* for custom config parsing */
+ bool (*parseConf) (const char *w1, const char *w2, enum HPluginConfType point);
+ /* validates plugin data */
+ bool (*DataCheck) (struct s_HPMDataCheck *src, unsigned int size, char *name);
} HPM_s;
struct HPM_interface *HPM;
void hpm_defaults(void);
-#endif /* _HPM_H_ */
+#endif /* _COMMON_HPM_H_ */
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
new file mode 100644
index 000000000..48089964d
--- /dev/null
+++ b/src/common/HPMDataCheck.h
@@ -0,0 +1,130 @@
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+//
+// NOTE: This file was auto-generated and should never be manually edited,
+// as it will get overwritten.
+#ifndef _HPM_DATA_CHECK_H_
+#define _HPM_DATA_CHECK_H_
+
+
+HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
+ #ifdef _COMMON_CONF_H_
+ { "libconfig_interface", sizeof(struct libconfig_interface) },
+ #else
+ #define _COMMON_CONF_H_
+ #endif // _COMMON_CONF_H_
+ #ifdef _COMMON_DB_H_
+ { "DBData", sizeof(struct DBData) },
+ { "DBIterator", sizeof(struct DBIterator) },
+ { "DBMap", sizeof(struct DBMap) },
+ #else
+ #define _COMMON_DB_H_
+ #endif // _COMMON_DB_H_
+ #ifdef _COMMON_DES_H_
+ { "BIT64", sizeof(struct BIT64) },
+ #else
+ #define _COMMON_DES_H_
+ #endif // _COMMON_DES_H_
+ #ifdef _COMMON_ERS_H_
+ { "eri", sizeof(struct eri) },
+ #else
+ #define _COMMON_ERS_H_
+ #endif // _COMMON_ERS_H_
+ #ifdef _COMMON_MAPINDEX_H_
+ { "mapindex_interface", sizeof(struct mapindex_interface) },
+ #else
+ #define _COMMON_MAPINDEX_H_
+ #endif // _COMMON_MAPINDEX_H_
+ #ifdef _COMMON_MMO_H_
+ { "quest", sizeof(struct quest) },
+ #else
+ #define _COMMON_MMO_H_
+ #endif // _COMMON_MMO_H_
+ #ifdef _COMMON_SOCKET_H_
+ { "socket_interface", sizeof(struct socket_interface) },
+ #else
+ #define _COMMON_SOCKET_H_
+ #endif // _COMMON_SOCKET_H_
+ #ifdef _COMMON_STRLIB_H_
+ { "StringBuf", sizeof(struct StringBuf) },
+ { "s_svstate", sizeof(struct s_svstate) },
+ #else
+ #define _COMMON_STRLIB_H_
+ #endif // _COMMON_STRLIB_H_
+ #ifdef _MAP_ATCOMMAND_H_
+ { "AliasInfo", sizeof(struct AliasInfo) },
+ { "atcommand_interface", sizeof(struct atcommand_interface) },
+ #else
+ #define _MAP_ATCOMMAND_H_
+ #endif // _MAP_ATCOMMAND_H_
+ #ifdef _MAP_BATTLE_H_
+ { "Damage", sizeof(struct Damage) },
+ { "battle_interface", sizeof(struct battle_interface) },
+ #else
+ #define _MAP_BATTLE_H_
+ #endif // _MAP_BATTLE_H_
+ #ifdef _MAP_BUYINGSTORE_H_
+ { "buyingstore_interface", sizeof(struct buyingstore_interface) },
+ { "s_buyingstore_item", sizeof(struct s_buyingstore_item) },
+ #else
+ #define _MAP_BUYINGSTORE_H_
+ #endif // _MAP_BUYINGSTORE_H_
+ #ifdef _MAP_CHRIF_H_
+ { "auth_node", sizeof(struct auth_node) },
+ #else
+ #define _MAP_CHRIF_H_
+ #endif // _MAP_CHRIF_H_
+ #ifdef _MAP_CLIF_H_
+ { "clif_interface", sizeof(struct clif_interface) },
+ #else
+ #define _MAP_CLIF_H_
+ #endif // _MAP_CLIF_H_
+ #ifdef _MAP_ELEMENTAL_H_
+ { "elemental_skill", sizeof(struct elemental_skill) },
+ #else
+ #define _MAP_ELEMENTAL_H_
+ #endif // _MAP_ELEMENTAL_H_
+ #ifdef _MAP_GUILD_H_
+ { "eventlist", sizeof(struct eventlist) },
+ #else
+ #define _MAP_GUILD_H_
+ #endif // _MAP_GUILD_H_
+ #ifdef _MAP_MAP_H_
+ { "map_data_other_server", sizeof(struct map_data_other_server) },
+ #else
+ #define _MAP_MAP_H_
+ #endif // _MAP_MAP_H_
+ #ifdef _MAP_PACKETS_STRUCT_H_
+ { "EQUIPSLOTINFO", sizeof(struct EQUIPSLOTINFO) },
+ #else
+ #define _MAP_PACKETS_STRUCT_H_
+ #endif // _MAP_PACKETS_STRUCT_H_
+ #ifdef _MAP_PC_H_
+ { "autotrade_vending", sizeof(struct autotrade_vending) },
+ { "item_cd", sizeof(struct item_cd) },
+ #else
+ #define _MAP_PC_H_
+ #endif // _MAP_PC_H_
+ #ifdef _MAP_SCRIPT_H_
+ { "Script_Config", sizeof(struct Script_Config) },
+ { "script_interface", sizeof(struct script_interface) },
+ #else
+ #define _MAP_SCRIPT_H_
+ #endif // _MAP_SCRIPT_H_
+ #ifdef _MAP_SEARCHSTORE_H_
+ { "searchstore_interface", sizeof(struct searchstore_interface) },
+ #else
+ #define _MAP_SEARCHSTORE_H_
+ #endif // _MAP_SEARCHSTORE_H_
+ #ifdef _MAP_SKILL_H_
+ { "skill_cd", sizeof(struct skill_cd) },
+ { "skill_condition", sizeof(struct skill_condition) },
+ { "skill_interface", sizeof(struct skill_interface) },
+ { "skill_unit_save", sizeof(struct skill_unit_save) },
+ #else
+ #define _MAP_SKILL_H_
+ #endif // _MAP_SKILL_H_
+};
+HPExport unsigned int HPMDataCheckLen = ARRAYLENGTH(HPMDataCheck);
+
+#endif /* _HPM_DATA_CHECK_H_ */
diff --git a/src/common/HPMi.h b/src/common/HPMi.h
index 9c2a6184e..95037fd14 100644
--- a/src/common/HPMi.h
+++ b/src/common/HPMi.h
@@ -1,8 +1,8 @@
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file
-#ifndef _HPMi_H_
-#define _HPMi_H_
+#ifndef _COMMON_HPMI_H_
+#define _COMMON_HPMI_H_
#include "../common/cbasetypes.h"
#include "../common/core.h"
@@ -20,7 +20,7 @@ struct map_session_data;
#define HPExport
#endif
-#ifndef _SHOWMSG_H_
+#ifndef _COMMON_SHOWMSG_H_
HPExport void (*ShowMessage) (const char *, ...);
HPExport void (*ShowStatus) (const char *, ...);
HPExport void (*ShowSQL) (const char *, ...);
@@ -36,6 +36,7 @@ struct map_session_data;
#include "../common/showmsg.h"
#define HPM_VERSION "1.0"
+#define HPM_ADDCONF_LENGTH 40
struct hplugin_info {
char* name;
@@ -44,18 +45,24 @@ struct hplugin_info {
char* req_version;
};
+struct s_HPMDataCheck {
+ char *name;
+ unsigned int size;
+};
+
HPExport void *(*import_symbol) (char *name, unsigned int pID);
HPExport Sql *mysql_handle;
-#define GET_SYMBOL(n) import_symbol(n,HPMi->pid)
+#define GET_SYMBOL(n) import_symbol((n),HPMi->pid)
-#define SERVER_TYPE_ALL SERVER_TYPE_LOGIN|SERVER_TYPE_CHAR|SERVER_TYPE_MAP
+#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_POST_FINAL,/* server is done shutting down */
+ HPET_PRE_INIT,/* server is about to start (used to e.g. add custom "--args" handling) */
HPET_MAX,
};
@@ -76,12 +83,88 @@ enum HPluginHookType {
HOOK_TYPE_POST,
};
-#define addHookPre(tname,hook) HPMi->AddHook(HOOK_TYPE_PRE,tname,hook,HPMi->pid)
-#define addHookPost(tname,hook) HPMi->AddHook(HOOK_TYPE_POST,tname,hook,HPMi->pid)
+enum HPluginDataTypes {
+ HPDT_SESSION,
+ HPDT_MSD,
+ HPDT_NPCD,
+ HPDT_MAP,
+ HPDT_INSTANCE,
+ HPDT_GUILD,
+ HPDT_PARTY,
+};
+
+/* used in macros and conf storage */
+enum HPluginConfType {
+ HPCT_BATTLE, /* battle-conf (map-server */
+ HPCT_MAX,
+};
+
+#define addHookPre(tname,hook) (HPMi->AddHook(HOOK_TYPE_PRE,(tname),(hook),HPMi->pid))
+#define addHookPost(tname,hook) (HPMi->AddHook(HOOK_TYPE_POST,(tname),(hook),HPMi->pid))
/* need better names ;/ */
/* will not run the original function after pre-hook processing is complete (other hooks will run) */
-#define hookStop() HPMi->HookStop(__func__,HPMi->pid)
-#define hookStopped() HPMi->HookStopped()
+#define hookStop() (HPMi->HookStop(__func__,HPMi->pid))
+#define hookStopped() (HPMi->HookStopped())
+
+#define addArg(name,param,func,help) (HPMi->addArg(HPMi->pid,(name),(param),(func),(help)))
+/* HPData handy redirects */
+/* session[] */
+#define addToSession(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_SESSION,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromSession(ptr,index) (HPMi->getFromHPData(HPDT_SESSION,HPMi->pid,(ptr),(index)))
+#define removeFromSession(ptr,index) (HPMi->removeFromHPData(HPDT_SESSION,HPMi->pid,(ptr),(index)))
+/* map_session_data */
+#define addToMSD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MSD,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromMSD(ptr,index) (HPMi->getFromHPData(HPDT_MSD,HPMi->pid,(ptr),(index)))
+#define removeFromMSD(ptr,index) (HPMi->removeFromHPData(HPDT_MSD,HPMi->pid,(ptr),(index)))
+/* npc_data */
+#define addToNPCD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_NPCD,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromNPCD(ptr,index) (HPMi->getFromHPData(HPDT_NPCD,HPMi->pid,(ptr),(index)))
+#define removeFromNPCD(ptr,index) (HPMi->removeFromHPData(HPDT_NPCD,HPMi->pid,(ptr),(index)))
+/* map_data */
+#define addToMAPD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_MAP,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromMAPD(ptr,index) (HPMi->getFromHPData(HPDT_MAP,HPMi->pid,(ptr),(index)))
+#define removeFromMAPD(ptr,index) (HPMi->removeFromHPData(HPDT_MAP,HPMi->pid,(ptr),(index)))
+/* party_data */
+#define addToPAD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_PARTY,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromPAD(ptr,index) (HPMi->getFromHPData(HPDT_PARTY,HPMi->pid,(ptr),(index)))
+#define removeFromPAD(ptr,index) (HPMi->removeFromHPData(HPDT_PARTY,HPMi->pid,(ptr),(index)))
+/* guild */
+#define addToGLD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_GUILD,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromGLD(ptr,index) (HPMi->getFromHPData(HPDT_GUILD,HPMi->pid,(ptr),(index)))
+#define removeFromGLD(ptr,index) (HPMi->removeFromHPData(HPDT_GUILD,HPMi->pid,(ptr),(index)))
+/* instance_data */
+#define addToINSTD(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(data),(index),(autofree)))
+#define getFromINSTD(ptr,index) (HPMi->getFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(index)))
+#define removeFromINSTD(ptr,index) (HPMi->removeFromHPData(HPDT_INSTANCE,HPMi->pid,(ptr),(index)))
+
+/* HPMi->addCommand */
+#define addAtcommand(cname,funcname) \
+ if ( HPMi->addCommand != NULL ) { \
+ HPMi->addCommand(cname,atcommand_ ## funcname); \
+ } else { \
+ ShowWarning("HPM (%s):addAtcommand(\"%s\",%s) failed, addCommand sub is NULL!\n",pinfo.name,cname,# funcname);\
+ }
+/* HPMi->addScript */
+#define addScriptCommand(cname,scinfo,funcname) \
+ if ( HPMi->addScript != NULL ) { \
+ HPMi->addScript(cname,scinfo,buildin_ ## funcname); \
+ } else { \
+ ShowWarning("HPM (%s):addScriptCommand(\"%s\",\"%s\",%s) failed, addScript sub is NULL!\n",pinfo.name,cname,scinfo,# funcname);\
+ }
+/* HPMi->addCPCommand */
+#define addCPCommand(cname,funcname) \
+ if ( HPMi->addCPCommand != NULL ) { \
+ HPMi->addCPCommand(cname,console_parse_ ## funcname); \
+ } else { \
+ ShowWarning("HPM (%s):addCPCommand(\"%s\",%s) failed, addCPCommand sub is NULL!\n",pinfo.name,cname,# funcname);\
+ }
+/* HPMi->addPacket */
+#define addPacket(cmd,len,receive,point) HPMi->addPacket(cmd,len,receive,point,HPMi->pid)
+/* HPMi->addBattleConf */
+#define addBattleConf(bcname,funcname) HPMi->addConf(HPMi->pid,HPCT_BATTLE,bcname,funcname)
+
+/* HPMi->addPCGPermission */
+#define addGroupPermission(pcgname,maskptr) HPMi->addPCGPermission(HPMi->pid,pcgname,&maskptr)
/* Hercules Plugin Mananger Include Interface */
HPExport struct HPMi_interface {
@@ -92,23 +175,25 @@ HPExport struct HPMi_interface {
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);
- /* map_session_data */
- void (*addToMSD) (struct map_session_data *sd, void *data, unsigned int id, unsigned int type, bool autofree);
- void *(*getFromMSD) (struct map_session_data *sd, unsigned int id, unsigned int type);
- void (*removeFromMSD) (struct map_session_data *sd, unsigned int id, unsigned int type);
- /* session[] */
- void (*addToSession) (struct socket_data *sess, void *data, unsigned int id, unsigned int type, bool autofree);
- void *(*getFromSession) (struct socket_data *sess, unsigned int id, unsigned int type);
- void (*removeFromSession) (struct socket_data *sess, unsigned int id, unsigned int type);
+ /* HPM Custom Data */
+ void (*addToHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, void *data, unsigned int index, bool autofree);
+ void *(*getFromHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index);
+ void (*removeFromHPData) (enum HPluginDataTypes type, unsigned int pluginID, void *ptr, unsigned int index);
/* packet */
bool (*addPacket) (unsigned short cmd, unsigned short length, void (*receive)(int fd), unsigned int point, unsigned int pluginID);
/* Hooking */
bool (*AddHook) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID);
void (*HookStop) (const char *func, unsigned int pID);
bool (*HookStopped) (void);
+ /* program --arg/-a */
+ bool (*addArg) (unsigned int pluginID, char *name, bool has_param,void (*func) (char *param),void (*help) (void));
+ /* battle-config recv param */
+ bool (*addConf) (unsigned int pluginID, enum HPluginConfType type, char *name, void (*func) (const char *val));
+ /* pc group permission */
+ void (*addPCGPermission) (unsigned int pluginID, char *name, unsigned int *mask);
} HPMi_s;
-#ifndef _HPM_H_
+#ifndef _COMMON_HPM_H_
HPExport struct HPMi_interface *HPMi;
#endif
-#endif /* _HPMi_H_ */
+#endif /* _COMMON_HPMI_H_ */
diff --git a/src/common/Makefile.in b/src/common/Makefile.in
index 53b7a472e..7bb9ae630 100644
--- a/src/common/Makefile.in
+++ b/src/common/Makefile.in
@@ -1,31 +1,37 @@
-MT19937AR_D = ../../3rdparty/mt19937ar
-MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o
-MT19937AR_H = $(MT19937AR_D)/mt19937ar.h
-MT19937AR_INCLUDE = -I$(MT19937AR_D)
+CONFIG_D = ../config
+CONFIG_H = $(wildcard $(CONFIG_D)/*.h) $(wildcard $(CONFIG_D)/*/*.h)
LIBCONFIG_D = ../../3rdparty/libconfig
LIBCONFIG_OBJ = $(addprefix $(LIBCONFIG_D)/, libconfig.o grammar.o scanctx.o \
- scanner.o strbuf.o)
+ scanner.o strbuf.o)
LIBCONFIG_H = $(addprefix $(LIBCONFIG_D)/, libconfig.h grammar.h parsectx.h \
- scanctx.h scanner.h strbuf.h wincompat.h)
+ scanctx.h scanner.h strbuf.h wincompat.h)
LIBCONFIG_INCLUDE = -I$(LIBCONFIG_D)
-COMMON_SHARED_OBJ = conf.o db.o des.o ers.o grfio.o HPM.o mapindex.o \
- md5calc.o mempool.o mutex.o nullpo.o raconf.o random.o \
- showmsg.o strlib.o thread.o timer.o utils.o
+MT19937AR_D = ../../3rdparty/mt19937ar
+MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o
+MT19937AR_H = $(MT19937AR_D)/mt19937ar.h
+MT19937AR_INCLUDE = -I$(MT19937AR_D)
+
+COMMON_SHARED_C = conf.c db.c des.c ers.c grfio.c HPM.c mapindex.c md5calc.c \
+ mutex.c nullpo.c random.c showmsg.c strlib.c thread.c \
+ timer.c utils.c
+COMMON_C = $(COMMON_SHARED_C)
+COMMON_SHARED_OBJ = $(patsubst %.c,%.o,$(COMMON_SHARED_C))
COMMON_OBJ = $(addprefix obj_all/, $(COMMON_SHARED_OBJ) \
- console.o core.o malloc.o socket.o)
+ console.o core.o malloc.o socket.o)
COMMON_MINI_OBJ = $(addprefix obj_all/, $(COMMON_SHARED_OBJ) \
- miniconsole.o minicore.o minimalloc.o minisocket.o)
+ miniconsole.o minicore.o minimalloc.o minisocket.o)
+COMMON_C += console.c core.c malloc.c socket.c
COMMON_H = atomic.h cbasetypes.h conf.h console.h core.h db.h des.h ers.h \
- evdp.h grfio.h HPM.h HPMi.h malloc.h mapindex.h md5calc.h \
- mempool.h mmo.h mutex.h netbuffer.h network.h nullpo.h raconf.h \
- random.h showmsg.h socket.h spinlock.h sql.h strlib.h thread.h \
- timer.h utils.h winapi.h
+ grfio.h HPM.h HPMi.h malloc.h mapindex.h md5calc.h mmo.h mutex.h \
+ nullpo.h random.h showmsg.h socket.h spinlock.h sql.h strlib.h \
+ thread.h timer.h utils.h winapi.h
COMMON_SQL_OBJ = obj_sql/sql.o
COMMON_SQL_H = sql.h
+COMMON_C += sql.c
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
diff --git a/src/common/atomic.h b/src/common/atomic.h
index b1a4bda92..c2227a9d4 100644
--- a/src/common/atomic.h
+++ b/src/common/atomic.h
@@ -1,8 +1,8 @@
// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _rA_ATOMIC_H_
-#define _rA_ATOMIC_H_
+#ifndef _COMMON_ATOMIC_H_
+#define _COMMON_ATOMIC_H_
// Atomic Operations
// (Interlocked CompareExchange, Add .. and so on ..)
@@ -19,6 +19,9 @@
#if defined(_MSC_VER)
#include "../common/winapi.h"
+// This checks if C/C++ Compiler Version is 18.00
+#if _MSC_VER < 1800
+
#if !defined(_M_X64)
// When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft
// (because they need at least i586 so its not generic enough.. ... )
@@ -80,6 +83,8 @@ forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 v
#endif //endif 32bit windows
+#endif //endif _msc_ver check
+
#elif defined(__GNUC__)
#if !defined(__x86_64__) && !defined(__i386__)
@@ -139,4 +144,4 @@ static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val){
#endif //endif compiler decission
-#endif
+#endif /* _COMMON_ATOMIC_H_ */
diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h
index 1e4fc04c7..654334a9b 100644
--- a/src/common/cbasetypes.h
+++ b/src/common/cbasetypes.h
@@ -1,5 +1,5 @@
-#ifndef _CBASETYPES_H_
-#define _CBASETYPES_H_
+#ifndef _COMMON_CBASETYPES_H_
+#define _COMMON_CBASETYPES_H_
/* +--------+-----------+--------+---------+
* | ILP32 | LP64 | ILP64 | (LL)P64 |
@@ -37,11 +37,16 @@
#define CYGWIN
#endif
-// __APPLE__ is the only predefined macro on MacOS X
+// __APPLE__ is the only predefined macro on MacOS
#if defined(__APPLE__)
#define __DARWIN__
#endif
+// Necessary for __NetBSD_Version__ (defined as VVRR00PP00) on NetBSD
+#ifdef __NETBSD__
+#include <sys/param.h>
+#endif // __NETBSD__
+
// 64bit OS
#if defined(_M_IA64) || defined(_M_X64) || defined(_WIN64) || defined(_LP64) || defined(_ILP64) || defined(__LP64__) || defined(__ppc64__)
#define __64BIT__
@@ -92,9 +97,9 @@
// (-20 >= USHRT_MAX) returns true
#if defined(__FreeBSD__) && defined(__x86_64)
#undef UCHAR_MAX
-#define UCHAR_MAX (unsigned char)0xff
+#define UCHAR_MAX ((unsigned char)0xff)
#undef USHRT_MAX
-#define USHRT_MAX (unsigned short)0xffff
+#define USHRT_MAX ((unsigned short)0xffff)
#endif
// ILP64 isn't supported, so always 32 bits?
@@ -180,7 +185,7 @@ typedef unsigned long int ppuint32;
#if defined(WIN32) && !defined(MINGW) // does not have a signed size_t
//////////////////////////////
-#if defined(_WIN64) // naive 64bit windows platform
+#if defined(_WIN64) // native 64bit windows platform
typedef __int64 ssize_t;
#else
typedef int ssize_t;
@@ -255,6 +260,13 @@ typedef uintptr_t uintptr;
#define ra_align(n) __attribute__(( aligned(n) ))
#endif
+// Directives for the (clang) static analyzer
+#ifdef __clang__
+#define analyzer_noreturn __attribute__((analyzer_noreturn))
+#else
+#define analyzer_noreturn
+#endif
+
/////////////////////////////
// for those still not building c++
@@ -293,7 +305,9 @@ typedef char bool;
// if using macros then something that is type independent
//#define swap(a,b) ((a == b) || ((a ^= b), (b ^= a), (a ^= b)))
// Avoid "value computed is not used" warning and generates the same assembly code
-#define swap(a,b) if (a != b) ((a ^= b), (b ^= a), (a ^= b))
+//#define swap(a,b) if (a != b) ((a ^= b), (b ^= a), (a ^= b))
+// but is vulnerable to 'if (foo) swap(bar, baz); else quux();', causing the else to nest incorrectly.
+#define swap(a,b) do { if ((a) != (b)) { (a) ^= (b); (b) ^= (a); (a) ^= (b); } } while(0)
#if 0 //to be activated soon, more tests needed on how VS works with the macro above
#ifdef WIN32
#undef swap
@@ -313,7 +327,7 @@ typedef char bool;
#endif
#endif
-#define swap_ptr(a,b) if ((a) != (b)) ((a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)), (b) = (void*)((intptr_t)(a) ^ (intptr_t)(b)), (a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)))
+#define swap_ptr(a,b) do { if ((a) != (b)) (a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); (b) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); (a) = (void*)((intptr_t)(a) ^ (intptr_t)(b)); } while(0)
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
@@ -341,8 +355,8 @@ typedef char bool;
#if defined(WIN32)
#define PATHSEP '\\'
#define PATHSEP_STR "\\"
-#elif defined(__APPLE__)
-// FIXME Mac OS X is unix based, is this still correct?
+#elif defined(__APPLE__) && !defined(__MACH__)
+// __MACH__ indicates OS X ( http://sourceforge.net/p/predef/wiki/OperatingSystems/ )
#define PATHSEP ':'
#define PATHSEP_STR ":"
#else
@@ -351,23 +365,6 @@ typedef char bool;
#endif
//////////////////////////////////////////////////////////////////////////
-// Assert
-
-#if ! defined(Assert)
-#if defined(RELEASE)
-#define Assert(EX)
-#else
-// extern "C" {
-#include <assert.h>
-// }
-#if !defined(DEFCPP) && defined(WIN32) && !defined(MINGW)
-#include <crtdbg.h>
-#endif
-#define Assert(EX) assert(EX)
-#endif
-#endif /* ! defined(Assert) */
-
-//////////////////////////////////////////////////////////////////////////
// Has to be unsigned to avoid problems in some systems
// Problems arise when these functions expect an argument in the range [0,256[ and are fed a signed char.
#include <ctype.h>
@@ -403,7 +400,7 @@ typedef char bool;
//////////////////////////////////////////////////////////////////////////
-// Use the preprocessor to 'stringify' stuff (concert to a string).
+// Use the preprocessor to 'stringify' stuff (convert to a string).
// example:
// #define TESTE blabla
// QUOTE(TESTE) -> "TESTE"
@@ -429,9 +426,9 @@ void SET_FUNCPOINTER(T1& var, T2 p)
var = tmp.out;
}
#else
-#define SET_POINTER(var,p) (var) = (p)
-#define SET_FUNCPOINTER(var,p) (var) = (p)
+#define SET_POINTER(var,p) ((var) = (p))
+#define SET_FUNCPOINTER(var,p) ((var) = (p))
#endif
-#endif /* _CBASETYPES_H_ */
+#endif /* _COMMON_CBASETYPES_H_ */
diff --git a/src/common/conf.c b/src/common/conf.c
index 6802f728b..b816b2f7f 100644
--- a/src/common/conf.c
+++ b/src/common/conf.c
@@ -1,18 +1,22 @@
-// 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 "conf.h"
#include "../../3rdparty/libconfig/libconfig.h"
#include "../common/showmsg.h" // ShowError
-int conf_read_file(config_t *config, const char *config_filename)
-{
- config_init(config);
- if (!config_read_file(config, config_filename)) {
+/* interface source */
+struct libconfig_interface libconfig_s;
+
+
+int conf_read_file(config_t *config, const char *config_filename) {
+ libconfig->init(config);
+ if (!libconfig->read_file_src(config, config_filename)) {
ShowError("%s:%d - %s\n", config_error_file(config),
config_error_line(config), config_error_text(config));
- config_destroy(config);
+ libconfig->destroy(config);
return 1;
}
return 0;
@@ -21,65 +25,63 @@ int conf_read_file(config_t *config, const char *config_filename)
//
// Functions to copy settings from libconfig/contrib
//
-static void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src);
-static void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src);
-static void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src);
-int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
-
-void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src)
-{
+void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src) {
if (config_setting_is_aggregate(src)) {
- config_setting_copy_aggregate(parent, src);
+ libconfig->setting_copy_aggregate(parent, src);
}
else {
- config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
-
- if (set == NULL)
+ config_setting_t *set;
+
+ if( libconfig->setting_get_member(parent, config_setting_name(src)) != NULL )
+ return;
+
+ if ((set = libconfig->setting_add(parent, config_setting_name(src), config_setting_type(src))) == NULL)
return;
if (CONFIG_TYPE_INT == config_setting_type(src)) {
- config_setting_set_int(set, config_setting_get_int(src));
- config_setting_set_format(set, src->format);
+ libconfig->setting_set_int(set, libconfig->setting_get_int(src));
+ libconfig->setting_set_format(set, src->format);
} else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
- config_setting_set_int64(set, config_setting_get_int64(src));
- config_setting_set_format(set, src->format);
+ libconfig->setting_set_int64(set, libconfig->setting_get_int64(src));
+ libconfig->setting_set_format(set, src->format);
} else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
- config_setting_set_float(set, config_setting_get_float(src));
+ libconfig->setting_set_float(set, libconfig->setting_get_float(src));
} else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
- config_setting_set_string(set, config_setting_get_string(src));
+ libconfig->setting_set_string(set, libconfig->setting_get_string(src));
} else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
- config_setting_set_bool(set, config_setting_get_bool(src));
+ libconfig->setting_set_bool(set, libconfig->setting_get_bool(src));
}
}
}
-void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src)
-{
+void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src) {
config_setting_t *set = NULL;
if (config_setting_is_aggregate(src))
- config_setting_copy_aggregate(parent, src);
+ libconfig->setting_copy_aggregate(parent, src);
else if (CONFIG_TYPE_INT == config_setting_type(src)) {
- set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src));
- config_setting_set_format(set, src->format);
+ set = libconfig->setting_set_int_elem(parent, -1, libconfig->setting_get_int(src));
+ libconfig->setting_set_format(set, src->format);
} else if (CONFIG_TYPE_INT64 == config_setting_type(src)) {
- set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src));
- config_setting_set_format(set, src->format);
+ set = libconfig->setting_set_int64_elem(parent, -1, libconfig->setting_get_int64(src));
+ libconfig->setting_set_format(set, src->format);
} else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) {
- config_setting_set_float_elem(parent, -1, config_setting_get_float(src));
+ libconfig->setting_set_float_elem(parent, -1, libconfig->setting_get_float(src));
} else if (CONFIG_TYPE_STRING == config_setting_type(src)) {
- config_setting_set_string_elem(parent, -1, config_setting_get_string(src));
+ libconfig->setting_set_string_elem(parent, -1, libconfig->setting_get_string(src));
} else if (CONFIG_TYPE_BOOL == config_setting_type(src)) {
- config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src));
+ libconfig->setting_set_bool_elem(parent, -1, libconfig->setting_get_bool(src));
}
}
-void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src)
-{
+void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src) {
config_setting_t *newAgg;
int i, n;
- newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src));
+ if( libconfig->setting_get_member(parent, config_setting_name(src)) != NULL )
+ return;
+
+ newAgg = libconfig->setting_add(parent, config_setting_name(src), config_setting_type(src));
if (newAgg == NULL)
return;
@@ -88,22 +90,101 @@ void config_setting_copy_aggregate(config_setting_t *parent, const config_settin
for (i = 0; i < n; i++) {
if (config_setting_is_group(src)) {
- config_setting_copy_simple(newAgg, config_setting_get_elem(src, i));
+ libconfig->setting_copy_simple(newAgg, libconfig->setting_get_elem(src, i));
} else {
- config_setting_copy_elem(newAgg, config_setting_get_elem(src, i));
+ libconfig->setting_copy_elem(newAgg, libconfig->setting_get_elem(src, i));
}
}
}
-int config_setting_copy(config_setting_t *parent, const config_setting_t *src)
-{
+int config_setting_copy(config_setting_t *parent, const config_setting_t *src) {
+
if (!config_setting_is_group(parent) && !config_setting_is_list(parent))
return CONFIG_FALSE;
if (config_setting_is_aggregate(src)) {
- config_setting_copy_aggregate(parent, src);
+ libconfig->setting_copy_aggregate(parent, src);
} else {
- config_setting_copy_simple(parent, src);
+ libconfig->setting_copy_simple(parent, src);
}
return CONFIG_TRUE;
}
+
+void libconfig_defaults(void) {
+ libconfig = &libconfig_s;
+
+ libconfig->read = config_read;
+ libconfig->write = config_write;
+ /* */
+ libconfig->set_auto_convert = config_set_auto_convert;
+ libconfig->get_auto_convert = config_get_auto_convert;
+ /* */
+ libconfig->read_string = config_read_string;
+ libconfig->read_file_src = config_read_file;
+ libconfig->write_file = config_write_file;
+ /* */
+ libconfig->set_destructor = config_set_destructor;
+ libconfig->set_include_dir = config_set_include_dir;
+ /* */
+ libconfig->init = config_init;
+ libconfig->destroy = config_destroy;
+ /* */
+ libconfig->setting_get_int = config_setting_get_int;
+ libconfig->setting_get_int64 = config_setting_get_int64;
+ libconfig->setting_get_float = config_setting_get_float;
+ libconfig->setting_get_bool = config_setting_get_bool;
+ libconfig->setting_get_string = config_setting_get_string;
+ /* */
+ libconfig->setting_lookup_int = config_setting_lookup_int;
+ libconfig->setting_lookup_int64 = config_setting_lookup_int64;
+ libconfig->setting_lookup_float = config_setting_lookup_float;
+ libconfig->setting_lookup_bool = config_setting_lookup_bool;
+ libconfig->setting_lookup_string = config_setting_lookup_string;
+ /* */
+ libconfig->setting_set_int = config_setting_set_int;
+ libconfig->setting_set_int64 = config_setting_set_int64;
+ libconfig->setting_set_bool = config_setting_set_bool;
+ libconfig->setting_set_string = config_setting_set_string;
+ /* */
+ libconfig->setting_set_format = config_setting_set_format;
+ libconfig->setting_get_format = config_setting_get_format;
+ /* */
+ libconfig->setting_get_int_elem = config_setting_get_int_elem;
+ libconfig->setting_get_int64_elem = config_setting_get_int64_elem;
+ libconfig->setting_get_float_elem = config_setting_get_float_elem;
+ libconfig->setting_get_bool_elem = config_setting_get_bool_elem;
+ libconfig->setting_get_string_elem = config_setting_get_string_elem;
+ /* */
+ libconfig->setting_set_int_elem = config_setting_set_int_elem;
+ libconfig->setting_set_int64_elem = config_setting_set_int64_elem;
+ libconfig->setting_set_float_elem = config_setting_set_float_elem;
+ libconfig->setting_set_bool_elem = config_setting_set_bool_elem;
+ libconfig->setting_set_string_elem = config_setting_set_string_elem;
+ /* */
+ libconfig->setting_index = config_setting_index;
+ libconfig->setting_length = config_setting_length;
+ /* */
+ libconfig->setting_get_elem = config_setting_get_elem;
+ libconfig->setting_get_member = config_setting_get_member;
+ /* */
+ libconfig->setting_add = config_setting_add;
+ libconfig->setting_remove = config_setting_remove;
+ libconfig->setting_remove_elem = config_setting_remove_elem;
+ /* */
+ libconfig->setting_set_hook = config_setting_set_hook;
+ /* */
+ libconfig->lookup = config_lookup;
+ libconfig->lookup_from = config_lookup_from;
+ /* */
+ libconfig->lookup_int = config_lookup_int;
+ libconfig->lookup_int64 = config_lookup_int64;
+ libconfig->lookup_float = config_lookup_float;
+ libconfig->lookup_bool = config_lookup_bool;
+ libconfig->lookup_string = config_lookup_string;
+ /* those are custom and are from src/common/conf.c */
+ libconfig->read_file = conf_read_file;
+ libconfig->setting_copy_simple = config_setting_copy_simple;
+ libconfig->setting_copy_elem = config_setting_copy_elem;
+ libconfig->setting_copy_aggregate = config_setting_copy_aggregate;
+ libconfig->setting_copy = config_setting_copy;
+}
diff --git a/src/common/conf.h b/src/common/conf.h
index d223505db..9aff3df47 100644
--- a/src/common/conf.h
+++ b/src/common/conf.h
@@ -1,13 +1,97 @@
-// 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 _CONF_H_
-#define _CONF_H_
+#ifndef _COMMON_CONF_H_
+#define _COMMON_CONF_H_
#include "../common/cbasetypes.h"
#include "../../3rdparty/libconfig/libconfig.h"
-int conf_read_file(config_t *config, const char *config_filename);
-int config_setting_copy(config_setting_t *parent, const config_setting_t *src);
+/**
+ * The libconfig interface -- specially for plugins, but we enforce it throughought the core to be consistent
+ **/
+struct libconfig_interface {
+ int (*read) (config_t *config, FILE *stream);
+ void (*write) (const config_t *config, FILE *stream);
+ /* */
+ void (*set_auto_convert) (config_t *config, int flag);
+ int (*get_auto_convert) (const config_t *config);
+ /* */
+ int (*read_string) (config_t *config, const char *str);
+ int (*read_file_src) (config_t *config, const char *filename);
+ int (*write_file) (config_t *config, const char *filename);
+
+ void (*set_destructor) (config_t *config, void (*destructor)(void *));
+ void (*set_include_dir) (config_t *config, const char *include_dir);
+
+ void (*init) (config_t *config);
+ void (*destroy) (config_t *config);
+
+ int (*setting_get_int) (const config_setting_t *setting);
+ long long (*setting_get_int64) (const config_setting_t *setting);
+ double (*setting_get_float) (const config_setting_t *setting);
+
+ int (*setting_get_bool) (const config_setting_t *setting);
+
+ const char * (*setting_get_string) (const config_setting_t *setting);
+
+ int (*setting_lookup_int) (const config_setting_t *setting, const char *name, int *value);
+ int (*setting_lookup_int64) (const config_setting_t *setting, const char *name, long long *value);
+ int (*setting_lookup_float) (const config_setting_t *setting, const char *name, double *value);
+ int (*setting_lookup_bool) (const config_setting_t *setting, const char *name, int *value);
+ int (*setting_lookup_string) (const config_setting_t *setting, const char *name, const char **value);
+ int (*setting_set_int) (config_setting_t *setting ,int value);
+ int (*setting_set_int64) (config_setting_t *setting, long long value);
+ int (*setting_set_float) (config_setting_t *setting, double value);
+ int (*setting_set_bool) (config_setting_t *setting, int value);
+ int (*setting_set_string) (config_setting_t *setting, const char *value);
+
+ int (*setting_set_format) (config_setting_t *setting, short format);
+ short (*setting_get_format) (const config_setting_t *setting);
+
+ int (*setting_get_int_elem) (const config_setting_t *setting, int idx);
+ long long (*setting_get_int64_elem) (const config_setting_t *setting, int idx);
+ double (*setting_get_float_elem) (const config_setting_t *setting, int idx);
+ int (*setting_get_bool_elem) (const config_setting_t *setting, int idx);
+ const char * (*setting_get_string_elem) (const config_setting_t *setting, int idx);
+ config_setting_t * (*setting_set_int_elem) (config_setting_t *setting, int idx, int value);
+ config_setting_t * (*setting_set_int64_elem) (config_setting_t *setting, int idx, long long value);
+ config_setting_t * (*setting_set_float_elem) (config_setting_t *setting, int idx, double value);
+ config_setting_t * (*setting_set_bool_elem) (config_setting_t *setting, int idx, int value);
+ config_setting_t * (*setting_set_string_elem) (config_setting_t *setting, int idx, const char *value);
+
+ int (*setting_index) (const config_setting_t *setting);
+ int (*setting_length) (const config_setting_t *setting);
+
+ config_setting_t * (*setting_get_elem) (const config_setting_t *setting, unsigned int idx);
+ config_setting_t * (*setting_get_member) (const config_setting_t *setting, const char *name);
+
+ config_setting_t * (*setting_add) (config_setting_t *parent, const char *name, int type);
+ int (*setting_remove) (config_setting_t *parent, const char *name);
+
+ int (*setting_remove_elem) (config_setting_t *parent, unsigned int idx);
+ void (*setting_set_hook) (config_setting_t *setting, void *hook);
+
+ config_setting_t * (*lookup) (const config_t *config, const char *path);
+ config_setting_t * (*lookup_from) (config_setting_t *setting, const char *path);
+ int (*lookup_int) (const config_t *config, const char *path, int *value);
+ int (*lookup_int64) (const config_t *config, const char *path, long long *value);
+ int (*lookup_float) (const config_t *config, const char *path, double *value);
+ int (*lookup_bool) (const config_t *config, const char *path, int *value);
+ int (*lookup_string) (const config_t *config, const char *path, const char **value);
+
+ /* those are custom and are from src/common/conf.c */
+ /* Functions to copy settings from libconfig/contrib */
+ int (*read_file) (config_t *config, const char *config_filename);
+ void (*setting_copy_simple) (config_setting_t *parent, const config_setting_t *src);
+ void (*setting_copy_elem) (config_setting_t *parent, const config_setting_t *src);
+ void (*setting_copy_aggregate) (config_setting_t *parent, const config_setting_t *src);
+ int (*setting_copy) (config_setting_t *parent, const config_setting_t *src);
+};
-#endif // _CONF_H_
+struct libconfig_interface *libconfig;
+
+void libconfig_defaults(void);
+
+#endif // _COMMON_CONF_H_
diff --git a/src/common/console.c b/src/common/console.c
index b25de84b3..94824dc25 100644
--- a/src/common/console.c
+++ b/src/common/console.c
@@ -175,6 +175,10 @@ void console_load_defaults(void) {
}
}
}
+#undef CP_DEF_C
+#undef CP_DEF_C2
+#undef CP_DEF_S
+#undef CP_DEF
void console_parse_create(char *name, CParseFunc func) {
unsigned int i;
char *tok;
@@ -344,7 +348,7 @@ void *cThread_main(void *x) {
return NULL;
}
-int console_parse_timer(int tid, unsigned int tick, int id, intptr_t data) {
+int console_parse_timer(int tid, int64 tick, int id, intptr_t data) {
int i;
EnterSpinLock(&console->ptlock);
for(i = 0; i < cinput.count; i++) {
diff --git a/src/common/console.h b/src/common/console.h
index cef898f17..513c769ff 100644
--- a/src/common/console.h
+++ b/src/common/console.h
@@ -1,8 +1,8 @@
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file
-#ifndef _CONSOLE_H_
-#define _CONSOLE_H_
+#ifndef _COMMON_CONSOLE_H_
+#define _COMMON_CONSOLE_H_
#include "../common/thread.h"
#include "../common/mutex.h"
@@ -56,7 +56,7 @@ struct console_interface {
/* */
void (*parse_init) (void);
void (*parse_final) (void);
- int (*parse_timer) (int tid, unsigned int tick, int id, intptr_t data);
+ int (*parse_timer) (int tid, int64 tick, int id, intptr_t data);
void *(*pthread_main) (void *x);
void (*parse) (char* line);
void (*parse_sub) (char* line);
@@ -72,4 +72,4 @@ struct console_interface *console;
void console_defaults(void);
-#endif /* _CONSOLE_H_ */
+#endif /* _COMMON_CONSOLE_H_ */
diff --git a/src/common/core.c b/src/common/core.c
index 6a73d2d39..86634ec4b 100644
--- a/src/common/core.c
+++ b/src/common/core.c
@@ -8,17 +8,18 @@
#include "../common/strlib.h"
#include "core.h"
#include "../common/console.h"
+#include "../common/random.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/sql.h"
#include "../config/core.h"
#include "../common/HPM.h"
#include "../common/utils.h"
+ #include "../common/conf.h"
#endif
#include <stdio.h>
@@ -52,7 +53,7 @@ char *SERVER_NAME = NULL;
#endif
#ifndef POSIX
-#define compat_signal(signo, func) signal(signo, func)
+#define compat_signal(signo, func) signal((signo), (func))
#else
sigfunc *compat_signal(int signo, sigfunc *func) {
struct sigaction sact, oact;
@@ -282,9 +283,11 @@ void core_defaults(void) {
strlib_defaults();
malloc_defaults();
#ifndef MINICORE
+ libconfig_defaults();
sql_defaults();
timer_defaults();
db_defaults();
+ socket_defaults();
#endif
}
/*======================================
@@ -302,10 +305,20 @@ int main (int argc, char **argv) {
arg_v = argv;
}
core_defaults();
+
+ {
+ int i;
+ for(i = 0; i < argc; i++) {
+ if( strcmp(argv[i], "--script-check") == 0 ) {
+ msg_silent = 0x7; // silence information and status messages
+ }
+ }
+ }
iMalloc->init();// needed for Show* in display_title() [FlavioJS]
-
- console->display_title();
+
+ if (!(msg_silent&0x1))
+ console->display_title();
#ifdef MINICORE // minimalist Core
usercheck();
@@ -317,7 +330,6 @@ int main (int argc, char **argv) {
Sql_Init();
rathread_init();
- mempool_init();
DB->init();
signals_init();
@@ -327,6 +339,10 @@ int main (int argc, char **argv) {
timer->init();
+ /* timer first */
+ rnd_init();
+ srand((unsigned int)timer->gettick());
+
console->init();
HCache->init();
@@ -335,14 +351,14 @@ int main (int argc, char **argv) {
HPM->init();
#endif
- socket_init();
+ sockt->init();
do_init(argc,argv);
{// Main runtime cycle
int next;
while (runflag != CORE_ST_STOP) {
- next = timer->do_timer(timer->gettick_nocache());
- do_sockets(next);
+ next = timer->perform(timer->gettick_nocache());
+ sockt->perform(next);
}
}
@@ -353,9 +369,8 @@ int main (int argc, char **argv) {
HPM->final();
#endif
timer->final();
- socket_final();
+ sockt->final();
DB->final();
- mempool_final();
rathread_final();
#endif
diff --git a/src/common/core.h b/src/common/core.h
index 8fdcdcfc3..72f956e1d 100644
--- a/src/common/core.h
+++ b/src/common/core.h
@@ -2,8 +2,8 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _CORE_H_
-#define _CORE_H_
+#ifndef _COMMON_CORE_H_
+#define _COMMON_CORE_H_
#include "../common/db.h"
#include "../common/mmo.h"
@@ -50,4 +50,4 @@ enum E_CORE_ST {
/// If NULL, runflag is set to CORE_ST_STOP instead.
extern void (*shutdown_callback)(void);
-#endif /* _CORE_H_ */
+#endif /* _COMMON_CORE_H_ */
diff --git a/src/common/db.c b/src/common/db.c
index b3a58e0a4..8c15c0feb 100644
--- a/src/common/db.c
+++ b/src/common/db.c
@@ -47,6 +47,7 @@
* - create a db that organizes itself by splaying
*
* HISTORY:
+ * 2013/08/25 - Added int64/uint64 support for keys [Ind/Hercules]
* 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.
@@ -236,10 +237,14 @@ static struct db_stats {
uint32 db_uint_alloc;
uint32 db_string_alloc;
uint32 db_istring_alloc;
+ uint32 db_int64_alloc;
+ uint32 db_uint64_alloc;
uint32 db_int_destroy;
uint32 db_uint_destroy;
uint32 db_string_destroy;
uint32 db_istring_destroy;
+ uint32 db_int64_destroy;
+ uint32 db_uint64_destroy;
// Function usage counters
uint32 db_rotate_left;
uint32 db_rotate_right;
@@ -256,10 +261,14 @@ static struct db_stats {
uint32 db_uint_cmp;
uint32 db_string_cmp;
uint32 db_istring_cmp;
+ uint32 db_int64_cmp;
+ uint32 db_uint64_cmp;
uint32 db_int_hash;
uint32 db_uint_hash;
uint32 db_string_hash;
uint32 db_istring_hash;
+ uint32 db_int64_hash;
+ uint32 db_uint64_hash;
uint32 db_release_nothing;
uint32 db_release_key;
uint32 db_release_data;
@@ -298,6 +307,8 @@ static struct db_stats {
uint32 db_i2key;
uint32 db_ui2key;
uint32 db_str2key;
+ uint32 db_i642key;
+ uint32 db_ui642key;
uint32 db_i2data;
uint32 db_ui2data;
uint32 db_ptr2data;
@@ -315,7 +326,7 @@ static struct db_stats {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
-#define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token
+#define DB_COUNTSTAT(token) do { if (stats. ## token != UINT32_MAX) ++stats. ## token ; } while(0)
#else /* !defined(DB_ENABLE_STATS) */
#define DB_COUNTSTAT(token)
#endif /* !defined(DB_ENABLE_STATS) */
@@ -830,10 +841,14 @@ static void db_free_unlock(DBMap_impl* db)
* 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_int64_cmp - Default comparator for DB_INT64 databases. *
+ * db_uint64_cmp - Default comparator for DB_UINT64 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_int64_hash - Default hasher for DB_INT64 databases. *
+ * db_uint64_hash - Default hasher for DB_UINT64 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. *
@@ -921,6 +936,51 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
}
/**
+ * Default comparator for DB_INT64 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_INT64
+ * @see #DBComparator
+ * @see #db_default_cmp(DBType)
+ */
+static int db_int64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_int64_cmp);
+ if (key1.i64 < key2.i64) return -1;
+ if (key1.i64 > key2.i64) return 1;
+ return 0;
+}
+
+/**
+ * Default comparator for DB_UINT64 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_UINT64
+ * @see #DBComparator
+ * @see #db_default_cmp(DBType)
+ */
+static int db_uint64_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_uint64_cmp);
+ if (key1.ui64 < key2.ui64) return -1;
+ if (key1.ui64 > key2.ui64) return 1;
+ return 0;
+}
+
+
+/**
* Default hasher for DB_INT databases.
* Returns the value of the key as an unsigned int.
* <code>maxlen</code> is ignored.
@@ -931,11 +991,11 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_int_hash(DBKey key, unsigned short maxlen)
+static uint64 db_int_hash(DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_int_hash);
- return (unsigned int)key.i;
+ return (uint64)key.i;
}
/**
@@ -949,11 +1009,11 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
+static uint64 db_uint_hash(DBKey key, unsigned short maxlen)
{
(void)maxlen;//not used
DB_COUNTSTAT(db_uint_hash);
- return key.ui;
+ return (uint64)key.ui;
}
/**
@@ -965,7 +1025,7 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
* @see #DBHasher
* @see #db_default_hash(DBType)
*/
-static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
+static uint64 db_string_hash(DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -980,7 +1040,7 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
break;
}
- return hash;
+ return (uint64)hash;
}
/**
@@ -991,7 +1051,7 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
* @see DBType#DB_ISTRING
* @see #db_default_hash(DBType)
*/
-static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
+static uint64 db_istring_hash(DBKey key, unsigned short maxlen)
{
const char *k = key.str;
unsigned int hash = 0;
@@ -1006,7 +1066,43 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
break;
}
- return hash;
+ return (uint64)hash;
+}
+
+/**
+ * Default hasher for DB_INT64 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_INT64
+ * @see #DBHasher
+ * @see #db_default_hash(DBType)
+ */
+static uint64 db_int64_hash(DBKey key, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_int64_hash);
+ return (uint64)key.i64;
+}
+
+/**
+ * Default hasher for DB_UINT64 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_UINT64
+ * @see #DBHasher
+ * @see #db_default_hash(DBType)
+ */
+static uint64 db_uint64_hash(DBKey key, unsigned short maxlen)
+{
+ (void)maxlen;//not used
+ DB_COUNTSTAT(db_uint64_hash);
+ return key.ui64;
}
/**
@@ -1696,7 +1792,7 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li
if (db->options&DB_OPT_DUP_KEY) {
node->key = db_dup_key(db, key);
if (db->options&DB_OPT_RELEASE_KEY)
- db->release(key, *data, DB_RELEASE_KEY);
+ db->release(key, node->data, DB_RELEASE_KEY);
} else {
node->key = key;
}
@@ -2122,6 +2218,8 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args)
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_INT64: DB_COUNTSTAT(db_int64_destroy); break;
+ case DB_UINT64: DB_COUNTSTAT(db_uint64_destroy); break;
}
#endif /* DB_ENABLE_STATS */
db_free_lock(db);
@@ -2246,6 +2344,8 @@ static DBOptions db_obj_options(DBMap* self)
* db_i2key - Manual cast from 'int' to 'DBKey'.
* db_ui2key - Manual cast from 'unsigned int' to 'DBKey'.
* db_str2key - Manual cast from 'unsigned char *' to 'DBKey'.
+ * db_i642key - Manual cast from 'int64' to 'DBKey'.
+ * db_ui642key - Manual cast from 'uin64' to 'DBKey'.
* db_i2data - Manual cast from 'int' to 'DBData'.
* db_ui2data - Manual cast from 'unsigned int' to 'DBData'.
* db_ptr2data - Manual cast from 'void*' to 'DBData'.
@@ -2272,7 +2372,9 @@ 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
+ case DB_UINT:
+ case DB_INT64:
+ case DB_UINT64: // Numeric database, do nothing with the keys
return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY));
default:
@@ -2292,6 +2394,8 @@ DBOptions db_fix_options(DBType type, DBOptions options)
* @see #db_uint_cmp(DBKey,DBKey,unsigned short)
* @see #db_string_cmp(DBKey,DBKey,unsigned short)
* @see #db_istring_cmp(DBKey,DBKey,unsigned short)
+ * @see #db_int64_cmp(DBKey,DBKey,unsigned short)
+ * @see #db_uint64_cmp(DBKey,DBKey,unsigned short)
*/
DBComparator db_default_cmp(DBType type)
{
@@ -2301,6 +2405,8 @@ DBComparator db_default_cmp(DBType type)
case DB_UINT: return &db_uint_cmp;
case DB_STRING: return &db_string_cmp;
case DB_ISTRING: return &db_istring_cmp;
+ case DB_INT64: return &db_int64_cmp;
+ case DB_UINT64: return &db_uint64_cmp;
default:
ShowError("db_default_cmp: Unknown database type %u\n", type);
return NULL;
@@ -2316,6 +2422,8 @@ DBComparator db_default_cmp(DBType type)
* @see #db_uint_hash(DBKey,unsigned short)
* @see #db_string_hash(DBKey,unsigned short)
* @see #db_istring_hash(DBKey,unsigned short)
+ * @see #db_int64_hash(DBKey,unsigned short)
+ * @see #db_uint64_hash(DBKey,unsigned short)
*/
DBHasher db_default_hash(DBType type)
{
@@ -2325,6 +2433,8 @@ DBHasher db_default_hash(DBType type)
case DB_UINT: return &db_uint_hash;
case DB_STRING: return &db_string_hash;
case DB_ISTRING: return &db_istring_hash;
+ case DB_INT64: return &db_int64_hash;
+ case DB_UINT64: return &db_uint64_hash;
default:
ShowError("db_default_hash: Unknown database type %u\n", type);
return NULL;
@@ -2412,6 +2522,8 @@ DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOpt
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_INT64: DB_COUNTSTAT(db_int64_alloc); break;
+ case DB_UINT64: DB_COUNTSTAT(db_uint64_alloc); break;
}
#endif /* DB_ENABLE_STATS */
db = ers_alloc(db_alloc_ers, struct DBMap_impl);
@@ -2446,7 +2558,7 @@ DBMap* db_alloc(const char *file, const char *func, int line, DBType type, DBOpt
db->free_lock = 0;
/* Other */
snprintf(ers_name, 50, "db_alloc:nodes:%s:%s:%d",func,file,line);
- db->nodes = ers_new(sizeof(struct dbn),ers_name,ERS_OPT_WAIT|ERS_OPT_FREE_NAME);
+ db->nodes = ers_new(sizeof(struct dbn),ers_name,ERS_OPT_WAIT|ERS_OPT_FREE_NAME|ERS_OPT_CLEAN);
db->cmp = DB->default_cmp(type);
db->hash = DB->default_hash(type);
db->release = DB->default_release(type, options);
@@ -2511,6 +2623,36 @@ DBKey db_str2key(const char *key)
}
/**
+ * Manual cast from 'int64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey db_i642key(int64 key)
+{
+ DBKey ret;
+
+ DB_COUNTSTAT(db_i642key);
+ ret.i64 = key;
+ return ret;
+}
+
+/**
+ * Manual cast from 'uin64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey db_ui642key(uint64 key)
+{
+ DBKey ret;
+
+ DB_COUNTSTAT(db_ui642key);
+ ret.ui64 = key;
+ return ret;
+}
+
+/**
* Manual cast from 'int' to the struct DBData.
* @param data Data to be casted
* @return The data as a DBData struct
@@ -2609,9 +2751,10 @@ void* db_data2ptr(DBData *data)
* @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_iterator_ers = ers_new(sizeof(struct DBIterator_impl),"db.c::db_iterator_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
+ db_alloc_ers = ers_new(sizeof(struct DBMap_impl),"db.c::db_alloc_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
ers_chunk_size(db_alloc_ers, 50);
+ ers_chunk_size(db_iterator_ers, 10);
DB_COUNTSTAT(db_init);
}
@@ -2632,10 +2775,14 @@ void db_final(void)
"DB_UINT : allocated %10u, destroyed %10u\n"
"DB_STRING : allocated %10u, destroyed %10u\n"
"DB_ISTRING : allocated %10u, destroyed %10u\n",
+ "DB_INT64 : allocated %10u, destroyed %10u\n"
+ "DB_UINT64 : 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);
+ stats.db_istring_alloc, stats.db_istring_destroy,
+ stats.db_int64_alloc, stats.db_int64_destroy,
+ stats.db_uint64_alloc, stats.db_uint64_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"
@@ -2645,8 +2792,10 @@ void db_final(void)
"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_int64_cmp %10u, db_uint64_cmp %10u,\n"
"db_int_hash %10u, db_uint_hash %10u,\n"
"db_string_hash %10u, db_istring_hash %10u,\n"
+ "db_int64_hash %10u, db_uint64_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"
@@ -2666,6 +2815,7 @@ void db_final(void)
"db_default_release %10u, db_custom_release %10u,\n"
"db_alloc %10u, db_i2key %10u,\n"
"db_ui2key %10u, db_str2key %10u,\n"
+ "db_i642key %10u, db_ui642key %10u,\n"
"db_i2data %10u, db_ui2data %10u,\n"
"db_ptr2data %10u, db_data2i %10u,\n"
"db_data2ui %10u, db_data2ptr %10u,\n"
@@ -2678,8 +2828,10 @@ void db_final(void)
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_int64_cmp, stats.db_uint64_cmp,
stats.db_int_hash, stats.db_uint_hash,
stats.db_string_hash, stats.db_istring_hash,
+ stats.db_int64_hash, stats.db_uint64_hash,
stats.db_release_nothing, stats.db_release_key,
stats.db_release_data, stats.db_release_both,
stats.dbit_first, stats.dbit_last,
@@ -2699,6 +2851,7 @@ void db_final(void)
stats.db_default_release, stats.db_custom_release,
stats.db_alloc, stats.db_i2key,
stats.db_ui2key, stats.db_str2key,
+ stats.db_i642key, stats.db_ui642key,
stats.db_i2data, stats.db_ui2data,
stats.db_ptr2data, stats.db_data2i,
stats.db_data2ui, stats.db_data2ptr,
@@ -2855,4 +3008,7 @@ void db_defaults(void) {
DB->str2key = db_str2key;
DB->ui2data = db_ui2data;
DB->ui2key = db_ui2key;
+ DB->i642key = db_i642key;
+ DB->ui642key = db_ui642key;
+
}
diff --git a/src/common/db.h b/src/common/db.h
index dffd2356d..67abe6f19 100644
--- a/src/common/db.h
+++ b/src/common/db.h
@@ -20,6 +20,7 @@
* - see what functions need or should be added to the database interface *
* *
* HISTORY: *
+ * 2013/08/25 - Added int64/uint64 support for keys *
* 2012/03/09 - Added enum for data types (int, uint, void*) *
* 2007/11/09 - Added an iterator to the database. *
* 2.1 (Athena build #???#) - Portability fix *
@@ -38,8 +39,8 @@
* @encoding US-ASCII *
* @see common#db.c *
\*****************************************************************************/
-#ifndef _DB_H_
-#define _DB_H_
+#ifndef _COMMON_DB_H_
+#define _COMMON_DB_H_
#include "../common/cbasetypes.h"
#include <stdarg.h>
@@ -83,6 +84,8 @@ typedef enum DBRelease {
* @param DB_UINT Uses unsigned int's for keys
* @param DB_STRING Uses strings for keys.
* @param DB_ISTRING Uses case insensitive strings for keys.
+ * @param DB_INT64 Uses int64's for keys
+ * @param DB_UINT64 Uses uint64's for keys
* @public
* @see #DBOptions
* @see #DBKey
@@ -96,7 +99,9 @@ typedef enum DBType {
DB_INT,
DB_UINT,
DB_STRING,
- DB_ISTRING
+ DB_ISTRING,
+ DB_INT64,
+ DB_UINT64,
} DBType;
/**
@@ -145,6 +150,8 @@ typedef union DBKey {
int i;
unsigned int ui;
const char *str;
+ int64 i64;
+ uint64 ui64;
} DBKey;
/**
@@ -158,7 +165,7 @@ typedef union DBKey {
typedef enum DBDataType {
DB_DATA_INT,
DB_DATA_UINT,
- DB_DATA_PTR
+ DB_DATA_PTR,
} DBDataType;
/**
@@ -245,7 +252,7 @@ typedef int (*DBComparator)(DBKey key1, DBKey key2, unsigned short maxlen);
* @public
* @see #db_default_hash(DBType)
*/
-typedef unsigned int (*DBHasher)(DBKey key, unsigned short maxlen);
+typedef uint64 (*DBHasher)(DBKey key, unsigned short maxlen);
/**
* Format of the releaser used by the database system.
@@ -598,75 +605,96 @@ 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 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 i64db_exists(db,k) ( (db)->exists((db),DB->i642key(k)) )
+#define ui64db_exists(db,k) ( (db)->exists((db),DB->ui642key(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))) )
+#define i64db_get(db,k) ( DB->data2ptr((db)->get((db),DB->i642key(k))) )
+#define ui64db_get(db,k) ( DB->data2ptr((db)->get((db),DB->ui642key(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))) )
+#define i64db_iget(db,k) ( DB->data2i((db)->get((db),DB->i642key(k))) )
+#define ui64db_iget(db,k) ( DB->data2i((db)->get((db),DB->ui642key(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))) )
+#define i64db_uiget(db,k) ( DB->data2ui((db)->get((db),DB->i642key(k))) )
+#define ui64db_uiget(db,k) ( DB->data2ui((db)->get((db),DB->ui642key(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) )
+#define i64db_put(db,k,d) ( (db)->put((db),DB->i642key(k),DB->ptr2data(d),NULL) )
+#define ui64db_put(db,k,d) ( (db)->put((db),DB->ui642key(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) )
+#define i64db_iput(db,k,d) ( (db)->put((db),DB->i642key(k),DB->i2data(d),NULL) )
+#define ui64db_iput(db,k,d) ( (db)->put((db),DB->ui642key(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) )
+#define i64db_uiput(db,k,d) ( (db)->put((db),DB->i642key(k),DB->ui2data(d),NULL) )
+#define ui64db_uiput(db,k,d) ( (db)->put((db),DB->ui642key(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 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 i64db_remove(db,k) ( (db)->remove((db),DB->i642key(k),NULL) )
+#define ui64db_remove(db,k) ( (db)->remove((db),DB->ui642key(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))) )
+#define i64db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->i642key(k),(f))) )
+#define ui64db_ensure(db,k,f) ( DB->data2ptr((db)->ensure((db),DB->ui642key(k),(f))) )
// Database creation and destruction macros
#define idb_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_INT,(opt),sizeof(int))
#define uidb_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_UINT,(opt),sizeof(unsigned int))
#define strdb_alloc(opt,maxlen) DB->alloc(__FILE__,__func__,__LINE__,DB_STRING,(opt),(maxlen))
#define stridb_alloc(opt,maxlen) DB->alloc(__FILE__,__func__,__LINE__,DB_ISTRING,(opt),(maxlen))
+#define i64db_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_INT64,(opt),sizeof(int64))
+#define ui64db_alloc(opt) DB->alloc(__FILE__,__func__,__LINE__,DB_UINT64,(opt),sizeof(uint64))
#define db_destroy(db) ( (db)->destroy((db),NULL) )
// Other macros
-#define db_clear(db) ( (db)->clear(db,NULL) )
+#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_remove(dbi) ( (dbi)->remove(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) )
@@ -682,6 +710,8 @@ struct DBMap {
* db_i2key - Manual cast from 'int' to 'DBKey'. *
* db_ui2key - Manual cast from 'unsigned int' to 'DBKey'. *
* db_str2key - Manual cast from 'unsigned char *' to 'DBKey'. *
+ * db_i642key - Manual cast from 'int64' to 'DBKey'. *
+ * db_ui642key - Manual cast from 'uint64' to 'DBKey'. *
* db_i2data - Manual cast from 'int' to 'DBData'. *
* db_ui2data - Manual cast from 'unsigned int' to 'DBData'. *
* db_ptr2data - Manual cast from 'void*' to 'DBData'. *
@@ -803,6 +833,22 @@ DBKey (*ui2key) (unsigned int key);
DBKey (*str2key) (const char *key);
/**
+ * Manual cast from 'int64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey (*i642key) (int64 key);
+
+/**
+ * Manual cast from 'uint64' to the union DBKey.
+ * @param key Key to be casted
+ * @return The key as a DBKey union
+ * @public
+ */
+DBKey (*ui642key) (uint64 key);
+
+/**
* Manual cast from 'int' to the struct DBData.
* @param data Data to be casted
* @return The data as a DBData struct
@@ -882,8 +928,8 @@ struct linkdb_node {
typedef void (*LinkDBFunc)(void* key, void* data, va_list args);
-void linkdb_insert (struct linkdb_node** head, void *key, void* data); // 重複を考慮しない
-void linkdb_replace (struct linkdb_node** head, void *key, void* data); // 重複を考慮する
+void linkdb_insert (struct linkdb_node** head, void *key, void* data); // Doesn't take into account duplicate keys
+void linkdb_replace (struct linkdb_node** head, void *key, void* data); // Takes into account duplicate keys
void* linkdb_search (struct linkdb_node** head, void *key);
void* linkdb_erase (struct linkdb_node** head, void *key);
void linkdb_final (struct linkdb_node** head);
@@ -1121,8 +1167,10 @@ void linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
#define VECTOR_ENSURE(__vec,__n,__step) \
do{ \
size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \
- while( (__n) > _empty_ ) _empty_ += (__step); \
- if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \
+ if( (__n) > _empty_ ) { \
+ while( (__n) > _empty_ ) _empty_ += (__step); \
+ VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \
+ } \
}while(0)
@@ -1500,4 +1548,4 @@ void linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
-#endif /* _DB_H_ */
+#endif /* _COMMON_DB_H_ */
diff --git a/src/common/des.h b/src/common/des.h
index e42136436..3f55448ba 100644
--- a/src/common/des.h
+++ b/src/common/des.h
@@ -1,7 +1,7 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _DES_H_
-#define _DES_H_
+#ifndef _COMMON_DES_H_
+#define _COMMON_DES_H_
/// One 64-bit block.
@@ -12,4 +12,4 @@ void des_decrypt_block(BIT64* block);
void des_decrypt(unsigned char* data, size_t size);
-#endif // _DES_H_
+#endif // _COMMON_DES_H_
diff --git a/src/common/ers.c b/src/common/ers.c
index 22269a51f..eb351a988 100644
--- a/src/common/ers.c
+++ b/src/common/ers.c
@@ -40,10 +40,12 @@
* @see common#ers.h *
\*****************************************************************************/
#include <stdlib.h>
+#include <string.h>
#include "../common/cbasetypes.h"
#include "../common/malloc.h" // CREATE, RECREATE, aMalloc, aFree
#include "../common/showmsg.h" // ShowMessage, ShowError, ShowFatalError, CL_BOLD, CL_NORMAL
+#include "../common/nullpo.h"
#include "ers.h"
#ifndef DISABLE_ERS
@@ -87,6 +89,9 @@ typedef struct ers_cache
// Default = ERS_BLOCK_ENTRIES, can be adjusted for performance for individual cache sizes.
unsigned int ChunkSize;
+ // Misc options, some options are shared from the instance
+ enum ERSOptions Options;
+
// Linked list
struct ers_cache *Next, *Prev;
} ers_cache_t;
@@ -122,12 +127,14 @@ static ers_cache_t *CacheList = NULL;
static struct ers_instance_t *InstanceList = NULL;
#endif
-static ers_cache_t *ers_find_cache(unsigned int size)
-{
+/**
+ * @param Options the options from the instance seeking a cache, we use it to give it a cache with matching configuration
+ **/
+static ers_cache_t *ers_find_cache(unsigned int size, enum ERSOptions Options) {
ers_cache_t *cache;
for (cache = CacheList; cache; cache = cache->Next)
- if (cache->ObjectSize == size)
+ if ( cache->ObjectSize == size && cache->Options == ( Options & ERS_CACHE_OPTIONS ) )
return cache;
CREATE(cache, ers_cache_t, 1);
@@ -140,6 +147,7 @@ static ers_cache_t *ers_find_cache(unsigned int size)
cache->UsedObjs = 0;
cache->Max = 0;
cache->ChunkSize = ERS_BLOCK_ENTRIES;
+ cache->Options = (Options & ERS_CACHE_OPTIONS);
if (CacheList == NULL)
{
@@ -238,6 +246,9 @@ static void ers_obj_free_entry(ERS self, void *entry)
return;
}
+ if( instance->Cache->Options & ERS_OPT_CLEAN )
+ memset((unsigned char*)reuse + sizeof(struct ers_list), 0, instance->Cache->ObjectSize - sizeof(struct ers_list));
+
reuse->Next = instance->Cache->ReuseList;
instance->Cache->ReuseList = reuse;
instance->Count--;
@@ -293,9 +304,10 @@ static void ers_obj_destroy(ERS self)
void ers_cache_size(ERS self, unsigned int new_size) {
struct ers_instance_t *instance = (struct ers_instance_t *)self;
- if (instance == NULL) {//change as per piotrhalaczkiewicz comment
- ShowError("ers_cache_size: NULL object, skipping...\n");
- return;
+ nullpo_retv(instance);
+
+ if( !(instance->Cache->Options&ERS_OPT_FLEX_CHUNK) ) {
+ ShowWarning("ers_cache_size: '%s' has adjusted its chunk size to '%d', however ERS_OPT_FLEX_CHUNK is missing!\n",instance->Name,new_size);
}
instance->Cache->ChunkSize = new_size;
@@ -320,7 +332,8 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options)
instance->Name = ( options & ERS_OPT_FREE_NAME ) ? aStrdup(name) : name;
instance->Options = options;
- instance->Cache = ers_find_cache(size);
+ instance->Cache = ers_find_cache(size,instance->Options);
+
instance->Cache->ReferenceCount++;
#ifdef DEBUG
if (InstanceList == NULL) {
diff --git a/src/common/ers.h b/src/common/ers.h
index 51701d778..4dae19f3b 100644
--- a/src/common/ers.h
+++ b/src/common/ers.h
@@ -37,8 +37,8 @@
* @author Flavio @ Amazon Project *
* @encoding US-ASCII *
\*****************************************************************************/
-#ifndef _ERS_H_
-#define _ERS_H_
+#ifndef _COMMON_ERS_H_
+#define _COMMON_ERS_H_
#include "../common/cbasetypes.h"
@@ -71,10 +71,15 @@
#endif /* not ERS_ALIGN_ENTRY */
enum ERSOptions {
- ERS_OPT_NONE = 0x0,
- ERS_OPT_CLEAR = 0x1,/* silently clears any entries left in the manager upon destruction */
- ERS_OPT_WAIT = 0x2,/* wait for entries to come in order to list! */
- ERS_OPT_FREE_NAME = 0x4,/* name is dynamic memory, and should be freed */
+ ERS_OPT_NONE = 0x0,
+ ERS_OPT_CLEAR = 0x1,/* silently clears any entries left in the manager upon destruction */
+ ERS_OPT_WAIT = 0x2,/* wait for entries to come in order to list! */
+ ERS_OPT_FREE_NAME = 0x4,/* name is dynamic memory, and should be freed */
+ ERS_OPT_CLEAN = 0x8,/* clears used memory upon ers_free so that its all new to be reused on the next alloc */
+ ERS_OPT_FLEX_CHUNK = 0x10,/* signs that it should look for its own cache given it'll have a dynamic chunk size, so that it doesn't affect the other ERS it'd otherwise be sharing */
+
+ /* Compound, is used to determine whether it should be looking for a cache of matching options */
+ ERS_CACHE_OPTIONS = ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK,
};
/**
@@ -137,11 +142,11 @@ typedef struct eri {
#else /* not DISABLE_ERS */
// These defines should be used to allow the code to keep working whenever
// the system is disabled
-# define ers_alloc(obj,type) (type *)(obj)->alloc(obj)
-# define ers_free(obj,entry) (obj)->free((obj),(entry))
-# define ers_entry_size(obj) (obj)->entry_size(obj)
-# define ers_destroy(obj) (obj)->destroy(obj)
-# define ers_chunk_size(obj,size) (obj)->chunk_size(obj,size)
+# define ers_alloc(obj,type) ((type *)(obj)->alloc(obj))
+# define ers_free(obj,entry) ((obj)->free((obj),(entry)))
+# define ers_entry_size(obj) ((obj)->entry_size(obj))
+# define ers_destroy(obj) ((obj)->destroy(obj))
+# define ers_chunk_size(obj,size) ((obj)->chunk_size((obj),(size)))
/**
* Get a new instance of the manager that handles the specified entry size.
@@ -175,4 +180,4 @@ void ers_report(void);
void ers_force_destroy_all(void);
#endif /* DISABLE_ERS / not DISABLE_ERS */
-#endif /* _ERS_H_ */
+#endif /* _COMMON_ERS_H_ */
diff --git a/src/common/grfio.c b/src/common/grfio.c
index 77b976926..57e8a5187 100644
--- a/src/common/grfio.c
+++ b/src/common/grfio.c
@@ -8,6 +8,7 @@
#include "../common/showmsg.h"
#include "../common/strlib.h"
#include "../common/utils.h"
+#include "../common/nullpo.h"
#include "grfio.h"
#include <stdio.h>
@@ -305,17 +306,21 @@ static FILELIST* filelist_find(const char* fname)
// returns the original file name
char* grfio_find_file(const char* fname)
{
- FILELIST *filelist = filelist_find(fname);
- if (!filelist) return NULL;
- return (!filelist->fnd ? filelist->fn : filelist->fnd);
+ FILELIST *flist = filelist_find(fname);
+ if (!flist) return NULL;
+ return (!flist->fnd ? flist->fn : flist->fnd);
}
// adds a FILELIST entry into the list of loaded files
-static FILELIST* filelist_add(FILELIST* entry)
-{
+static FILELIST* filelist_add(FILELIST* entry) {
int hash;
+ nullpo_ret(entry);
+#ifdef __clang_analyzer__
+ // Make clang's static analyzer shut up about a possible NULL pointer in &filelist[filelist_entrys]
+ nullpo_ret(&filelist[filelist_entrys]);
+#endif // __clang_analyzer__
- #define FILELIST_ADDS 1024 // number increment of file lists `
+#define FILELIST_ADDS 1024 // number increment of file lists `
if (filelist_entrys >= filelist_maxentry) {
filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST));
@@ -323,7 +328,9 @@ static FILELIST* filelist_add(FILELIST* entry)
filelist_maxentry += FILELIST_ADDS;
}
- memcpy (&filelist[filelist_entrys], entry, sizeof(FILELIST));
+#undef FILELIST_ADDS
+
+ memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST));
hash = filehash(entry->fn);
filelist[filelist_entrys].next = filelist_hash[hash];
@@ -405,7 +412,7 @@ void* grfio_reads(const char* fname, int* size)
if( in != NULL ) {
int declen;
fseek(in,0,SEEK_END);
- declen = ftell(in);
+ declen = (int)ftell(in);
fseek(in,0,SEEK_SET);
buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination
if(fread(buf2, 1, declen, in) != (size_t)declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname);
diff --git a/src/common/grfio.h b/src/common/grfio.h
index c5a56a14e..4f5d0d6bc 100644
--- a/src/common/grfio.h
+++ b/src/common/grfio.h
@@ -1,17 +1,17 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _GRFIO_H_
-#define _GRFIO_H_
+#ifndef _COMMON_GRFIO_H_
+#define _COMMON_GRFIO_H_
void grfio_init(const char* fname);
void grfio_final(void);
void* grfio_reads(const char* fname, int* size);
char* grfio_find_file(const char* fname);
-#define grfio_read(fn) grfio_reads(fn, NULL)
+#define grfio_read(fn) grfio_reads((fn), NULL)
unsigned long grfio_crc32(const unsigned char *buf, unsigned int len);
int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
-#endif /* _GRFIO_H_ */
+#endif /* _COMMON_GRFIO_H_ */
diff --git a/src/common/malloc.c b/src/common/malloc.c
index 4d2c93b77..f7f108304 100644
--- a/src/common/malloc.c
+++ b/src/common/malloc.c
@@ -19,28 +19,28 @@ struct malloc_interface iMalloc_s;
# include <string.h>
# include "memwatch.h"
-# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line))
-# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line))
-# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line))
-# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line))
-# define FREE(p,file,line,func) mwFree((p),(file),(line))
-# define MEMORY_USAGE() 0
-# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1)
-# define MEMORY_CHECK() CHECK()
+# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line))
+# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line))
+# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line))
+# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line))
+# define FREE(p,file,line,func) mwFree((p),(file),(line))
+# define MEMORY_USAGE() (size_t)0
+# define MEMORY_VERIFY(ptr) mwIsSafeAddr((ptr), 1)
+# define MEMORY_CHECK() CHECK()
#elif defined(DMALLOC)
# include <string.h>
# include <stdlib.h>
# include "dmalloc.h"
-# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0)
-# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0)
-# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0)
-# define STRDUP(p,file,line,func) strdup(p)
-# define FREE(p,file,line,func) free(p)
-# define MEMORY_USAGE() dmalloc_memory_allocated()
-# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR)
-# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed()
+# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0)
+# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0)
+# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0)
+# define STRDUP(p,file,line,func) strdup(p)
+# define FREE(p,file,line,func) free(p)
+# define MEMORY_USAGE() dmalloc_memory_allocated()
+# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR)
+# define MEMORY_CHECK() do { dmalloc_log_stats(); dmalloc_log_unfreed() } while(0)
#elif defined(GCOLLECT)
@@ -50,24 +50,26 @@ struct malloc_interface iMalloc_s;
# else
# define RETURN_ADDR
# endif
-# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line))
-# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line))
-# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line))
-# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line))
-# define FREE(p,file,line,func) GC_debug_free(p)
-# define MEMORY_USAGE() GC_get_heap_size()
-# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL)
-# define MEMORY_CHECK() GC_gcollect()
+# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line))
+# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line))
+# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line))
+# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line))
+# define FREE(p,file,line,func) GC_debug_free(p)
+# define MEMORY_USAGE() GC_get_heap_size()
+# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL)
+# define MEMORY_CHECK() GC_gcollect()
+
+# undef RETURN_ADDR
#else
-# define MALLOC(n,file,line,func) malloc(n)
-# define CALLOC(m,n,file,line,func) calloc((m),(n))
-# define REALLOC(p,n,file,line,func) realloc((p),(n))
-# define STRDUP(p,file,line,func) strdup(p)
-# define FREE(p,file,line,func) free(p)
-# define MEMORY_USAGE() 0
-# define MEMORY_VERIFY(ptr) true
+# define MALLOC(n,file,line,func) malloc(n)
+# define CALLOC(m,n,file,line,func) calloc((m),(n))
+# define REALLOC(p,n,file,line,func) realloc((p),(n))
+# define STRDUP(p,file,line,func) strdup(p)
+# define FREE(p,file,line,func) free(p)
+# define MEMORY_USAGE() (size_t)0
+# define MEMORY_VERIFY(ptr) true
# define MEMORY_CHECK()
#endif
@@ -367,6 +369,37 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c
}
}
+/* a _mrealloc clone with the difference it 'z'eroes the newly created memory */
+void* _mreallocz(void *memblock, size_t size, const char *file, int line, const char *func ) {
+ size_t old_size;
+ void *p = NULL;
+
+ if(memblock == NULL) {
+ p = iMalloc->malloc(size,file,line,func);
+ memset(p,0,size);
+ return p;
+ }
+
+ old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size;
+ if( old_size == 0 ) {
+ old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size;
+ }
+ if(old_size > size) {
+ // Size reduction - return> as it is (negligence)
+ return memblock;
+ } else {
+ // Size Large
+ p = iMalloc->malloc(size,file,line,func);
+ if(p != NULL) {
+ memcpy(p,memblock,old_size);
+ memset((char*)p+old_size,0,size-old_size);
+ }
+ iMalloc->free(memblock,file,line,func);
+ return p;
+ }
+}
+
+
char* _mstrdup(const char *p, const char *file, int line, const char *func )
{
if(p == NULL) {
@@ -667,7 +700,7 @@ void memmgr_report (int extra) {
struct {
const char *file;
unsigned short line;
- unsigned int size;
+ size_t size;
unsigned int count;
} data[100];
memset(&data, 0, sizeof(data));
@@ -820,12 +853,14 @@ void malloc_defaults(void) {
iMalloc->malloc = _mmalloc;
iMalloc->calloc = _mcalloc;
iMalloc->realloc = _mrealloc;
+ iMalloc->reallocz= _mreallocz;
iMalloc->astrdup = _mstrdup;
iMalloc->free = _mfree;
#else
iMalloc->malloc = aMalloc_;
iMalloc->calloc = aCalloc_;
iMalloc->realloc = aRealloc_;
+ iMalloc->reallocz= aRealloc_;/* not using memory manager huhum o.o perhaps we could still do something about */
iMalloc->astrdup = aStrdup_;
iMalloc->free = aFree_;
#endif
diff --git a/src/common/malloc.h b/src/common/malloc.h
index bc8aa9a20..7309bb0f7 100644
--- a/src/common/malloc.h
+++ b/src/common/malloc.h
@@ -1,8 +1,8 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _MALLOC_H_
-#define _MALLOC_H_
+#ifndef _COMMON_MALLOC_H_
+#define _COMMON_MALLOC_H_
#include "../common/cbasetypes.h"
@@ -30,11 +30,12 @@
#undef LOG_MEMMGR
#endif
-# define aMalloc(n) iMalloc->malloc (n,ALC_MARK)
-# define aCalloc(m,n) iMalloc->calloc (m,n,ALC_MARK)
-# define aRealloc(p,n) iMalloc->realloc (p,n,ALC_MARK)
-# define aStrdup(p) iMalloc->astrdup (p,ALC_MARK)
-# define aFree(p) iMalloc->free (p,ALC_MARK)
+# define aMalloc(n) (iMalloc->malloc((n),ALC_MARK))
+# define aCalloc(m,n) (iMalloc->calloc((m),(n),ALC_MARK))
+# define aRealloc(p,n) (iMalloc->realloc((p),(n),ALC_MARK))
+# define aReallocz(p,n) (iMalloc->reallocz((p),(n),ALC_MARK))
+# define aStrdup(p) (iMalloc->astrdup((p),ALC_MARK))
+# define aFree(p) (iMalloc->free((p),ALC_MARK))
/////////////// Buffer Creation /////////////////
// Full credit for this goes to Shinomori [Ajarn]
@@ -46,15 +47,15 @@
#else // others don't, so we emulate them
-#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type))
+#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc((size), sizeof(type))
#define DELETE_BUFFER(name) aFree(name)
#endif
////////////// Others //////////////////////////
// should be merged with any of above later
-#define CREATE(result, type, number) (result) = (type *) aCalloc ((number), sizeof(type))
-#define RECREATE(result, type, number) (result) = (type *) aRealloc ((result), sizeof(type) * (number))
+#define CREATE(result, type, number) ((result) = (type *) aCalloc((number), sizeof(type)))
+#define RECREATE(result, type, number) ((result) = (type *) aReallocz((result), sizeof(type) * (number)))
////////////////////////////////////////////////
@@ -73,6 +74,7 @@ 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);
+ void* (*reallocz)(void *p, size_t size, const char *file, int line, const char *func);
char* (*astrdup )(const char *p, const char *file, int line, const char *func);
void (*free )(void *p, const char *file, int line, const char *func);
/* */
@@ -86,4 +88,4 @@ struct malloc_interface {
void memmgr_report (int extra);
struct malloc_interface *iMalloc;
-#endif /* _MALLOC_H_ */
+#endif /* _COMMON_MALLOC_H_ */
diff --git a/src/common/mapindex.c b/src/common/mapindex.c
index 83de21b2b..3128a3cb0 100644
--- a/src/common/mapindex.c
+++ b/src/common/mapindex.c
@@ -13,15 +13,9 @@
#include <stdio.h>
#include <stdlib.h>
-struct _indexes {
- char name[MAP_NAME_LENGTH]; //Stores map name
-} indexes[MAX_MAPINDEX];
+/* mapindex.c interface source */
+struct mapindex_interface mapindex_s;
-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) {
@@ -78,9 +72,8 @@ int mapindex_addmap(int index, const char* name) {
char map_name[MAP_NAME_LENGTH];
if (index == -1){
- for (index = 1; index < max_index; index++) {
- //if (strcmp(indexes[index].name,"#CLEARED#")==0)
- if (indexes[index].name[0] == '\0')
+ for (index = 1; index < mapindex->num; index++) {
+ if (mapindex->list[index].name[0] == '\0')
break;
}
}
@@ -90,7 +83,7 @@ int mapindex_addmap(int index, const char* name) {
return 0;
}
- mapindex_getmapname(name, map_name);
+ mapindex->getmapname(name, map_name);
if (map_name[0] == '\0') {
ShowError("(mapindex_add) Cannot add maps with no name.\n");
@@ -103,14 +96,15 @@ int mapindex_addmap(int index, const char* name) {
}
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);
+ ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, mapindex->list[index].name, map_name);
+ strdb_remove(mapindex->db, mapindex->list[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;
+ safestrncpy(mapindex->list[index].name, map_name, MAP_NAME_LENGTH);
+ strdb_iput(mapindex->db, map_name, index);
+
+ if (mapindex->num <= index)
+ mapindex->num = index+1;
return index;
}
@@ -119,9 +113,9 @@ unsigned short mapindex_name2id(const char* name) {
int i;
char map_name[MAP_NAME_LENGTH];
- mapindex_getmapname(name, map_name);
+ mapindex->getmapname(name, map_name);
- if( (i = strdb_iget(mapindex_db, map_name)) )
+ if( (i = strdb_iget(mapindex->db, map_name)) )
return i;
ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name);
@@ -131,24 +125,25 @@ unsigned short mapindex_name2id(const char* name) {
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. %s:%s:%d\n", id,file,func,line);
- return indexes[0].name; // dummy empty string so that the callee doesn't crash
+ return mapindex->list[0].name; // dummy empty string so that the callee doesn't crash
}
- return indexes[id].name;
+ return mapindex->list[id].name;
}
-void mapindex_init(void) {
+int mapindex_init(void) {
FILE *fp;
char line[1024];
int last_index = -1;
- int index;
+ int index, total = 0;
char map_name[12];
- if( ( fp = fopen(mapindex_cfgfile,"r") ) == NULL ){
- ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile);
+ if( ( fp = fopen(mapindex->config_file,"r") ) == NULL ){
+ ShowFatalError("Unable to read mapindex config file %s!\n", mapindex->config_file);
exit(EXIT_FAILURE); //Server can't really run without this file.
}
- memset (&indexes, 0, sizeof (indexes));
- mapindex_db = strdb_alloc(DB_OPT_DUP_KEY, MAP_NAME_LENGTH);
+
+ mapindex->db = strdb_alloc(DB_OPT_DUP_KEY, MAP_NAME_LENGTH);
+
while(fgets(line, sizeof(line), fp)) {
if(line[0] == '/' && line[1] == '/')
continue;
@@ -157,7 +152,8 @@ void mapindex_init(void) {
case 1: //Map with no ID given, auto-assign
index = last_index+1;
case 2: //Map with ID given
- mapindex_addmap(index,map_name);
+ mapindex->addmap(index,map_name);
+ total++;
break;
default:
continue;
@@ -166,16 +162,40 @@ void mapindex_init(void) {
}
fclose(fp);
- if( !strdb_iget(mapindex_db, MAP_DEFAULT) ) {
+ 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);
}
+
+ return total;
}
-int mapindex_removemap(int index){
- indexes[index].name[0] = '\0';
- return 0;
+void mapindex_removemap(int index){
+ strdb_remove(mapindex->db, mapindex->list[index].name);
+ mapindex->list[index].name[0] = '\0';
}
void mapindex_final(void) {
- db_destroy(mapindex_db);
+ db_destroy(mapindex->db);
+}
+
+void mapindex_defaults(void) {
+ mapindex = &mapindex_s;
+
+ /* TODO: place it in inter-server.conf? */
+ snprintf(mapindex->config_file, 80, "%s","db/map_index.txt");
+ /* */
+ mapindex->db = NULL;
+ mapindex->num = 0;
+ memset (&mapindex->list, 0, sizeof (mapindex->list));
+
+ /* */
+ mapindex->init = mapindex_init;
+ mapindex->final = mapindex_final;
+ /* */
+ mapindex->addmap = mapindex_addmap;
+ mapindex->removemap = mapindex_removemap;
+ mapindex->getmapname = mapindex_getmapname;
+ mapindex->getmapname_ext = mapindex_getmapname_ext;
+ mapindex->name2id = mapindex_name2id;
+ mapindex->id2name = mapindex_id2name_sub;
}
diff --git a/src/common/mapindex.h b/src/common/mapindex.h
index 43953a8e0..fa9b9e920 100644
--- a/src/common/mapindex.h
+++ b/src/common/mapindex.h
@@ -2,21 +2,20 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _MAPINDEX_H_
-#define _MAPINDEX_H_
+#ifndef _COMMON_MAPINDEX_H_
+#define _COMMON_MAPINDEX_H_
#include "../common/db.h"
+#include "../common/mmo.h"
+
+#define MAX_MAPINDEX 2000
+
+/* wohoo, someone look at all those |: map_default could (or *should*) be a char-server.conf */
// 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];
-
-#define MAX_MAPINDEX 2000
//Some definitions for the mayor city maps.
#define MAP_PRONTERA "prontera"
@@ -56,15 +55,39 @@ extern char mapindex_cfgfile[80];
#define MAP_MALAYA "malaya"
#define MAP_ECLAGE "eclage"
-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*);
-#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);
+#define mapindex_id2name(n) mapindex->id2name((n),__FILE__, __LINE__, __func__)
+#define mapindex_exists(n) ( mapindex->list[(n)].name[0] != '\0' )
+
+/**
+ * mapindex.c interface
+ **/
+struct mapindex_interface {
+ char config_file[80];
+ /* mapname (str) -> index (int) */
+ DBMap *db;
+ /* number of entries in the index table */
+ int num;
+ /* index list -- since map server map count is *unlimited* this should be too */
+ struct {
+ char name[MAP_NAME_LENGTH];
+ } list[MAX_MAPINDEX];
+ /* */
+ int (*init) (void);
+ void (*final) (void);
+ /* */
+ int (*addmap) (int index, const char* name);
+ void (*removemap) (int index);
+ const char* (*getmapname) (const char* string, char* output);
+ /* TODO: server shouldn't be handling the extension, game client automatically adds .gat/.rsw/.whatever
+ * and there are official map names taking advantage of it that we cant support due to the .gat room being saved */
+ const char* (*getmapname_ext) (const char* string, char* output);
+ /* TODO: Hello World! make up your mind, this thing is int on some places and unsigned short on others */
+ unsigned short (*name2id) (const char*);
+ const char* (*id2name) (unsigned short,const char *file, int line, const char *func);
+};
+
+struct mapindex_interface *mapindex;
-int mapindex_addmap(int index, const char* name);
-int mapindex_removemap(int index);
+void mapindex_defaults(void);
-#endif /* _MAPINDEX_H_ */
+#endif /* _COMMON_MAPINDEX_H_ */
diff --git a/src/common/md5calc.h b/src/common/md5calc.h
index 323affa2c..d0caf6787 100644
--- a/src/common/md5calc.h
+++ b/src/common/md5calc.h
@@ -1,8 +1,8 @@
-#ifndef _MD5CALC_H_
-#define _MD5CALC_H_
+#ifndef _COMMON_MD5CALC_H_
+#define _COMMON_MD5CALC_H_
void MD5_String(const char * string, char * output);
void MD5_Binary(const char * string, unsigned char * output);
void MD5_Salt(unsigned int len, char * output);
-#endif /* _MD5CALC_H_ */
+#endif /* _COMMON_MD5CALC_H_ */
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 5eccbf178..4559d8f2a 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -30,16 +30,16 @@
#include "../common/malloc.h"
#include "../common/mutex.h"
-#define ALIGN16 ra_align(16)
-#define ALIGN_TO(x, a) (x + ( a - ( x % a) ) )
-#define ALIGN_TO_16(x) ALIGN_TO(x, 16)
+#define ALIGN16 ra_align(16)
+#define ALIGN_TO(x, a) ((x) + ( (a) - ( (x) % (a)) ) )
+#define ALIGN_TO_16(x) ALIGN_TO((x), 16)
#undef MEMPOOL_DEBUG
#define MEMPOOLASSERT
-#define NODE_TO_DATA(x) ( ((char*)x) + sizeof(struct node) )
-#define DATA_TO_NODE(x) ( (struct node*)(((char*)x) - sizeof(struct node)) )
+#define NODE_TO_DATA(x) ( ((char*)(x)) + sizeof(struct node) )
+#define DATA_TO_NODE(x) ( (struct node*)(((char*)(x)) - sizeof(struct node)) )
struct ra_align(16) node{
void *next;
void *segment;
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 205cf8425..2b66c516c 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -2,8 +2,8 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _MMO_H_
-#define _MMO_H_
+#ifndef _COMMON_MMO_H_
+#define _COMMON_MMO_H_
#include "cbasetypes.h"
#include "../common/db.h"
@@ -48,18 +48,20 @@
// 20120307 - 2012-03-07aRagexeRE+ - 0x970
#ifndef PACKETVER
- #define PACKETVER 20120418
-#endif
+ #define PACKETVER 20131223
+#endif // PACKETVER
-// Comment the following line if your client is NOT ragexeRE (required because of conflicting packets in ragexe vs ragexeRE).
-#define PACKETVER_RE
+//Uncomment the following line if your client is ragexeRE instead of ragexe (required because of conflicting packets in ragexe vs ragexeRE).
+//#define ENABLE_PACKETVER_RE
+#ifdef ENABLE_PACKETVER_RE
+ #define PACKETVER_RE
+ #undef ENABLE_PACKETVER_RE
+#endif // DISABLE_PACKETVER_RE
// Client support for experimental RagexeRE UI present in 2012-04-10 and 2012-04-18
-#ifdef PACKETVER_RE
-#if (PACKETVER == 20120410) || (PACKETVER == 20120418)
- #define PARTY_RECRUIT
-#endif
-#endif
+#if defined(PACKETVER_RE) && ( PACKETVER == 20120410 || PACKETVER == 20120418 )
+#define PARTY_RECRUIT
+#endif // PACKETVER_RE && (PACKETVER == 20120410 || PACKETVER == 10120418)
// Comment the following line to disable sc_data saving. [Skotlex]
#define ENABLE_SC_SAVING
@@ -90,6 +92,10 @@
//Max amount of a single stacked item
#define MAX_AMOUNT 30000
#define MAX_ZENY 1000000000
+
+//Official Limit: 2.1b ( the var that stores the money doesn't go much higher than this by default )
+#define MAX_BANK_ZENY 2100000000
+
#define MAX_FAME 1000000000
#define MAX_CART 100
#define MAX_SKILL 1478
@@ -97,25 +103,19 @@
//Update this max as necessary. 55 is the value needed for Super Baby currently
//Raised to 84 since Expanded Super Novice needs it.
#define MAX_SKILL_TREE 84
-#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
-//Should hold the max of GLOBAL/ACCOUNT/ACCOUNT2 (needed for some arrays that hold all three)
-#define MAX_REG_NUM 256
#define DEFAULT_WALK_SPEED 150
-#define MIN_WALK_SPEED 0
+#define MIN_WALK_SPEED 20 /* below 20 clips animation */
#define MAX_WALK_SPEED 1000
#define MAX_STORAGE 600
#define MAX_GUILD_STORAGE 600
#define MAX_PARTY 12
-#define MAX_GUILD 16+10*6 // Increased max guild members +6 per 1 extension levels [Lupus]
+#define MAX_GUILD (16+10*6) // Increased max guild members +6 per 1 extension levels [Lupus]
#define MAX_GUILDPOSITION 20 // Increased max guild positions to accomodate for all members [Valaris] (removed) [PoW]
#define MAX_GUILDEXPULSION 32
#define MAX_GUILDALLIANCE 16
#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 2662 // 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]
@@ -180,6 +180,8 @@
#define EL_CLASS_BASE 2114
#define EL_CLASS_MAX (EL_CLASS_BASE+MAX_ELEMENTAL_CLASS-1)
+struct HPluginData;
+
enum item_types {
IT_HEALING = 0,
IT_UNKNOWN, //1
@@ -198,27 +200,33 @@ enum item_types {
};
-// Questlog system [Kevin] [Inkfish]
-typedef enum quest_state { Q_INACTIVE, Q_ACTIVE, Q_COMPLETE } quest_state;
+// Questlog states
+enum quest_state {
+ Q_INACTIVE, ///< Inactive quest (the user can toggle between active and inactive quests)
+ Q_ACTIVE, ///< Active quest
+ Q_COMPLETE, ///< Completed quest
+};
+/// Questlog entry
struct quest {
- int quest_id;
- unsigned int time;
- int count[MAX_QUEST_OBJECTIVES];
- quest_state state;
+ int quest_id; ///< Quest ID
+ unsigned int time; ///< Expiration time
+ int count[MAX_QUEST_OBJECTIVES]; ///< Kill counters of each quest objective
+ enum quest_state state; ///< Current quest state
};
struct item {
int id;
short nameid;
short amount;
- unsigned short equip; // Location(s) where item is equipped (using enum equip_pos for bitmasking).
+ unsigned int equip; // Location(s) where item is equipped (using enum equip_pos for bitmasking).
char identify;
char refine;
char attribute;
short card[MAX_SLOTS];
unsigned int expire_time;
char favorite;
+ unsigned char bound;
uint64 unique_id;
};
@@ -245,28 +253,41 @@ enum e_mmo_charstatus_opt {
OPT_ALLOW_PARTY = 0x2,
};
+enum e_item_bound_type {
+ IBT_MIN = 0x1,
+ IBT_ACCOUNT = 0x1,
+ IBT_GUILD = 0x2,
+ IBT_PARTY = 0x3,
+ IBT_CHARACTER = 0x4,
+ IBT_MAX = 0x4,
+};
+
struct s_skill {
unsigned short id;
unsigned char lv;
unsigned char flag; // See enum e_skill_flag
};
-struct global_reg {
- char str[32];
- char value[256];
+struct script_reg_state {
+ unsigned int type : 1;/* because I'm a memory hoarder and having them in the same struct would be a 8-byte/instance waste while ints outnumber str on a 10000-to-1 ratio. */
+ unsigned int update : 1;/* whether it needs to be sent to char server for insertion/update/delete */
};
-// Holds array of global registries, used by the char server and converter.
-struct accreg {
- int account_id, char_id;
- int reg_num;
- struct global_reg reg[MAX_REG_NUM];
+struct script_reg_num {
+ struct script_reg_state flag;
+ int value;
+};
+
+struct script_reg_str {
+ struct script_reg_state flag;
+ char *value;
};
// For saving status changes across sessions. [Skotlex]
struct status_change_data {
unsigned short type; //SC_type
- long val1, val2, val3, val4, tick; //Remaining duration.
+ int val1, val2, val3, val4;
+ unsigned int tick; //Remaining duration.
};
struct storage_data {
@@ -366,6 +387,7 @@ struct mmo_charstatus {
unsigned int base_exp,job_exp;
int zeny;
+ int bank_vault;
short class_;
unsigned int status_point,skill_point;
@@ -409,6 +431,11 @@ struct mmo_charstatus {
unsigned short slotchange;
time_t delete_date;
+
+ /* `account_data` modifiers */
+ unsigned short mod_exp,mod_drop,mod_death;
+
+ unsigned char font;
};
typedef enum mail_status {
@@ -458,15 +485,6 @@ struct auction_data {
int auction_end_timer;
};
-struct registry {
- int global_num;
- struct global_reg global[GLOBAL_REG_NUM];
- int account_num;
- struct global_reg account[ACCOUNT_REG_NUM];
- int account2_num;
- struct global_reg account2[ACCOUNT_REG2_NUM];
-};
-
struct party_member {
int account_id;
int char_id;
@@ -484,7 +502,7 @@ struct party {
unsigned char count; //Count of online characters.
unsigned exp : 1,
item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared.
- struct party_member member[MAX_PARTY];
+ struct party_member member[MAX_PARTY];
};
struct map_session_data;
@@ -522,6 +540,7 @@ struct guild_skill {
int id,lv;
};
+struct hChSysCh;
struct guild {
int guild_id;
short guild_lv, connect_member, max_member, average_lv;
@@ -538,13 +557,17 @@ struct guild {
struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
struct guild_skill skill[MAX_GUILDSKILL];
- /* TODO: still used for something?|: */
- unsigned short save_flag; // for TXT saving
+ /* used on char.c to state what kind of data is being saved/processed */
+ unsigned short save_flag;
short *instance;
unsigned short instances;
- void *channel;
+ struct hChSysCh *channel;
+
+ /* HPM Custom Struct */
+ struct HPluginData **hdata;
+ unsigned int hdatac;
};
struct guild_castle {
@@ -833,10 +856,34 @@ enum ammo_type {
A_THROWWEAPON //9
};
+enum e_char_server_type {
+ CST_NORMAL = 0,
+ CST_MAINTENANCE = 1,
+ CST_OVER18 = 2,
+ CST_PAYING = 3,
+ CST_F2P = 4,
+};
+
+enum e_pc_reg_loading {
+ PRL_NONE = 0x0,
+ PRL_CHAR = 0x1,
+ PRL_ACCL = 0x2,/* local */
+ PRL_ACCG = 0x4,/* global */
+ PRL_ALL = 0xFF,
+};
+
+/* packet size constant for itemlist */
+#if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART
+#define MAX_ITEMLIST MAX_INVENTORY
+#elif MAX_CART > MAX_INVENTORY && MAX_CART > MAX_STORAGE
+#define MAX_ITEMLIST MAX_CART
+#else
+#define MAX_ITEMLIST MAX_STORAGE
+#endif
// sanity checks...
#if MAX_ZENY > INT_MAX
#error MAX_ZENY is too big
#endif
-#endif /* _MMO_H_ */
+#endif /* _COMMON_MMO_H_ */
diff --git a/src/common/mutex.h b/src/common/mutex.h
index 1999627cd..eeb24e6ff 100644
--- a/src/common/mutex.h
+++ b/src/common/mutex.h
@@ -1,8 +1,8 @@
// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _rA_MUTEX_H_
-#define _rA_MUTEX_H_
+#ifndef _COMMON_MUTEX_H_
+#define _COMMON_MUTEX_H_
typedef struct ramutex *ramutex; // Mutex
@@ -89,4 +89,4 @@ void racond_signal( racond c );
void racond_broadcast( racond c );
-#endif
+#endif /* _COMMON_MUTEX_H_ */
diff --git a/src/common/netbuffer.h b/src/common/netbuffer.h
index 844241226..6ddecfdd9 100644
--- a/src/common/netbuffer.h
+++ b/src/common/netbuffer.h
@@ -73,11 +73,9 @@ void netbuffer_incref( netbuf buf );
// Some Useful macros
-#define NBUFP(netbuf,pos) (((uint8*)(netbuf->buf)) + (pos))
-#define NBUFB(netbuf,pos) (*(uint8*)((netbuf->buf) + (pos)))
-#define NBUFW(netbuf,pos) (*(uint16*)((netbuf->buf) + (pos)))
-#define NBUFL(netbuf,pos) (*(uint32*)((netbuf->buf) + (pos)))
-
-
+#define NBUFP(netbuf,pos) (((uint8*)((netbuf)->buf)) + (pos))
+#define NBUFB(netbuf,pos) (*(uint8*)(((netbuf)->buf) + (pos)))
+#define NBUFW(netbuf,pos) (*(uint16*)(((netbuf)->buf) + (pos)))
+#define NBUFL(netbuf,pos) (*(uint32*)(((netbuf)->buf) + (pos)))
#endif
diff --git a/src/common/network.c b/src/common/network.c
index 1f1621363..a40cbd602 100644
--- a/src/common/network.c
+++ b/src/common/network.c
@@ -50,7 +50,7 @@ SESSION g_Session[MAXCONN];
static bool onSend(int32 fd);
-#define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t) buf)
+#define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t)(buf))
static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data){
// netbuf is in data
netbuffer_put( (netbuf)data );
diff --git a/src/common/nullpo.c b/src/common/nullpo.c
index 4383109a7..1cb471aff 100644
--- a/src/common/nullpo.c
+++ b/src/common/nullpo.c
@@ -1,91 +1,30 @@
-// 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 <stdio.h>
#include <stdarg.h>
#include <string.h>
-#include "nullpo.h"
+#include "../common/nullpo.h"
#include "../common/showmsg.h"
-// #include "logs.h" // 布石してみる
-static void nullpo_info_core(const char *file, int line, const char *func,
- const char *fmt, va_list ap);
-
-/*======================================
- * Nullチェック 及び 情報出力
- *--------------------------------------*/
-int nullpo_chk_f(const char *file, int line, const char *func, const void *target,
- const char *fmt, ...)
-{
- va_list ap;
-
- if (target != NULL)
- return 0;
-
- va_start(ap, fmt);
- nullpo_info_core(file, line, func, fmt, ap);
- va_end(ap);
- return 1;
-}
-
-int nullpo_chk(const char *file, int line, const char *func, const void *target)
-{
- if (target != NULL)
- return 0;
-
- nullpo_info_core(file, line, func, NULL, NULL);
- return 1;
-}
-
-
-/*======================================
- * nullpo情報出力(外部呼出し向けラッパ)
- *--------------------------------------*/
-void nullpo_info_f(const char *file, int line, const char *func,
- const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- nullpo_info_core(file, line, func, fmt, ap);
- va_end(ap);
-}
-
-void nullpo_info(const char *file, int line, const char *func)
-{
- nullpo_info_core(file, line, func, NULL, NULL);
-}
-
-
-/*======================================
- * nullpo情報出力(Main)
- *--------------------------------------*/
-static void nullpo_info_core(const char *file, int line, const char *func,
- const char *fmt, va_list ap)
-{
+/**
+ * Reports failed assertions or NULL pointers
+ *
+ * @param file Source file where the error was detected
+ * @param line Line
+ * @param func Function
+ * @param targetname Name of the checked symbol
+ * @param title Message title to display (i.e. failed assertion or nullpo info)
+ */
+void assert_report(const char *file, int line, const char *func, const char *targetname, const char *title) {
if (file == NULL)
file = "??";
- func =
- func == NULL ? "unknown":
- func[0] == '\0' ? "unknown":
- func;
-
- ShowMessage("--- nullpo info --------------------------------------------\n");
- ShowMessage("%s:%d: in func `%s'\n", file, line, func);
- if (fmt != NULL)
- {
- if (fmt[0] != '\0')
- {
- vprintf(fmt, ap);
-
- // 最後に改行したか確認
- if (fmt[strlen(fmt)-1] != '\n')
- ShowMessage("\n");
- }
- }
- ShowMessage("--- end nullpo info ----------------------------------------\n");
+ if (func == NULL || *func == '\0')
+ func = "unknown";
- // ここらでnullpoログをファイルに書き出せたら
- // まとめて提出できるなと思っていたり。
+ ShowError("--- %s --------------------------------------------\n", title);
+ ShowError("%s:%d: '%s' in function `%s'\n", file, line, targetname, func);
+ ShowError("--- end %s ----------------------------------------\n", title);
}
diff --git a/src/common/nullpo.h b/src/common/nullpo.h
index 8ee86a782..fb1cf0feb 100644
--- a/src/common/nullpo.h
+++ b/src/common/nullpo.h
@@ -1,225 +1,128 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _NULLPO_H_
-#define _NULLPO_H_
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
+#ifndef _COMMON_NULLPO_H_
+#define _COMMON_NULLPO_H_
#include "../common/cbasetypes.h"
-#define NLP_MARK __FILE__, __LINE__, __func__
-
// enabled by default on debug builds
#if defined(DEBUG) && !defined(NULLPO_CHECK)
#define NULLPO_CHECK
#endif
-/*----------------------------------------------------------------------------
- * Macros
- *----------------------------------------------------------------------------
- */
-/*======================================
- * Nullチェック 及び 情報出力後 return
- *・展開するとifとかreturn等が出るので
- * 一行単体で使ってください。
- *・nullpo_ret(x = func());
- * のような使用法も想定しています。
- *--------------------------------------
- * nullpo_ret(t)
- * 戻り値 0固定
- * [引数]
- * t チェック対象
- *--------------------------------------
- * nullpo_retv(t)
- * 戻り値 なし
- * [引数]
- * t チェック対象
- *--------------------------------------
- * nullpo_retr(ret, t)
- * 戻り値 指定
- * [引数]
- * ret return(ret);
- * t チェック対象
- *--------------------------------------
- * nullpo_ret_f(t, fmt, ...)
- * 詳細情報出力用
- * 戻り値 0
- * [引数]
- * t チェック対象
- * fmt ... vprintfに渡される
- * 備考や関係変数の書き出しなどに
- *--------------------------------------
- * nullpo_retv_f(t, fmt, ...)
- * 詳細情報出力用
- * 戻り値 なし
- * [引数]
- * t チェック対象
- * fmt ... vprintfに渡される
- * 備考や関係変数の書き出しなどに
- *--------------------------------------
- * nullpo_retr_f(ret, t, fmt, ...)
- * 詳細情報出力用
- * 戻り値 指定
- * [引数]
- * ret return(ret);
- * t チェック対象
- * fmt ... vprintfに渡される
- * 備考や関係変数の書き出しなどに
- *--------------------------------------
- */
+// Skip assert checks on release builds
+#if !defined(RELEASE) && !defined(ASSERT_CHECK)
+#define ASSERT_CHECK
+#endif
+
+/** Assert */
+
+#if defined(ASSERT_CHECK)
+// extern "C" {
+#include <assert.h>
+// }
+#if !defined(DEFCPP) && defined(WIN32) && !defined(MINGW)
+#include <crtdbg.h>
+#endif // !DEFCPP && WIN && !MINGW
+#define Assert(EX) assert(EX)
+#define Assert_chk(EX) ( (EX) ? false : (assert_report(__FILE__, __LINE__, __func__, #EX, "failed assertion"), true) )
+#else // ! ASSERT_CHECK
+#define Assert(EX) (EX)
+#define Assert_chk(EX) ((EX), false)
+#endif // ASSERT_CHECK
#if defined(NULLPO_CHECK)
+/**
+ * Reports NULL pointer information if the passed pointer is NULL
+ *
+ * @param t pointer to check
+ * @return true if the passed pointer is NULL, false otherwise
+ */
+#define nullpo_chk(t) ( (t) != NULL ? false : (assert_report(__FILE__, __LINE__, __func__, #t, "nullpo info"), true) )
+#else // ! NULLPO_CHECK
+#define nullpo_chk(t) ((void)(t), false)
+#endif // NULLPO_CHECK
+
+/**
+ * The following macros check for NULL pointers and return from the current
+ * function or block in case one is found.
+ *
+ * It is guaranteed that the argument is evaluated once and only once, so it
+ * is safe to call them as:
+ * nullpo_ret(x = func());
+ * The macros can be used safely in any context, as they expand to a do/while
+ * construct, except nullpo_retb, which expands to an if/else construct.
+ */
+/**
+ * Returns 0 if a NULL pointer is found.
+ *
+ * @param t pointer to check
+ */
#define nullpo_ret(t) \
- if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);}
-
-#define nullpo_retv(t) \
- if (nullpo_chk(NLP_MARK, (void *)(t))) {return;}
-
-#define nullpo_retr(ret, t) \
- if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);}
-
-#define nullpo_retb(t) \
- if (nullpo_chk(NLP_MARK, (void *)(t))) {break;}
-
-// 可変引数マクロに関する条件コンパイル
-#if __STDC_VERSION__ >= 199901L
-/* C99に対応 */
-#define nullpo_ret_f(t, fmt, ...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);}
-
-#define nullpo_retv_f(t, fmt, ...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;}
-
-#define nullpo_retr_f(ret, t, fmt, ...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);}
-
-#define nullpo_retb_f(t, fmt, ...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;}
+ do { if (nullpo_chk(t)) return(0); } while(0)
-#elif __GNUC__ >= 2
-/* GCC用 */
-#define nullpo_ret_f(t, fmt, args...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);}
-
-#define nullpo_retv_f(t, fmt, args...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;}
-
-#define nullpo_retr_f(ret, t, fmt, args...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);}
-
-#define nullpo_retb_f(t, fmt, args...) \
- if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;}
-
-#else
-
-/* その他の場合・・・ orz */
-
-#endif
-
-#else /* NULLPO_CHECK */
-/* No Nullpo check */
-
-// if((t)){;}
-// 良い方法が思いつかなかったので・・・苦肉の策です。
-// 一応ワーニングは出ないはず
-
-#define nullpo_ret(t) (void)(t)
-#define nullpo_retv(t) (void)(t)
-#define nullpo_retr(ret, t) (void)(t)
-#define nullpo_retb(t) (void)(t)
-
-// 可変引数マクロに関する条件コンパイル
-#if __STDC_VERSION__ >= 199901L
-/* C99に対応 */
-#define nullpo_ret_f(t, fmt, ...) (void)(t)
-#define nullpo_retv_f(t, fmt, ...) (void)(t)
-#define nullpo_retr_f(ret, t, fmt, ...) (void)(t)
-#define nullpo_retb_f(t, fmt, ...) (void)(t)
-
-#elif __GNUC__ >= 2
-/* GCC用 */
-#define nullpo_ret_f(t, fmt, args...) (void)(t)
-#define nullpo_retv_f(t, fmt, args...) (void)(t)
-#define nullpo_retr_f(ret, t, fmt, args...) (void)(t)
-#define nullpo_retb_f(t, fmt, args...) (void)(t)
-
-#else
-/* その他の場合・・・ orz */
-#endif
+/**
+ * Returns 0 if the given assertion fails.
+ *
+ * @param t statement to check
+ */
+#define Assert_ret(t) \
+ do { if (Assert_chk(t)) return(0); } while(0)
-#endif /* NULLPO_CHECK */
+/**
+ * Returns void if a NULL pointer is found.
+ *
+ * @param t pointer to check
+ */
+#define nullpo_retv(t) \
+ do { if (nullpo_chk(t)) return; } while(0)
-/*----------------------------------------------------------------------------
- * Functions
- *----------------------------------------------------------------------------
+/**
+ * Returns void if the given assertion fails.
+ *
+ * @param t statement to check
*/
-/*======================================
- * nullpo_chk
- * Nullチェック 及び 情報出力
- * [引数]
- * file __FILE__
- * line __LINE__
- * func __func__ (関数名)
- * これらには NLP_MARK を使うとよい
- * target チェック対象
- * [返り値]
- * 0 OK
- * 1 NULL
- *--------------------------------------
+#define Assert_retv(t) \
+ do { if (Assert_chk(t)) return; } while(0)
+
+/**
+ * Returns the given value if a NULL pointer is found.
+ *
+ * @param ret value to return
+ * @param t pointer to check
*/
-int nullpo_chk(const char *file, int line, const char *func, const void *target);
-
-
-/*======================================
- * nullpo_chk_f
- * Nullチェック 及び 詳細な情報出力
- * [引数]
- * file __FILE__
- * line __LINE__
- * func __func__ (関数名)
- * これらには NLP_MARK を使うとよい
- * target チェック対象
- * fmt ... vprintfに渡される
- * 備考や関係変数の書き出しなどに
- * [返り値]
- * 0 OK
- * 1 NULL
- *--------------------------------------
+#define nullpo_retr(ret, t) \
+ do { if (nullpo_chk(t)) return(ret); } while(0)
+
+/**
+ * Returns the given value if the given assertion fails.
+ *
+ * @param ret value to return
+ * @param t statement to check
*/
-int nullpo_chk_f(const char *file, int line, const char *func, const void *target,
- const char *fmt, ...)
- __attribute__((format(printf,5,6)));
-
-
-/*======================================
- * nullpo_info
- * nullpo情報出力
- * [引数]
- * file __FILE__
- * line __LINE__
- * func __func__ (関数名)
- * これらには NLP_MARK を使うとよい
- *--------------------------------------
+#define Assert_retr(ret, t) \
+ do { if (Assert_chk(t)) return(ret); } while(0)
+
+/**
+ * Breaks from the current loop/switch if a NULL pointer is found.
+ *
+ * @param t pointer to check
*/
-void nullpo_info(const char *file, int line, const char *func);
-
-
-/*======================================
- * nullpo_info_f
- * nullpo詳細情報出力
- * [引数]
- * file __FILE__
- * line __LINE__
- * func __func__ (関数名)
- * これらには NLP_MARK を使うとよい
- * fmt ... vprintfに渡される
- * 備考や関係変数の書き出しなどに
- *--------------------------------------
+#define nullpo_retb(t) \
+ if (nullpo_chk(t)) break; else (void)0
+
+/**
+ * Breaks from the current loop/switch if the given assertion fails.
+ *
+ * @param t statement to check
*/
-void nullpo_info_f(const char *file, int line, const char *func,
- const char *fmt, ...)
- __attribute__((format(printf,4,5)));
+#define Assert_retb(t) \
+ if (Assert_chk(t)) break; else (void)0
+
+void assert_report(const char *file, int line, const char *func, const char *targetname, const char *title);
-#endif /* _NULLPO_H_ */
+#endif /* _COMMON_NULLPO_H_ */
diff --git a/src/common/raconf.c b/src/common/raconf.c
index f7d1284b7..abeed444b 100644
--- a/src/common/raconf.c
+++ b/src/common/raconf.c
@@ -382,21 +382,20 @@ static bool configParse(raconf inst, const char *fileName){
}//end: configParse()
-#define MAKEKEY(dest, section, key) { size_t section_len, key_len; \
- if(section == NULL || *section == '\0'){ \
- strncpy(dest, "<unnamed>", 9); \
- section_len = 9; \
- }else{ \
- section_len = strlen(section); \
- strncpy(dest, section, section_len); \
- } \
- \
- dest[section_len] = '.'; \
- \
- key_len = strlen(key); \
- strncpy(&dest[section_len+1], key, key_len); \
- dest[section_len + key_len + 1] = '\0'; \
- }
+#define MAKEKEY(dest, section, key) do { \
+ size_t section_len_, key_len_; \
+ if((section) == NULL || *(section) == '\0'){ \
+ strncpy((dest), "<unnamed>", 9); \
+ section_len_ = 9; \
+ } else { \
+ section_len_ = strlen(section); \
+ strncpy((dest), (section), section_len_); \
+ } \
+ (dest)[section_len_] = '.'; \
+ key_len_ = strlen(key); \
+ strncpy(&(dest)[section_len_+1], (key), key_len_); \
+ (dest)[section_len_ + key_len_ + 1] = '\0'; \
+} while(0)
raconf raconf_parse(const char *file_name){
diff --git a/src/common/random.c b/src/common/random.c
index 2f1b62934..e46c52cad 100644
--- a/src/common/random.c
+++ b/src/common/random.c
@@ -17,17 +17,17 @@
/// Initializes the random number generator with an appropriate seed.
void rnd_init(void)
{
- uint32 seed = timer->gettick();
- seed += (uint32)time(NULL);
+ unsigned long seed = (unsigned long)timer->gettick();
+ seed += (unsigned long)time(NULL);
#if defined(WIN32)
- seed += GetCurrentProcessId();
- seed += GetCurrentThreadId();
+ seed += (unsigned long)GetCurrentProcessId();
+ seed += (unsigned long)GetCurrentThreadId();
#else
#if defined(HAVE_GETPID)
- seed += (uint32)getpid();
+ seed += (unsigned long)getpid();
#endif // HAVE_GETPID
#if defined(HAVE_GETTID)
- seed += (uint32)gettid();
+ seed += (unsigned long)gettid();
#endif // HAVE_GETTID
#endif
init_genrand(seed);
diff --git a/src/common/random.h b/src/common/random.h
index 43dfd36c0..ab83fb4d4 100644
--- a/src/common/random.h
+++ b/src/common/random.h
@@ -1,8 +1,8 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#ifndef _RANDOM_H_
-#define _RANDOM_H_
+#ifndef _COMMON_RANDOM_H_
+#define _COMMON_RANDOM_H_
#include "../common/cbasetypes.h"
@@ -15,4 +15,4 @@ int32 rnd_value(int32 min, int32 max);// [min, max]
double rnd_uniform(void);// [0.0, 1.0)
double rnd_uniform53(void);// [0.0, 1.0)
-#endif /* _RANDOM_H_ */
+#endif /* _COMMON_RANDOM_H_ */
diff --git a/src/common/showmsg.c b/src/common/showmsg.c
index 9e0f63003..14342fe5e 100644
--- a/src/common/showmsg.c
+++ b/src/common/showmsg.c
@@ -16,33 +16,17 @@
#include "../../3rdparty/libconfig/libconfig.h"
#ifdef WIN32
- #include "../common/winapi.h"
-
- #ifdef DEBUGLOGMAP
- #define DEBUGLOGPATH "log\\map-server.log"
- #else
- #ifdef DEBUGLOGCHAR
- #define DEBUGLOGPATH "log\\char-server.log"
- #else
- #ifdef DEBUGLOGLOGIN
- #define DEBUGLOGPATH "log\\login-server.log"
- #endif
- #endif
- #endif
-#else
- #include <unistd.h>
-
- #ifdef DEBUGLOGMAP
- #define DEBUGLOGPATH "log/map-server.log"
- #else
- #ifdef DEBUGLOGCHAR
- #define DEBUGLOGPATH "log/char-server.log"
- #else
- #ifdef DEBUGLOGLOGIN
- #define DEBUGLOGPATH "log/login-server.log"
- #endif
- #endif
- #endif
+#include "../common/winapi.h"
+#else // not WIN32
+#include <unistd.h>
+#endif // WIN32
+
+#if defined(DEBUGLOGMAP)
+#define DEBUGLOGPATH "log"PATHSEP_STR"map-server.log"
+#elif defined(DEBUGLOGCHAR)
+#define DEBUGLOGPATH "log"PATHSEP_STR"char-server.log"
+#elif defined(DEBUGLOGLOGIN)
+#define DEBUGLOGPATH "log"PATHSEP_STR"login-server.log"
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -61,41 +45,40 @@ int console_msg_log = 0;//[Ind] msg error logging
#define SBUF_SIZE 2054 // never put less that what's required for the debug message
-#define NEWBUF(buf) \
- struct { \
- char s_[SBUF_SIZE]; \
- StringBuf *d_; \
- char *v_; \
- int l_; \
- } buf ={"",NULL,NULL,0}; \
+#define NEWBUF(buf) \
+ struct { \
+ char s_[SBUF_SIZE]; \
+ StringBuf *d_; \
+ char *v_; \
+ int l_; \
+ } buf ={"",NULL,NULL,0}; \
//define NEWBUF
-#define BUFVPRINTF(buf,fmt,args) \
- buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \
- if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \
- {/* static buffer */ \
- buf.v_ = buf.s_; \
- } \
- else \
- {/* dynamic buffer */ \
- 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
-
-#define BUFVAL(buf) buf.v_
-#define BUFLEN(buf) buf.l_
-
-#define FREEBUF(buf) \
- if( buf.d_ ) \
- { \
- StrBuf->Free(buf.d_); \
- buf.d_ = NULL; \
- } \
- buf.v_ = NULL; \
-//define FREEBUF
+#define BUFVPRINTF(buf,fmt,args) do { \
+ (buf).l_ = vsnprintf((buf).s_, SBUF_SIZE, (fmt), args); \
+ if( (buf).l_ >= 0 && (buf).l_ < SBUF_SIZE ) \
+ {/* static buffer */ \
+ (buf).v_ = (buf).s_; \
+ } \
+ else \
+ {/* dynamic buffer */ \
+ (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); \
+ } \
+} while(0) //define BUFVPRINTF
+
+#define BUFVAL(buf) ((buf).v_)
+#define BUFLEN(buf) ((buf).l_)
+
+#define FREEBUF(buf) do {\
+ if( (buf).d_ ) { \
+ StrBuf->Free((buf).d_); \
+ (buf).d_ = NULL; \
+ } \
+ (buf).v_ = NULL; \
+} while(0) //define FREEBUF
///////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
@@ -666,14 +649,6 @@ int FPRINTF(FILE *file, const char *fmt, ...)
#endif// not _WIN32
-
-
-
-
-
-
-
-
char timestamp_format[20] = ""; //For displaying Timestamps
int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
diff --git a/src/common/showmsg.h b/src/common/showmsg.h
index 59a0d9538..49fbc34fb 100644
--- a/src/common/showmsg.h
+++ b/src/common/showmsg.h
@@ -2,12 +2,15 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _SHOWMSG_H_
-#define _SHOWMSG_H_
+#ifndef _COMMON_SHOWMSG_H_
+#define _COMMON_SHOWMSG_H_
-#ifndef _HPMi_H_
+#ifndef _COMMON_HPMI_H_
#include "../../3rdparty/libconfig/libconfig.h"
#endif
+
+#include <stdarg.h>
+
// for help with the console colors look here:
// http://www.edoceo.com/liberum/?doc=printf-with-color
// some code explanation (used here):
@@ -87,7 +90,7 @@ enum msg_type {
};
extern void ClearScreen(void);
-#ifndef _HPMi_H_
+#ifndef _COMMON_HPMI_H_
extern void ShowMessage(const char *, ...);
extern void ShowStatus(const char *, ...);
extern void ShowSQL(const char *, ...);
@@ -99,5 +102,6 @@ extern void ClearScreen(void);
extern void ShowFatalError(const char *, ...);
extern void ShowConfigWarning(config_setting_t *config, const char *string, ...);
#endif
+extern int _vShowMessage(enum msg_type flag, const char *string, va_list ap);
-#endif /* _SHOWMSG_H_ */
+#endif /* _COMMON_SHOWMSG_H_ */
diff --git a/src/common/socket.c b/src/common/socket.c
index 7c8b3738b..35d350e95 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -10,6 +10,9 @@
#include "../common/strlib.h"
#include "../config/core.h"
#include "../common/HPM.h"
+
+#define _H_SOCKET_C_
+
#include "socket.h"
#include <stdio.h>
@@ -43,6 +46,19 @@
#endif
#endif
+/**
+ * Socket Interface Source
+ **/
+struct socket_interface sockt_s;
+
+#ifdef SEND_SHORTLIST
+ // Add a fd to the shortlist so that it'll be recognized as a fd that needs
+ // sending done on it.
+ void send_shortlist_add_fd(int fd);
+ // Do pending network sends (and eof handling) from the shortlist.
+ void send_shortlist_do_sends();
+#endif
+
/////////////////////////////////////////////////////////////////////
#if defined(WIN32)
/////////////////////////////////////////////////////////////////////
@@ -157,19 +173,19 @@ char* sErr(int code)
return sbuf;
}
-#define sBind(fd,name,namelen) bind(fd2sock(fd),name,namelen)
-#define sConnect(fd,name,namelen) connect(fd2sock(fd),name,namelen)
-#define sIoctl(fd,cmd,argp) ioctlsocket(fd2sock(fd),cmd,argp)
-#define sListen(fd,backlog) listen(fd2sock(fd),backlog)
-#define sRecv(fd,buf,len,flags) recv(fd2sock(fd),buf,len,flags)
-#define sSelect select
-#define sSend(fd,buf,len,flags) send(fd2sock(fd),buf,len,flags)
-#define sSetsockopt(fd,level,optname,optval,optlen) setsockopt(fd2sock(fd),level,optname,optval,optlen)
-#define sShutdown(fd,how) shutdown(fd2sock(fd),how)
-#define sFD_SET(fd,set) FD_SET(fd2sock(fd),set)
-#define sFD_CLR(fd,set) FD_CLR(fd2sock(fd),set)
-#define sFD_ISSET(fd,set) FD_ISSET(fd2sock(fd),set)
-#define sFD_ZERO FD_ZERO
+#define sBind(fd,name,namelen) bind(fd2sock(fd),(name),(namelen))
+#define sConnect(fd,name,namelen) connect(fd2sock(fd),(name),(namelen))
+#define sIoctl(fd,cmd,argp) ioctlsocket(fd2sock(fd),(cmd),(argp))
+#define sListen(fd,backlog) listen(fd2sock(fd),(backlog))
+#define sRecv(fd,buf,len,flags) recv(fd2sock(fd),(buf),(len),(flags))
+#define sSelect select
+#define sSend(fd,buf,len,flags) send(fd2sock(fd),(buf),(len),(flags))
+#define sSetsockopt(fd,level,optname,optval,optlen) setsockopt(fd2sock(fd),(level),(optname),(optval),(optlen))
+#define sShutdown(fd,how) shutdown(fd2sock(fd),(how))
+#define sFD_SET(fd,set) FD_SET(fd2sock(fd),(set))
+#define sFD_CLR(fd,set) FD_CLR(fd2sock(fd),(set))
+#define sFD_ISSET(fd,set) FD_ISSET(fd2sock(fd),(set))
+#define sFD_ZERO FD_ZERO
/////////////////////////////////////////////////////////////////////
#else
@@ -212,12 +228,6 @@ char* sErr(int code)
#endif
fd_set readfds;
-int fd_max;
-time_t last_tick;
-time_t stall_time = 60;
-
-uint32 addr_[16]; // ip addresses of local host (host byte order)
-int naddr_ = 0; // # of ip addresses
// Maximum packet size in bytes, which the client is able to handle.
// Larger packets cause a buffer overflow and stack corruption.
@@ -328,7 +338,7 @@ void setsocketopts(int fd, struct hSockOpt *opt) {
*--------------------------------------*/
void set_eof(int fd)
{
- if( session_isActive(fd) )
+ if( sockt->session_isActive(fd) )
{
#ifdef SEND_SHORTLIST
// Add this socket to the shortlist for eof handling.
@@ -340,9 +350,9 @@ void set_eof(int fd)
int recv_to_fifo(int fd)
{
- int len;
+ ssize_t len;
- if( !session_isActive(fd) )
+ if( !sockt->session_isActive(fd) )
return -1;
len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0);
@@ -363,7 +373,7 @@ int recv_to_fifo(int fd)
}
session[fd]->rdata_size += len;
- session[fd]->rdata_tick = last_tick;
+ session[fd]->rdata_tick = sockt->last_tick;
#ifdef SHOW_SERVER_STATS
socket_data_i += len;
socket_data_qi += len;
@@ -377,9 +387,9 @@ int recv_to_fifo(int fd)
int send_from_fifo(int fd)
{
- int len;
+ ssize_t len;
- if( !session_isValid(fd) )
+ if( !sockt->session_isValid(fd) )
return -1;
if( session[fd]->wdata_size == 0 )
@@ -431,8 +441,8 @@ void flush_fifo(int fd)
void flush_fifos(void)
{
int i;
- for(i = 1; i < fd_max; i++)
- flush_fifo(i);
+ for(i = 1; i < sockt->fd_max; i++)
+ sockt->flush_fifo(i);
}
/*======================================
@@ -466,12 +476,12 @@ int connect_client(int listen_fd) {
#ifndef MINICORE
if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) {
- do_close(fd);
+ sockt->close(fd);
return -1;
}
#endif
- if( fd_max <= fd ) fd_max = fd + 1;
+ if( sockt->fd_max <= fd ) sockt->fd_max = fd + 1;
sFD_SET(fd,&readfds);
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
@@ -521,7 +531,7 @@ int make_listen_bind(uint32 ip, uint16 port)
exit(EXIT_FAILURE);
}
- if(fd_max <= fd) fd_max = fd + 1;
+ if(sockt->fd_max <= fd) sockt->fd_max = fd + 1;
sFD_SET(fd, &readfds);
create_session(fd, connect_client, null_send, null_parse);
@@ -566,13 +576,13 @@ int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
if( result == SOCKET_ERROR ) {
if( !( opt && opt->silent ) )
ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg());
- do_close(fd);
+ sockt->close(fd);
return -1;
}
//Now the socket can be made non-blocking. [Skotlex]
set_nonblocking(fd, 1);
- if (fd_max <= fd) fd_max = fd + 1;
+ if (sockt->fd_max <= fd) sockt->fd_max = fd + 1;
sFD_SET(fd,&readfds);
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
@@ -591,7 +601,7 @@ static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseF
session[fd]->func_recv = func_recv;
session[fd]->func_send = func_send;
session[fd]->func_parse = func_parse;
- session[fd]->rdata_tick = last_tick;
+ session[fd]->rdata_tick = sockt->last_tick;
session[fd]->session_data = NULL;
session[fd]->hdata = NULL;
session[fd]->hdatac = 0;
@@ -600,7 +610,7 @@ static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseF
static void delete_session(int fd)
{
- if( session_isValid(fd) ) {
+ if( sockt->session_isValid(fd) ) {
unsigned int i;
#ifdef SHOW_SERVER_STATS
socket_data_qi -= session[fd]->rdata_size - session[fd]->rdata_pos;
@@ -613,8 +623,8 @@ static void delete_session(int fd)
for(i = 0; i < session[fd]->hdatac; i++) {
if( session[fd]->hdata[i]->flag.free ) {
aFree(session[fd]->hdata[i]->data);
- aFree(session[fd]->hdata[i]);
}
+ aFree(session[fd]->hdata[i]);
}
if( session[fd]->hdata )
aFree(session[fd]->hdata);
@@ -625,7 +635,7 @@ static void delete_session(int fd)
int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size)
{
- if( !session_isValid(fd) )
+ if( !sockt->session_isValid(fd) )
return 0;
if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) {
@@ -644,7 +654,7 @@ int realloc_writefifo(int fd, size_t addition)
{
size_t newsize;
- if( !session_isValid(fd) ) // might not happen
+ if( !sockt->session_isValid(fd) ) // might not happen
return 0;
if( session[fd]->wdata_size + addition > session[fd]->max_wdata )
@@ -672,7 +682,7 @@ int RFIFOSKIP(int fd, size_t len)
{
struct socket_data *s;
- if ( !session_isActive(fd) )
+ if ( !sockt->session_isActive(fd) )
return 0;
s = session[fd];
@@ -695,7 +705,7 @@ int WFIFOSET(int fd, size_t len)
size_t newreserve;
struct socket_data* s = session[fd];
- if( !session_isValid(fd) || s->wdata == NULL )
+ if( !sockt->session_isValid(fd) || s->wdata == NULL )
return 0;
// we have written len bytes to the buffer already before calling WFIFOSET
@@ -771,7 +781,7 @@ int do_sockets(int next)
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
#else
- for (i = 1; i < fd_max; i++)
+ for (i = 1; i < sockt->fd_max; i++)
{
if(!session[i])
continue;
@@ -786,7 +796,7 @@ int do_sockets(int next)
timeout.tv_usec = next%1000*1000;
memcpy(&rfd, &readfds, sizeof(rfd));
- ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout);
+ ret = sSelect(sockt->fd_max, &rfd, NULL, NULL, &timeout);
if( ret == SOCKET_ERROR )
{
@@ -798,7 +808,7 @@ int do_sockets(int next)
return 0; // interrupted by a signal, just loop and try again
}
- last_tick = time(NULL);
+ sockt->last_tick = time(NULL);
#if defined(WIN32)
// on windows, enumerating all members of the fd_set is way faster if we access the internals
@@ -810,7 +820,7 @@ int do_sockets(int next)
}
#else
// otherwise assume that the fd_set is a bit-array and enumerate it in a standard way
- for( i = 1; ret && i < fd_max; ++i )
+ for( i = 1; ret && i < sockt->fd_max; ++i )
{
if(sFD_ISSET(i,&rfd) && session[i])
{
@@ -824,7 +834,7 @@ int do_sockets(int next)
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
#else
- for (i = 1; i < fd_max; i++)
+ for (i = 1; i < sockt->fd_max; i++)
{
if(!session[i])
continue;
@@ -840,12 +850,12 @@ int do_sockets(int next)
#endif
// parse input data on each socket
- for(i = 1; i < fd_max; i++)
+ for(i = 1; i < sockt->fd_max; i++)
{
if(!session[i])
continue;
- if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) {
+ if (session[i]->rdata_tick && DIFF_TICK(sockt->last_tick, session[i]->rdata_tick) > sockt->stall_time) {
if( session[i]->flag.server ) {/* server is special */
if( session[i]->flag.ping != 2 )/* only update if necessary otherwise it'd resend the ping unnecessarily */
session[i]->flag.ping = 1;
@@ -855,21 +865,25 @@ int do_sockets(int next)
}
}
+#ifdef __clang_analyzer__
+ // Let Clang's static analyzer know this never happens (it thinks it might because of a NULL check in session_isValid)
+ if (!session[i]) continue;
+#endif // __clang_analyzer__
session[i]->func_parse(i);
if(!session[i])
continue;
-
+
+ RFIFOFLUSH(i);
// 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 == session[i]->max_rdata) {
set_eof(i);
continue;
}
- RFIFOFLUSH(i);
}
#ifdef SHOW_SERVER_STATS
- if (last_tick != socket_data_last_tick)
+ if (sockt->last_tick != socket_data_last_tick)
{
char buf[1024];
@@ -879,7 +893,7 @@ int do_sockets(int next)
#else
ShowMessage("\033[s\033[1;1H\033[2K%s\033[u", buf);
#endif
- socket_data_last_tick = last_tick;
+ socket_data_last_tick = sockt->last_tick;
socket_data_i = socket_data_ci = 0;
socket_data_o = socket_data_co = 0;
}
@@ -896,7 +910,7 @@ int do_sockets(int next)
typedef struct _connect_history {
struct _connect_history* next;
uint32 ip;
- uint32 tick;
+ int64 tick;
int count;
unsigned ddos : 1;
} ConnectHistory;
@@ -1043,8 +1057,7 @@ static int connect_check_(uint32 ip)
/// Timer function.
/// Deletes old connection history records.
-static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data)
-{
+static int connect_check_clear(int tid, int64 tick, int id, intptr_t data) {
int i;
int clear = 0;
int list = 0;
@@ -1145,9 +1158,9 @@ int socket_config_read(const char* cfgName)
continue;
if (!strcmpi(w1, "stall_time")) {
- stall_time = atoi(w2);
- if( stall_time < 3 )
- stall_time = 3;/* a minimum is required to refrain it from killing itself */
+ sockt->stall_time = atoi(w2);
+ if( sockt->stall_time < 3 )
+ sockt->stall_time = 3;/* a minimum is required to refrain it from killing itself */
}
#ifndef MINICORE
else if (!strcmpi(w1, "enable_ip_rules")) {
@@ -1215,9 +1228,9 @@ void socket_final(void)
aFree(access_deny);
#endif
- for( i = 1; i < fd_max; i++ )
+ for( i = 1; i < sockt->fd_max; i++ )
if(session[i])
- do_close(i);
+ sockt->close(i);
// session[0] のダミーデータを削除
aFree(session[0]->rdata);
@@ -1331,7 +1344,7 @@ int socket_getips(uint32* ips, int max)
void socket_init(void)
{
char *SOCKET_CONF_FILENAME = "conf/packet.conf";
- unsigned int rlim_cur = FD_SETSIZE;
+ uint64 rlim_cur = FD_SETSIZE;
#ifdef WIN32
{// Start up windows networking
@@ -1379,7 +1392,7 @@ void socket_init(void)
#endif
// Get initial local ips
- naddr_ = socket_getips(addr_,16);
+ sockt->naddr_ = socket_getips(sockt->addr_,16);
sFD_ZERO(&readfds);
#if defined(SEND_SHORTLIST)
@@ -1391,7 +1404,7 @@ void socket_init(void)
socket_config_read(SOCKET_CONF_FILENAME);
// initialise last send-receive tick
- last_tick = time(NULL);
+ sockt->last_tick = time(NULL);
// session[0] is now currently used for disconnected sessions of the map server, and as such,
// should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex]
@@ -1404,12 +1417,10 @@ void socket_init(void)
timer->add_interval(timer->gettick()+1000, connect_check_clear, 0, 0, 5*60*1000);
#endif
- ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur);
+ ShowInfo("Server supports up to '"CL_WHITE"%"PRId64""CL_RESET"' concurrent connections.\n", rlim_cur);
/* Hercules Plugin Manager */
HPM->share(session,"session");
- HPM->share(&fd_max,"fd_max");
- HPM->share(addr_,"addr");
}
bool session_isValid(int fd)
@@ -1419,7 +1430,7 @@ bool session_isValid(int fd)
bool session_isActive(int fd)
{
- return ( session_isValid(fd) && !session[fd]->flag.eof );
+ return ( sockt->session_isValid(fd) && !session[fd]->flag.eof );
}
// Resolves hostname into a numeric ip.
@@ -1461,8 +1472,6 @@ void socket_datasync(int fd, bool send) {
{ 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) },
@@ -1473,7 +1482,6 @@ void socket_datasync(int fd, bool send) {
{ 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) },
@@ -1484,6 +1492,7 @@ void socket_datasync(int fd, bool send) {
{ sizeof(struct guild) },
{ sizeof(struct guild_castle) },
{ sizeof(struct fame_list) },
+ { PACKETVER },
};
unsigned short i;
unsigned int alen = ARRAYLENGTH(data_list);
@@ -1525,7 +1534,7 @@ void send_shortlist_add_fd(int fd)
int i;
int bit;
- if( !session_isValid(fd) )
+ if( !sockt->session_isValid(fd) )
return;// out of range
i = fd/32;
@@ -1594,3 +1603,44 @@ void send_shortlist_do_sends()
}
}
#endif
+
+void socket_defaults(void) {
+ sockt = &sockt_s;
+
+ sockt->fd_max = 0;
+ /* */
+ sockt->stall_time = 60;
+ sockt->last_tick = 0;
+ /* */
+ memset(&sockt->addr_, 0, sizeof(sockt->addr_));
+ sockt->naddr_ = 0;
+ /* */
+ sockt->init = socket_init;
+ sockt->final = socket_final;
+ /* */
+ sockt->perform = do_sockets;
+ /* */
+ sockt->datasync = socket_datasync;
+ /* */
+ sockt->make_listen_bind = make_listen_bind;
+ sockt->make_connection = make_connection;
+ sockt->realloc_fifo = realloc_fifo;
+ sockt->realloc_writefifo = realloc_writefifo;
+ sockt->WFIFOSET = WFIFOSET;
+ sockt->RFIFOSKIP = RFIFOSKIP;
+ sockt->close = do_close;
+ /* */
+ sockt->session_isValid = session_isValid;
+ sockt->session_isActive = session_isActive;
+ /* */
+ sockt->flush_fifo = flush_fifo;
+ sockt->flush_fifos = flush_fifos;
+ sockt->set_nonblocking = set_nonblocking;
+ sockt->set_defaultparse = set_defaultparse;
+ sockt->host2ip = host2ip;
+ sockt->ip2str = ip2str;
+ sockt->str2ip = str2ip;
+ sockt->ntows = ntows;
+ sockt->getips = socket_getips;
+ sockt->set_eof = set_eof;
+}
diff --git a/src/common/socket.h b/src/common/socket.h
index 0e34da660..ca9141716 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -2,8 +2,8 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _SOCKET_H_
-#define _SOCKET_H_
+#ifndef _COMMON_SOCKET_H_
+#define _COMMON_SOCKET_H_
#include "../common/cbasetypes.h"
@@ -24,18 +24,18 @@ struct HPluginData;
// socket I/O macros
#define RFIFOHEAD(fd)
-#define WFIFOHEAD(fd, size) do{ if((fd) && session[fd]->wdata_size + (size) > session[fd]->max_wdata ) realloc_writefifo(fd, size); }while(0)
+#define WFIFOHEAD(fd, size) do{ if((fd) && session[fd]->wdata_size + (size) > session[fd]->max_wdata ) realloc_writefifo((fd), (size)); }while(0)
#define RFIFOP(fd,pos) (session[fd]->rdata + session[fd]->rdata_pos + (pos))
#define WFIFOP(fd,pos) (session[fd]->wdata + session[fd]->wdata_size + (pos))
-#define RFIFOB(fd,pos) (*(uint8*)RFIFOP(fd,pos))
-#define WFIFOB(fd,pos) (*(uint8*)WFIFOP(fd,pos))
-#define RFIFOW(fd,pos) (*(uint16*)RFIFOP(fd,pos))
-#define WFIFOW(fd,pos) (*(uint16*)WFIFOP(fd,pos))
-#define RFIFOL(fd,pos) (*(uint32*)RFIFOP(fd,pos))
-#define WFIFOL(fd,pos) (*(uint32*)WFIFOP(fd,pos))
-#define RFIFOQ(fd,pos) (*(uint64*)RFIFOP(fd,pos))
-#define WFIFOQ(fd,pos) (*(uint64*)WFIFOP(fd,pos))
+#define RFIFOB(fd,pos) (*(uint8*)RFIFOP((fd),(pos)))
+#define WFIFOB(fd,pos) (*(uint8*)WFIFOP((fd),(pos)))
+#define RFIFOW(fd,pos) (*(uint16*)RFIFOP((fd),(pos)))
+#define WFIFOW(fd,pos) (*(uint16*)WFIFOP((fd),(pos)))
+#define RFIFOL(fd,pos) (*(uint32*)RFIFOP((fd),(pos)))
+#define WFIFOL(fd,pos) (*(uint32*)WFIFOP((fd),(pos)))
+#define RFIFOQ(fd,pos) (*(uint64*)RFIFOP((fd),(pos)))
+#define WFIFOQ(fd,pos) (*(uint64*)WFIFOP((fd),(pos)))
#define RFIFOSPACE(fd) (session[fd]->max_rdata - session[fd]->rdata_size)
#define WFIFOSPACE(fd) (session[fd]->max_wdata - session[fd]->wdata_size)
@@ -77,8 +77,7 @@ typedef int (*RecvFunc)(int fd);
typedef int (*SendFunc)(int fd);
typedef int (*ParseFunc)(int fd);
-struct socket_data
-{
+struct socket_data {
struct {
unsigned char eof : 1;
unsigned char server : 1;
@@ -108,72 +107,93 @@ struct hSockOpt {
unsigned int setTimeo : 1;
};
-// Data prototype declaration
-
-struct socket_data **session;
-
-extern int fd_max;
-
-extern time_t last_tick;
-extern time_t stall_time;
-
-//////////////////////////////////
-// some checking on sockets
-extern bool session_isValid(int fd);
-extern bool session_isActive(int fd);
-//////////////////////////////////
-
-// Function prototype declaration
-
-int make_listen_bind(uint32 ip, uint16 port);
-int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt);
-int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size);
-int realloc_writefifo(int fd, size_t addition);
-int WFIFOSET(int fd, size_t len);
-int RFIFOSKIP(int fd, size_t len);
-
-int do_sockets(int next);
-void do_close(int fd);
-void socket_init(void);
-void socket_final(void);
-
-extern void flush_fifo(int fd);
-extern void flush_fifos(void);
-extern void set_nonblocking(int fd, unsigned long yes);
-
-void set_defaultparse(ParseFunc defaultparse);
-
-// hostname/ip conversion functions
-uint32 host2ip(const char* hostname);
-const char* ip2str(uint32 ip, char ip_str[16]);
-uint32 str2ip(const char* ip_str);
-#define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF
-#define MAKEIP(a,b,c,d) (uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) )
-uint16 ntows(uint16 netshort);
-
-int socket_getips(uint32* ips, int max);
-
-extern uint32 addr_[16]; // ip addresses of local host (host byte order)
-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
+/// 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.
///
/// @author Buuyo-tama
#define SEND_SHORTLIST
-#ifdef SEND_SHORTLIST
-// Add a fd to the shortlist so that it'll be recognized as a fd that needs
-// sending done on it.
-void send_shortlist_add_fd(int fd);
-// Do pending network sends (and eof handling) from the shortlist.
-void send_shortlist_do_sends();
-#endif
+// Note: purposely returns four comma-separated arguments
+#define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF
+#define MAKEIP(a,b,c,d) ((uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) ))
+
+/**
+ * This stays out of the interface.
+ **/
+struct socket_data **session;
+
+/**
+ * Socket.c interface, mostly for reading however.
+ **/
+struct socket_interface {
+ int fd_max;
+ /* */
+ time_t stall_time;
+ time_t last_tick;
+ /* */
+ uint32 addr_[16]; // ip addresses of local host (host byte order)
+ int naddr_; // # of ip addresses
+ /* */
+ void (*init) (void);
+ void (*final) (void);
+ /* */
+ int (*perform) (int next);
+ /* [Ind/Hercules] - socket_datasync */
+ void (*datasync) (int fd, bool send);
+ /* */
+ int (*make_listen_bind) (uint32 ip, uint16 port);
+ int (*make_connection) (uint32 ip, uint16 port, struct hSockOpt *opt);
+ int (*realloc_fifo) (int fd, unsigned int rfifo_size, unsigned int wfifo_size);
+ int (*realloc_writefifo) (int fd, size_t addition);
+ int (*WFIFOSET) (int fd, size_t len);
+ int (*RFIFOSKIP) (int fd, size_t len);
+ void (*close) (int fd);
+ /* */
+ bool (*session_isValid) (int fd);
+ bool (*session_isActive) (int fd);
+ /* */
+ void (*flush_fifo) (int fd);
+ void (*flush_fifos) (void);
+ void (*set_nonblocking) (int fd, unsigned long yes);
+ void (*set_defaultparse) (ParseFunc defaultparse);
+ /* hostname/ip conversion functions */
+ uint32 (*host2ip) (const char* hostname);
+ const char * (*ip2str) (uint32 ip, char ip_str[16]);
+ uint32 (*str2ip) (const char* ip_str);
+ /* */
+ uint16 (*ntows) (uint16 netshort);
+ /* */
+ int (*getips) (uint32* ips, int max);
+ /* */
+ void (*set_eof) (int fd);
+};
-#endif /* _SOCKET_H_ */
+struct socket_interface *sockt;
+
+void socket_defaults(void);
+
+/* the purpose of these macros is simply to not make calling them be an annoyance */
+#ifndef _H_SOCKET_C_
+ #define make_listen_bind(ip, port) ( sockt->make_listen_bind(ip, port) )
+ #define make_connection(ip, port, opt) ( sockt->make_connection(ip, port, opt) )
+ #define realloc_fifo(fd, rfifo_size, wfifo_size) ( sockt->realloc_fifo(fd, rfifo_size, wfifo_size) )
+ #define realloc_writefifo(fd, addition) ( sockt->realloc_writefifo(fd, addition) )
+ #define WFIFOSET(fd, len) ( sockt->WFIFOSET(fd, len) )
+ #define RFIFOSKIP(fd, len) ( sockt->RFIFOSKIP(fd, len) )
+ #define do_close(fd) ( sockt->close(fd) )
+ #define session_isValid(fd) ( sockt->session_isValid(fd) )
+ #define session_isActive(fd) ( sockt->session_isActive(fd) )
+ #define flush_fifo(fd) ( sockt->flush_fifo(fd) )
+ #define flush_fifos() ( sockt->flush_fifos() )
+ #define set_nonblocking(fd, yes) ( sockt->set_nonblocking(fd, yes) )
+ #define set_defaultparse(defaultparse) ( sockt->set_defaultparse(defaultparse) )
+ #define host2ip(hostname) ( sockt->host2ip(hostname) )
+ #define ip2str(ip, ip_str) ( sockt->ip2str(ip, ip_str) )
+ #define str2ip(ip_str) ( sockt->str2ip(ip_str) )
+ #define ntows(netshort) ( sockt->ntows(netshort) )
+ #define getips(ips, max) ( sockt->getips(ips, max) )
+ #define set_eof(fd) ( sockt->set_eof(fd) )
+#endif /* _H_SOCKET_C_ */
+
+#endif /* _COMMON_SOCKET_H_ */
diff --git a/src/common/spinlock.h b/src/common/spinlock.h
index 3419bfdd5..29fbb355b 100644
--- a/src/common/spinlock.h
+++ b/src/common/spinlock.h
@@ -1,6 +1,6 @@
#pragma once
-#ifndef _rA_SPINLOCK_H_
-#define _rA_SPINLOCK_H_
+#ifndef _COMMON_SPINLOCK_H_
+#define _COMMON_SPINLOCK_H_
//
// CAS based Spinlock Implementation
@@ -52,8 +52,8 @@ static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){
}
-#define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } }
-#define dropsynclock(l) { InterlockedExchange(l, 0); }
+#define getsynclock(l) do { if(InterlockedCompareExchange((l), 1, 0) == 0) break; rathread_yield(); } while(/*always*/1)
+#define dropsynclock(l) do { InterlockedExchange((l), 0); } while(0)
static forceinline void EnterSpinLock(PSPIN_LOCK lck){
int tid = rathread_get_tid();
@@ -101,4 +101,4 @@ static forceinline void LeaveSpinLock(PSPIN_LOCK lck){
-#endif
+#endif /* _COMMON_SPINLOCK_H_ */
diff --git a/src/common/sql.c b/src/common/sql.c
index 9b7fe4108..79ccc8e92 100644
--- a/src/common/sql.c
+++ b/src/common/sql.c
@@ -180,7 +180,7 @@ int Sql_Ping(Sql* self)
/// Wrapper function for Sql_Ping.
///
/// @private
-static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data)
+static int Sql_P_KeepaliveTimer(int tid, int64 tick, int id, intptr_t data)
{
Sql* self = (Sql*)data;
ShowInfo("Pinging SQL server to keep connection alive...\n");
@@ -1005,6 +1005,9 @@ void Sql_HerculesUpdateCheck(Sql* self) {
unsigned int performed = 0;
StringBuf buf;
+ if( self == NULL )
+ return;/* return silently, build has no mysql connection */
+
if( !( ifp = fopen("sql-files/upgrades/index.txt", "r") ) ) {
ShowError("SQL upgrade index was not found!\n");
return;
@@ -1033,7 +1036,7 @@ void Sql_HerculesUpdateCheck(Sql* self) {
fseek (ufp,1,SEEK_SET);/* woo. skip the # */
if( fgets(timestamp,sizeof(timestamp),ufp) ) {
- unsigned int timestampui = atol(timestamp);
+ unsigned int timestampui = (unsigned int)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 ) {
@@ -1076,7 +1079,7 @@ void Sql_HerculesUpdateSkip(Sql* self,const char *filename) {
fseek (ifp,1,SEEK_SET);/* woo. skip the # */
if( fgets(timestamp,sizeof(timestamp),ifp) ) {
- unsigned int timestampui = atol(timestamp);
+ unsigned int timestampui = (unsigned int)atol(timestamp);
if( SQL_ERROR == SQL->Query(self, "SELECT 1 FROM `sql_updates` WHERE `timestamp` = '%u' LIMIT 1", timestampui) )
Sql_ShowDebug(self);
else if( Sql_NumRows(self) == 1 ) {
diff --git a/src/common/sql.h b/src/common/sql.h
index da00edf2d..1fb436853 100644
--- a/src/common/sql.h
+++ b/src/common/sql.h
@@ -11,7 +11,7 @@
// Return codes
-#define SQL_ERROR -1
+#define SQL_ERROR (-1)
#define SQL_SUCCESS 0
#define SQL_NO_DATA 100
@@ -277,7 +277,7 @@ void sql_defaults(void);
#if defined(SQL_REMOVE_SHOWDEBUG)
#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
void Sql_HerculesUpdateCheck(Sql* self);
@@ -286,16 +286,10 @@ void Sql_HerculesUpdateSkip(Sql* self,const char *filename);
#if defined(SQL_REMOVE_SHOWDEBUG)
#define SqlStmt_ShowDebug(self) (void)0
#else
-#define SqlStmt_ShowDebug(self) SQL->StmtShowDebug_(self, __FILE__, __LINE__)
-#endif
/// Shows debug information (with statement).
-
-
-
-
-
+#define SqlStmt_ShowDebug(self) (SQL->StmtShowDebug_((self), __FILE__, __LINE__))
+#endif
void Sql_Init(void);
-
#endif /* _COMMON_SQL_H_ */
diff --git a/src/common/strlib.c b/src/common/strlib.c
index e45cb0789..361595b07 100644
--- a/src/common/strlib.c
+++ b/src/common/strlib.c
@@ -240,16 +240,19 @@ char* _strtok_r(char *s1, const char *s2, char **lasts) {
}
#endif
+// TODO: The _MSC_VER check can probably be removed (we no longer support VS
+// versions <= 2003, do we?), but this implementation might be still necessary
+// for NetBSD 5.x and possibly some Solaris versions.
#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
/* Find the length of STRING, but scan at most MAXLEN characters.
If no '\0' terminator is found in that many characters, return MAXLEN. */
-size_t strnlen (const char* string, size_t maxlen)
-{
- const char* end = (const char*)memchr(string, '\0', maxlen);
- return end ? (size_t) (end - string) : maxlen;
+size_t strnlen(const char* string, size_t maxlen) {
+ const char* end = (const char*)memchr(string, '\0', maxlen);
+ return end ? (size_t) (end - string) : maxlen;
}
#endif
+// TODO: This should probably be removed, I don't think we support MSVC++ 6.0 anymore.
#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
uint64 strtoull(const char* str, char** endptr, int base)
{
@@ -331,13 +334,22 @@ int e_mail_check(char* email)
//--------------------------------------------------
// Return numerical value of a switch configuration
-// on/off, english, fran軋is, deutsch, espaol
+// on/off, yes/no, true/false, number
//--------------------------------------------------
-int config_switch(const char* str)
-{
- if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
+int config_switch(const char* str) {
+ size_t len = strlen(str);
+ if ((len == 2 && strcmpi(str, "on") == 0)
+ || (len == 3 && strcmpi(str, "yes") == 0)
+ || (len == 4 && strcmpi(str, "true") == 0)
+ // || (len == 3 && strcmpi(str, "oui") == 0) // Uncomment and edit to add your own localized versions
+ )
return 1;
- if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
+
+ if ((len == 3 && strcmpi(str, "off") == 0)
+ || (len == 2 && strcmpi(str, "no") == 0)
+ || (len == 5 && strcmpi(str, "false") == 0)
+ // || (len == 3 && strcmpi(str, "non") == 0) // Uncomment and edit to add your own localized versions
+ )
return 0;
return (int)strtol(str, NULL, 0);
@@ -952,7 +964,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
continue;
- columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
+ columns = sv_split(line, (int)strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
if( columns < mincols ) {
ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols);
@@ -1018,7 +1030,8 @@ int StringBuf_Printf(StringBuf* self, const char* fmt, ...) {
/// Appends the result of vprintf to the StringBuf
int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) {
- int n, size, off;
+ int n, off;
+ size_t size;
for(;;) {
va_list apcopy;
@@ -1028,7 +1041,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 && (size_t)n < size ) {
self->ptr_ += n;
return (int)(self->ptr_ - self->buf_);
}
@@ -1042,11 +1055,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 available = self->max_ - (self->ptr_ - self->buf_);
- int needed = (int)(sbuf->ptr_ - sbuf->buf_);
+ size_t available = self->max_ - (self->ptr_ - self->buf_);
+ size_t needed = sbuf->ptr_ - sbuf->buf_;
if( needed >= available ) {
- int off = (int)(self->ptr_ - self->buf_);
+ size_t off = (self->ptr_ - self->buf_);
self->max_ += needed;
self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1);
self->ptr_ = self->buf_ + off;
@@ -1059,12 +1072,12 @@ int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) {
// Appends str to the StringBuf
int StringBuf_AppendStr(StringBuf* self, const char* str) {
- int available = self->max_ - (self->ptr_ - self->buf_);
- int needed = (int)strlen(str);
+ size_t available = self->max_ - (self->ptr_ - self->buf_);
+ size_t needed = strlen(str);
if( needed >= available ) {
// not enough space, expand the buffer (minimum expansion = 1024)
- int off = (int)(self->ptr_ - self->buf_);
+ size_t off = (self->ptr_ - self->buf_);
self->max_ += max(needed, 1024);
self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1);
self->ptr_ = self->buf_ + off;
@@ -1118,10 +1131,14 @@ void strlib_defaults(void) {
#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
strlib->strnlen = strnlen;
+#else
+ strlib->strnlen = NULL;
#endif
#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
strlib->strtoull = strtoull;
+#else
+ strlib->strtoull = NULL;
#endif
strlib->e_mail_check = e_mail_check;
strlib->config_switch = config_switch;
diff --git a/src/common/strlib.h b/src/common/strlib.h
index 5ef455a0e..10844d257 100644
--- a/src/common/strlib.h
+++ b/src/common/strlib.h
@@ -2,8 +2,8 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _STRLIB_H_
-#define _STRLIB_H_
+#ifndef _COMMON_STRLIB_H_
+#define _COMMON_STRLIB_H_
#include "../common/cbasetypes.h"
#include <stdarg.h>
@@ -70,13 +70,11 @@ struct strlib_interface {
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)
+ /* only used when '!(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)', needs to be defined at all times however */
size_t (*strnlen) (const char* string, size_t maxlen);
-#endif
-
-#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
+
+ /* only used when 'defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200', needs to be defined at all times however */
uint64 (*strtoull) (const char* str, char** endptr, int base);
-#endif
int (*e_mail_check) (char* email);
int (*config_switch) (const char* str);
@@ -168,28 +166,29 @@ 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)
+ #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)
+ #define strnlen(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)
+ #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)
+ #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_ */
+
+#endif /* _COMMON_STRLIB_H_ */
diff --git a/src/common/thread.h b/src/common/thread.h
index a5a66e954..d6b2bbc6e 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -2,8 +2,8 @@
// For more information, see LICENCE in the main folder
#pragma once
-#ifndef _rA_THREAD_H_
-#define _rA_THREAD_H_
+#ifndef _COMMON_THREAD_H_
+#define _COMMON_THREAD_H_
#include "../common/cbasetypes.h"
@@ -116,4 +116,4 @@ void rathread_init();
void rathread_final();
-#endif
+#endif /* _COMMON_THREAD_H_ */
diff --git a/src/common/timer.c b/src/common/timer.c
index a2378a5aa..526854582 100644
--- a/src/common/timer.c
+++ b/src/common/timer.c
@@ -65,8 +65,7 @@ struct timer_func_list {
} *tfl_root = NULL;
/// Sets the name of a timer function.
-int timer_add_func_list(TimerFunc func, char* name)
-{
+int timer_add_func_list(TimerFunc func, char* name) {
struct timer_func_list* tfl;
if (name) {
@@ -139,22 +138,62 @@ static void rdtsc_calibrate(){
#endif
-/// platform-abstracted tick retrieval
-static unsigned int tick(void) {
+/**
+ * platform-abstracted tick retrieval
+ * @return server's current tick
+ */
+static int64 sys_tick(void) {
#if defined(WIN32)
- return GetTickCount();
+ // Windows: GetTickCount/GetTickCount64: Return the number of
+ // milliseconds that have elapsed since the system was started.
+
+ // TODO: GetTickCount/GetTickCount64 has a resolution of only 10~15ms.
+ // Ai4rei recommends that we replace it with either performance
+ // counters or multimedia timers if we want it to be more accurate.
+ // I'm leaving this for a future follow-up patch.
+
+ // GetTickCount64 is only available in Windows Vista / Windows Server
+ // 2008 or newer. Since we still support older versions, this runtime
+ // check is required in order not to crash.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724411%28v=vs.85%29.aspx
+ static bool first = true;
+ static ULONGLONG (WINAPI *pGetTickCount64)(void) = NULL;
+
+ if( first ) {
+ HMODULE hlib = GetModuleHandle(TEXT("KERNEL32.DLL"));
+ if( hlib != NULL )
+ pGetTickCount64 = (ULONGLONG (WINAPI *)(void))GetProcAddress(hlib, "GetTickCount64");
+ first = false;
+ }
+ if (pGetTickCount64)
+ return (int64)pGetTickCount64();
+ // 32-bit fallback. Note: This will wrap around every ~49 days since system startup!!!
+ return (int64)GetTickCount();
#elif defined(ENABLE_RDTSC)
- //
- return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK);
- //
+ // RDTSC: Returns the number of CPU cycles since reset. Unreliable if
+ // the CPU frequency is variable.
+ return (int64)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK);
#elif defined(HAVE_MONOTONIC_CLOCK)
+ // Monotinic clock: Implementation-defined.
+ // Clock that cannot be set and represents monotonic time since some
+ // unspecified starting point. This clock is not affected by
+ // discontin窶訊ous jumps in the system time (e.g., if the system
+ // administrator manually changes the clock), but is affected by
+ // the incremental adjustments performed by adjtime(3) and NTP.
struct timespec tval;
clock_gettime(CLOCK_MONOTONIC, &tval);
- return tval.tv_sec * 1000 + tval.tv_nsec / 1000000;
+ // int64 cast to avoid overflows on platforms where time_t is 32 bit
+ return (int64)tval.tv_sec * 1000 + tval.tv_nsec / 1000000;
#else
+ // Fallback, regular clock: Number of milliseconds since epoch.
+ // The time returned by gettimeofday() is affected by discontinuous
+ // jumps in the system time (e.g., if the system administrator
+ // manually changes the system time). If you need a monotonically
+ // increasing clock, see clock_gettime(2).
struct timeval tval;
gettimeofday(&tval, NULL);
- return tval.tv_sec * 1000 + tval.tv_usec / 1000;
+ // int64 cast to avoid overflows on platforms where time_t is 32 bit
+ return (int64)tval.tv_sec * 1000 + tval.tv_usec / 1000;
#endif
}
@@ -162,29 +201,29 @@ static unsigned int tick(void) {
#if defined(TICK_CACHE) && TICK_CACHE > 1
//////////////////////////////////////////////////////////////////////////
// tick is cached for TICK_CACHE calls
-static unsigned int gettick_cache;
+static int64 gettick_cache;
static int gettick_count = 1;
-unsigned int timer_gettick_nocache(void) {
+int64 timer_gettick_nocache(void) {
gettick_count = TICK_CACHE;
- gettick_cache = tick();
+ gettick_cache = sys_tick();
return gettick_cache;
}
-unsigned int timer_gettick(void) {
+int64 timer_gettick(void) {
return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache;
}
//////////////////////////////
#else
//////////////////////////////
// tick doesn't get cached
-unsigned int timer_gettick_nocache(void)
+int64 timer_gettick_nocache(void)
{
- return tick();
+ return sys_tick();
}
-unsigned int timer_gettick(void) {
- return tick();
+int64 timer_gettick(void) {
+ return sys_tick();
}
//////////////////////////////////////////////////////////////////////////
#endif
@@ -237,7 +276,7 @@ static int acquire_timer(void) {
/// Starts a new timer that is deleted once it expires (single-use).
/// Returns the timer's id.
-int timer_add(unsigned int tick, TimerFunc func, int id, intptr_t data) {
+int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) {
int tid;
tid = acquire_timer();
@@ -254,12 +293,11 @@ int timer_add(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 timer_add_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval)
-{
+int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval) {
int tid;
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, timer->gettick()));
+ ShowError("timer_add_interval: invalid interval (tick=%"PRId64" %p[%s] id=%d data=%d diff_tick=%"PRId64")\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, timer->gettick()));
return INVALID_TIMER;
}
@@ -301,13 +339,13 @@ int timer_do_delete(int tid, TimerFunc func) {
/// Adjusts a timer's expiration time.
/// Returns the new tick value, or -1 if it fails.
-int timer_addtick(int tid, unsigned int tick) {
+int64 timer_addtick(int tid, int64 tick) {
return timer->settick(tid, timer_data[tid].tick+tick);
}
/// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one).
/// Returns the new tick value, or -1 if it fails.
-int timer_settick(int tid, unsigned int tick) {
+int64 timer_settick(int tid, int64 tick) {
size_t i;
// search timer position
@@ -317,23 +355,23 @@ int timer_settick(int tid, unsigned int tick) {
return -1;
}
- if( (int)tick == -1 )
- tick = 0;// add 1ms to avoid the error value -1
+ if( tick == -1 )
+ tick = 0; // add 1ms to avoid the error value -1
if( timer_data[tid].tick == tick )
- return (int)tick;// nothing to do, already in propper position
+ return tick; // nothing to do, already in proper position
// pop and push adjusted timer
BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP, swap);
timer_data[tid].tick = tick;
BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP, swap);
- return (int)tick;
+ return tick;
}
/// Executes all expired timers.
/// Returns the value of the smallest non-expired timer (or 1 second if there aren't any).
-int do_timer(unsigned int tick) {
- int diff = TIMER_MAX_INTERVAL; // return value
+int do_timer(int64 tick) {
+ int64 diff = TIMER_MAX_INTERVAL; // return value
// process all timers one by one
while( BHEAP_LENGTH(timer_heap) ) {
@@ -381,7 +419,7 @@ int do_timer(unsigned int tick) {
}
}
- return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL);
+ return (int)cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL);
}
unsigned long timer_get_uptime(void) {
@@ -430,7 +468,7 @@ void timer_defaults(void) {
timer->addtick = timer_addtick;
timer->settick = timer_settick;
timer->get_uptime = timer_get_uptime;
- timer->do_timer = do_timer;
+ timer->perform = do_timer;
timer->init = timer_init;
timer->final = timer_final;
}
diff --git a/src/common/timer.h b/src/common/timer.h
index 600f9fd02..ab3ffc21f 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -1,13 +1,16 @@
// 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_
+
+#ifndef _COMMON_TIMER_H_
+#define _COMMON_TIMER_H_
+
#include "../common/cbasetypes.h"
-#define DIFF_TICK(a,b) ((int)((a)-(b)))
+#define DIFF_TICK(a,b) ((a)-(b))
+#define DIFF_TICK32(a,b) ((int32)((a)-(b)))
-#define INVALID_TIMER -1
+#define INVALID_TIMER (-1)
// timer flags
enum {
@@ -18,10 +21,10 @@ enum {
// Struct declaration
-typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data);
+typedef int (*TimerFunc)(int tid, int64 tick, int id, intptr_t data);
struct TimerData {
- unsigned int tick;
+ int64 tick;
TimerFunc func;
unsigned char type;
int interval;
@@ -40,22 +43,22 @@ struct TimerData {
struct timer_interface {
/* funcs */
- unsigned int (*gettick) (void);
- unsigned int (*gettick_nocache) (void);
+ int64 (*gettick) (void);
+ int64 (*gettick_nocache) (void);
- int (*add) (unsigned int tick, TimerFunc func, int id, intptr_t data);
- int (*add_interval) (unsigned int tick, TimerFunc func, int id, intptr_t data, int interval);
+ int (*add) (int64 tick, TimerFunc func, int id, intptr_t data);
+ int (*add_interval) (int64 tick, TimerFunc func, int id, intptr_t data, int interval);
const struct TimerData *(*get) (int tid);
int (*delete) (int tid, TimerFunc func);
- int (*addtick) (int tid, unsigned int tick);
- int (*settick) (int tid, unsigned int tick);
+ int64 (*addtick) (int tid, int64 tick);
+ int64 (*settick) (int tid, int64 tick);
int (*add_func_list) (TimerFunc func, char* name);
unsigned long (*get_uptime) (void);
- int (*do_timer) (unsigned int tick);
+ int (*perform) (int64 tick);
void (*init) (void);
void (*final) (void);
};
@@ -64,4 +67,4 @@ struct timer_interface *timer;
void timer_defaults(void);
-#endif /* _TIMER_H_ */
+#endif /* _COMMON_TIMER_H_ */
diff --git a/src/common/utils.c b/src/common/utils.c
index 9e3dbac47..9a7d4971b 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -287,6 +287,17 @@ unsigned int get_percentage(const unsigned int A, const unsigned int B)
return (unsigned int)floor(result);
}
+//-----------------------------------------------------
+// custom timestamp formatting (from eApp)
+//-----------------------------------------------------
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
+{
+ size_t len = strftime(str, size, format, localtime(&timestamp));
+ memset(str + len, '\0', size - len);
+ return str;
+}
+
+
/* [Ind/Hercules] Caching */
bool HCache_check(const char *file) {
struct stat bufa, bufb;
diff --git a/src/common/utils.h b/src/common/utils.h
index 32087d78f..68dd01ac4 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -2,8 +2,8 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
-#ifndef _UTILS_H_
-#define _UTILS_H_
+#ifndef _COMMON_UTILS_H_
+#define _COMMON_UTILS_H_
#include "../common/cbasetypes.h"
#include <stdio.h> // FILE*
@@ -20,11 +20,13 @@ void findfile(const char *p, const char *pat, void (func)(const char*));
bool exists(const char* filename);
//Caps values to min/max
-#define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a)
+#define cap_value(a, min, max) (((a) >= (max)) ? (max) : ((a) <= (min)) ? (min) : (a))
/// calculates the value of A / B, in percent (rounded down)
unsigned int get_percentage(const unsigned int A, const unsigned int B);
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format);
+
//////////////////////////////////////////////////////////////////////////
// byte word dword access [Shinomori]
//////////////////////////////////////////////////////////////////////////
@@ -52,4 +54,4 @@ struct HCache_interface *HCache;
void HCache_defaults(void);
-#endif /* _UTILS_H_ */
+#endif /* _COMMON_UTILS_H_ */