diff options
author | Haru <haru@dotalux.com> | 2014-11-09 02:07:09 +0100 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2015-01-18 21:35:36 +0100 |
commit | ce08d6238d902590dbfb650f889a8ab8887356bf (patch) | |
tree | 218266957f961e71a51a307b432b02ed9647243a /src/common/core.c | |
parent | 0285ddf7cee2f6569a513fe6118c43f99fd71279 (diff) | |
download | hercules-ce08d6238d902590dbfb650f889a8ab8887356bf.tar.gz hercules-ce08d6238d902590dbfb650f889a8ab8887356bf.tar.bz2 hercules-ce08d6238d902590dbfb650f889a8ab8887356bf.tar.xz hercules-ce08d6238d902590dbfb650f889a8ab8887356bf.zip |
Command line arguments handling overhaul
- login_server, char_server, map_server as well as the tools (mapcache)
now have a common command line arguments handling mechanism.
- All of them now accept `--help` (`-h`), `--version` (`-v`) and
`--load-plugin`.
- login_server now accepts `--login-config` and `--lan-config` instead
of relying on positional arguments to override those files. The old
syntax will no longer work, please update your custom startup scripts.
- char_server now accepts `--char-config`, `--inter-config`,
`--lan-config` instead of relying on positional arguments. The old
syntax will no longer work, please update your custom startup scripts.
- mapcache now accepts `--grf-list`, `--map-list`, `--map-cache`,
`--rebuild` in place of, respectively, `-grf`, `-list`, `-cache`,
`-rebuild`.
- A new macro `CMDLINEARG()` is provided, to help defining new command
line argument handlers (i.e. in plugins). the `addArg()` call is still
required, but its syntax has changed. The `help` argument is now of type
`const char *` rather than a function pointer, and it is supposed to
contain the message to show in the `--help` screen. Pass `NULL` if no
help message is desired.
Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/common/core.c')
-rw-r--r-- | src/common/core.c | 207 |
1 files changed, 198 insertions, 9 deletions
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(); |