diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/HPM.c | 104 | ||||
-rw-r--r-- | src/common/HPM.h | 20 | ||||
-rw-r--r-- | src/common/HPMi.h | 4 | ||||
-rw-r--r-- | src/common/core.c | 207 | ||||
-rw-r--r-- | src/common/core.h | 44 | ||||
-rw-r--r-- | src/common/malloc.c | 36 | ||||
-rw-r--r-- | src/common/malloc.h | 7 |
7 files changed, 331 insertions, 91 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c index 6d9a2cb6b..10208cdad 100644 --- a/src/common/HPM.c +++ b/src/common/HPM.c @@ -293,7 +293,20 @@ void hplugin_unload(struct hplugin* plugin) { } } -void hplugins_config_read(const char * const *extra_plugins, int extra_plugins_count) { +/** + * Adds a plugin requested from the command line to the auto-load list. + */ +CMDLINEARG(loadplugin) +{ + RECREATE(HPM->cmdline_plugins, char *, ++HPM->cmdline_plugins_count); + HPM->cmdline_plugins[HPM->cmdline_plugins_count-1] = aStrdup(params); + return true; +} + +/** + * Reads the plugin configuration and loads the plugins as necessary. + */ +void hplugins_config_read(void) { config_t plugins_conf; config_setting_t *plist = NULL; const char *config_filename = "conf/plugins.conf"; // FIXME hardcoded name @@ -313,9 +326,9 @@ void hplugins_config_read(const char * const *extra_plugins, int extra_plugins_c HPM->symbol_defaults_sub(); plist = libconfig->lookup(&plugins_conf, "plugins_list"); - for (i = 0; i < extra_plugins_count; i++) { + for (i = 0; i < HPM->cmdline_plugins_count; i++) { config_setting_t *entry = libconfig->setting_add(plist, NULL, CONFIG_TYPE_STRING); - config_setting_set_string(entry, extra_plugins[i]); + config_setting_set_string(entry, HPM->cmdline_plugins[i]); } if (plist != NULL) { @@ -562,6 +575,9 @@ unsigned char hplugins_parse_packets(int fd, enum HPluginPacketHookingPoints poi char *hplugins_id2name (unsigned int pid) { unsigned int i; + if (pid == HPM_PID_CORE) + return "core"; + for( i = 0; i < HPM->plugin_count; i++ ) { if( HPM->plugins[i]->idx == pid ) return HPM->plugins[i]->info->name; @@ -624,50 +640,32 @@ 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; +/** + * Adds a plugin-defined command-line argument. + * + * @param pluginID the current plugin's ID. + * @param name the command line argument's name, including the leading '--'. + * @param has_param whether the command line argument expects to be followed by a value. + * @param func the triggered function. + * @param help the help string to be displayed by '--help', if any. + * @return the success status. + */ +bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecFunc func, const char *help) { + int i; - if( strdb_exists(HPM->arg_db, name) ) { - ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID)); + if (!name || strlen(name) < 3 || name[0] != '-' || name[1] != '-') { + ShowError("HPM:add_arg:%s invalid argument name: arguments must begin with '--' (from %s)\n", name, HPM->pid2name(pluginID)); return false; } - CREATE(data, struct HPMArgData, 1); + ARR_FIND(0, cmdline->args_data_count, i, strcmp(cmdline->args_data[i].name, name) == 0); - data->pluginID = pluginID; - data->name = aStrdup(name); - data->func = func; - data->help = help; - data->has_param = has_param; + if (i < cmdline->args_data_count) { + ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID)); + return false; + } - strdb_put(HPM->arg_db, data->name, data); - - return true; + return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL); } bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *name, void (*func) (const char *val)) { struct HPConfListenStorage *conf; @@ -833,8 +831,6 @@ void hpm_init(void) { HPM->packetsc[i] = 0; } - HPM->arg_db = strdb_alloc(DB_OPT_RELEASE_DATA, 0); - HPM->symbol_defaults(); #ifdef CONSOLE_INPUT @@ -855,13 +851,6 @@ void hpm_memdown(void) { 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; @@ -892,8 +881,13 @@ void hpm_final(void) { if( HPM->confsc[i] ) aFree(HPM->confs[i]); } - - HPM->arg_db->destroy(HPM->arg_db,HPM->arg_db_clear_sub); + if (HPM->cmdline_plugins) { + for (i = 0; i < HPM->cmdline_plugins_count; i++) + aFree(HPM->cmdline_plugins[i]); + aFree(HPM->cmdline_plugins); + HPM->cmdline_plugins = NULL; + HPM->cmdline_plugins_count = 0; + } /* HPM->fnames is cleared after the memory manager goes down */ iMalloc->post_shutdown = hpm_memdown; @@ -919,7 +913,8 @@ void hpm_defaults(void) { HPM->confs[i] = NULL; HPM->confsc[i] = 0; } - HPM->arg_db = NULL; + HPM->cmdline_plugins = NULL; + HPM->cmdline_plugins_count = 0; /* */ HPM->init = hpm_init; HPM->final = hpm_final; @@ -940,9 +935,6 @@ 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; diff --git a/src/common/HPM.h b/src/common/HPM.h index 973bc6cca..e99b0f2ae 100644 --- a/src/common/HPM.h +++ b/src/common/HPM.h @@ -82,14 +82,6 @@ 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; @@ -123,8 +115,9 @@ struct HPM_interface { /* config listen */ struct HPConfListenStorage *confs[HPCT_MAX]; unsigned int confsc[HPCT_MAX]; - /* --command-line */ - DBMap *arg_db; + /** Plugins requested through the command line */ + char **cmdline_plugins; + int cmdline_plugins_count; /* funcs */ void (*init) (void); void (*final) (void); @@ -137,16 +130,13 @@ struct HPM_interface { void *(*import_symbol) (char *name, unsigned int pID); void (*share) (void *, char *); void (*symbol_defaults) (void); - void (*config_read) (const char * const *extra_plugins, int extra_plugins_count); + void (*config_read) (void); bool (*populate) (struct hplugin *plugin,const char *filename); void (*symbol_defaults_sub) (void);//TODO drop char *(*pid2name) (unsigned int pid); unsigned char (*parse_packets) (int fd, enum HPluginPacketHookingPoints point); void (*load_sub) (struct hplugin *plugin); bool (*addhook_sub) (enum HPluginHookType type, const char *target, void *hook, unsigned int pID); - 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); @@ -158,6 +148,8 @@ struct HPM_interface { void (*datacheck_final) (void); }; +CMDLINEARG(loadplugin); + struct HPM_interface *HPM; void hpm_defaults(void); diff --git a/src/common/HPMi.h b/src/common/HPMi.h index 47f4e6b8b..d4b2e323c 100644 --- a/src/common/HPMi.h +++ b/src/common/HPMi.h @@ -104,7 +104,7 @@ enum HPluginConfType { #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))) +#define addArg(name, param,func,help) (HPMi->addArg(HPMi->pid,(name),(param),(cmdline_arg_ ## func),(help))) /* HPData handy redirects */ /* session[] */ #define addToSession(ptr,data,index,autofree) (HPMi->addToHPData(HPDT_SESSION,HPMi->pid,(ptr),(data),(index),(autofree))) @@ -214,7 +214,7 @@ HPExport struct HPMi_interface { 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)); + bool (*addArg) (unsigned int pluginID, char *name, bool has_param, CmdlineExecFunc func, const char *help); /* battle-config recv param */ bool (*addConf) (unsigned int pluginID, enum HPluginConfType type, char *name, void (*func) (const char *val)); /* pc group permission */ diff --git a/src/common/core.c b/src/common/core.c index e1bb9ed0b..6ad971c86 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -178,6 +178,7 @@ void core_defaults(void) { console_defaults(); strlib_defaults(); malloc_defaults(); + cmdline_defaults(); #ifndef MINICORE libconfig_defaults(); sql_defaults(); @@ -186,6 +187,196 @@ void core_defaults(void) { socket_defaults(); #endif } +/** + * Returns the source (core or plugin name) for the given command-line argument + */ +const char *cmdline_arg_source(struct CmdlineArgData *arg) { +#ifdef MINICORE + return "core"; +#else // !MINICORE + return HPM->pid2name(arg->pluginID); +#endif // MINICORE +} +/** + * Defines a command line argument. + * + * @param pluginID the source plugin ID (use HPM_PID_CORE if loading from the core). + * @param name the command line argument name, including the leading '--'. + * @param shortname an optional short form (single-character, it will be prefixed with '-'). Use '\0' to skip. + * @param func the triggered function. + * @param help the help string to be displayed by '--help', if any. + * @param options options associated to the command-line argument. @see enum cmdline_options. + * @return the success status. + */ +bool cmdline_arg_add(unsigned int pluginID, const char *name, char shortname, CmdlineExecFunc func, const char *help, unsigned int options) { + struct CmdlineArgData *data = NULL; + + RECREATE(cmdline->args_data, struct CmdlineArgData, ++cmdline->args_data_count); + data = &cmdline->args_data[cmdline->args_data_count-1]; + data->pluginID = pluginID; + data->name = aStrdup(name); + data->shortname = shortname; + data->func = func; + data->help = aStrdup(help); + data->options = options; + + return true; +} +/** + * Help screen to be displayed by '--help'. + */ +static CMDLINEARG(help) +{ + int i; + ShowInfo("Usage: %s [options]\n", SERVER_NAME); + ShowInfo("\n"); + ShowInfo("Options:\n"); + + for (i = 0; i < cmdline->args_data_count; i++) { + struct CmdlineArgData *data = &cmdline->args_data[i]; + char altname[16], paramnames[256]; + if (data->shortname) { + snprintf(altname, sizeof(altname), " [-%c]", data->shortname); + } else { + *altname = '\0'; + } + snprintf(paramnames, sizeof(paramnames), "%s%s%s", data->name, altname, data->options&CMDLINE_OPT_PARAM ? " <name>" : ""); + ShowInfo(" %-30s %s [%s]\n", paramnames, data->help ? data->help : "<no description provided>", cmdline->arg_source(data)); + } + return false; +} +/** + * Info screen to be displayed by '--version'. + */ +static CMDLINEARG(version) +{ + ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://hercules.ws/\n"); + ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#Hercules\n"); + ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n"); + return false; +} +/** + * Checks if there is a value available for the current argument + * + * @param name the current argument's name. + * @param current_arg the current argument's position. + * @param argc the program's argc. + * @return true if a value for the current argument is available on the command line. + */ +bool cmdline_arg_next_value(const char *name, int current_arg, int argc) +{ + if (current_arg >= argc-1) { + ShowError("Missing value for option '%s'.\n", name); + return false; + } + + return true; +} +/** + * Executes the command line arguments handlers. + * + * @param argc the program's argc + * @param argv the program's argv + * @param options Execution options. Allowed values: + * - CMDLINE_OPT_SILENT: Scans the argv for a command line argument that + * requires the server's silent mode, and triggers it. Invalid command line + * arguments don't cause it to abort. No command handlers are executed. + * - CMDLINE_OPT_PREINIT: Scans the argv for command line arguments with the + * CMDLINE_OPT_PREINIT flag set and executes their handlers. Invalid command + * line arguments don't cause it to abort. Handler's failure causes the + * program to abort. + * - CMDLINE_OPT_NORMAL: Scans the argv for normal command line arguments, + * skipping the pre-init ones, and executes their handlers. Invalid command + * line arguments or handler's failure cause the program to abort. + * @return the amount of command line handlers successfully executed. + */ +int cmdline_exec(int argc, char **argv, unsigned int options) +{ + int count = 0, i, j; + for (i = 1; i < argc; i++) { + struct CmdlineArgData *data = NULL; + const char *arg = argv[i]; + if (arg[0] != '-') { // All arguments must begin with '-' + ShowError("Invalid option '%s'.\n", argv[i]); + exit(EXIT_FAILURE); + } + if (arg[1] != '-' && strlen(arg) == 2) { + ARR_FIND(0, cmdline->args_data_count, j, cmdline->args_data[j].shortname == arg[1]); + } else { + ARR_FIND(0, cmdline->args_data_count, j, strcmpi(cmdline->args_data[j].name, arg) == 0); + } + if (j == cmdline->args_data_count) { + if (options&(CMDLINE_OPT_SILENT|CMDLINE_OPT_PREINIT)) + continue; + ShowError("Unknown option '%s'.\n", arg); + exit(EXIT_FAILURE); + } + data = &cmdline->args_data[j]; + if (data->options&CMDLINE_OPT_PARAM) { + if (!cmdline->arg_next_value(arg, i, argc)) + exit(EXIT_FAILURE); + i++; + } + if (options&CMDLINE_OPT_SILENT) { + if (data->options&CMDLINE_OPT_SILENT) { + msg_silent = 0x7; // silence information and status messages + break; + } + } else if ((data->options&CMDLINE_OPT_PREINIT) == (options&CMDLINE_OPT_PREINIT)) { + const char *param = NULL; + if (data->options&CMDLINE_OPT_PARAM) { + param = argv[i]; // Already incremented above + } + if (!data->func(arg, param)) + exit(EXIT_SUCCESS); + count++; + } + } + return count; +} +/** + * Defines the global command-line arguments. + */ +void cmdline_init(void) +{ +#ifdef MINICORE + // Minicore has no HPM. This value isn't used, but the arg_add function requires it, so we're (re)defining it here +#define HPM_PID_CORE ((unsigned int)-1) +#endif + CMDLINEARG_DEF(help, 'h', "Displays this help screen", CMDLINE_OPT_NORMAL); + CMDLINEARG_DEF(version, 'v', "Displays the server's version.", CMDLINE_OPT_NORMAL); +#ifndef MINICORE + CMDLINEARG_DEF2(load-plugin, loadplugin, "Loads an additional plugin (can be repeated).", CMDLINE_OPT_PARAM|CMDLINE_OPT_PREINIT); +#endif // !MINICORE + cmdline_args_init_local(); +} +void cmdline_final(void) +{ + int i; + for (i = 0; i < cmdline->args_data_count; i++) { + aFree(cmdline->args_data[i].name); + aFree(cmdline->args_data[i].help); + } + if (cmdline->args_data) + aFree(cmdline->args_data); +} + +struct cmdline_interface cmdline_s; + +void cmdline_defaults(void) +{ + cmdline = &cmdline_s; + + cmdline->args_data = NULL; + cmdline->args_data_count = 0; + + cmdline->init = cmdline_init; + cmdline->final = cmdline_final; + cmdline->arg_add = cmdline_arg_add; + cmdline->exec = cmdline_exec; + cmdline->arg_next_value = cmdline_arg_next_value; + cmdline->arg_source = cmdline_arg_source; +} /*====================================== * CORE : MAINROUTINE *--------------------------------------*/ @@ -203,17 +394,14 @@ int main (int argc, char **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] + cmdline->init(); + + cmdline->exec(argc, argv, CMDLINE_OPT_SILENT); + + iMalloc->init_messages(); // Initialization messages (after buying us some time to suppress them if needed) + sysinfo->init(); if (!(msg_silent&0x1)) @@ -269,6 +457,7 @@ int main (int argc, char **argv) { rathread_final(); ers_final(); #endif + cmdline->final(); //sysinfo->final(); Called by iMalloc->final() iMalloc->final(); diff --git a/src/common/core.h b/src/common/core.h index 025f636e9..827d345ba 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -5,6 +5,7 @@ #ifndef COMMON_CORE_H #define COMMON_CORE_H +#include "../common/cbasetypes.h" #include "../common/db.h" #include "../common/mmo.h" @@ -39,6 +40,7 @@ extern char *SERVER_NAME; enum server_types SERVER_TYPE; +extern void cmdline_args_init_local(void); extern int do_init(int,char**); extern void set_server_type(void); extern void do_abort(void); @@ -49,4 +51,46 @@ extern int do_final(void); extern void (*shutdown_callback)(void); #endif // HERCULES_CORE +/// Options for command line argument handlers. +enum cmdline_options { + CMDLINE_OPT_NORMAL = 0x0, ///< No special options. + CMDLINE_OPT_PARAM = 0x1, ///< An additional value parameter is expected. + CMDLINE_OPT_SILENT = 0x2, ///< If this command-line argument is passed, the server won't print any messages. + CMDLINE_OPT_PREINIT = 0x4, ///< This command-line argument is executed before initializing the HPM. +}; +typedef bool (*CmdlineExecFunc)(const char *name, const char *params); +struct CmdlineArgData { + unsigned int pluginID; ///< Plugin ID (HPM_PID_CORE if used by the core) + unsigned int options; ///< Command line argument options (@see enum cmdline_options) + char *name; ///< Command-line argument (i.e. "--my-arg", "--version", "--whatever") + char shortname; ///< Short form (i.e. "-v") - only store the 'v' part. + CmdlineExecFunc func; ///< Function to call + char *help; ///< Help message +}; + +struct cmdline_interface { + struct CmdlineArgData *args_data; + int args_data_count; + + void (*init) (void); + void (*final) (void); + bool (*arg_add) (unsigned int pluginID, const char *name, char shortname, CmdlineExecFunc func, const char *help, unsigned int options); + int (*exec) (int argc, char **argv, unsigned int options); + bool (*arg_next_value) (const char *name, int current_arg, int argc); + const char *(*arg_source) (struct CmdlineArgData *arg); +}; + +struct cmdline_interface *cmdline; + +#define CMDLINEARG(x) bool cmdline_arg_ ## x (const char *name, const char *params) +#ifdef HERCULES_CORE +/// Special plugin ID assigned to the Hercules core +#define HPM_PID_CORE ((unsigned int)-1) + +#define CMDLINEARG_DEF(name, shortname, help, options) cmdline->arg_add(HPM_PID_CORE, "--" EXPAND_AND_QUOTE(name), shortname, cmdline_arg_ ## name, help, options) +#define CMDLINEARG_DEF2(name, funcname, help, options) cmdline->arg_add(HPM_PID_CORE, "--" EXPAND_AND_QUOTE(name), '\0', cmdline_arg_ ## funcname, help, options) + +void cmdline_defaults(void); +#endif // HERCULES_CORE + #endif /* COMMON_CORE_H */ diff --git a/src/common/malloc.c b/src/common/malloc.c index 244b1114c..43fbe4ea1 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -769,12 +769,24 @@ void memmgr_report (int extra) { } -static void memmgr_init (void) +/** + * Initializes the Memory Manager. + */ +static void memmgr_init(void) +{ +#ifdef LOG_MEMMGR + memset(hash_unfill, 0, sizeof(hash_unfill)); +#endif /* LOG_MEMMGR */ +} + +/** + * Prints initialization messages from the Memory Manager. + */ +static void memmgr_init_messages(void) { #ifdef LOG_MEMMGR sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); ShowStatus("Memory manager initialized: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); - memset(hash_unfill, 0, sizeof(hash_unfill)); #endif /* LOG_MEMMGR */ } #endif /* USE_MEMMGR */ @@ -821,7 +833,22 @@ void malloc_final (void) { iMalloc->post_shutdown(); } -void malloc_init (void) { +/** + * Prints initialization status messages. + * + * This is separated from malloc_init() in order to be run after giving the + * chance to other modules to initialize, in case they want to silence any + * status messages, but at the same time require malloc. + */ +void malloc_init_messages(void) +{ +#ifdef USE_MEMMGR + memmgr_init_messages(); +#endif +} + +void malloc_init(void) +{ #ifdef USE_MEMMGR memmgr_usage_bytes_t = 0; memmgr_usage_bytes = 0; @@ -836,7 +863,7 @@ void malloc_init (void) { GC_INIT(); #endif #ifdef USE_MEMMGR - memmgr_init (); + memmgr_init(); #endif } @@ -865,4 +892,5 @@ void malloc_defaults(void) { iMalloc->free = aFree_; #endif iMalloc->post_shutdown = NULL; + iMalloc->init_messages = malloc_init_messages; } diff --git a/src/common/malloc.h b/src/common/malloc.h index bc79ac65a..7ed2fb19c 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -59,12 +59,6 @@ //////////////////////////////////////////////// -//void malloc_memory_check(void); -//bool malloc_verify_ptr(void* ptr); -//size_t malloc_usage (void); -//void malloc_init (void); -//void malloc_final (void); - #ifdef HERCULES_CORE void malloc_defaults(void); @@ -87,6 +81,7 @@ struct malloc_interface { size_t (*usage) (void); /* */ void (*post_shutdown) (void); + void (*init_messages) (void); }; struct malloc_interface *iMalloc; |