summaryrefslogtreecommitdiff
path: root/src/common/core.c
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2014-11-09 02:07:09 +0100
committerHaru <haru@dotalux.com>2015-01-18 21:35:36 +0100
commitce08d6238d902590dbfb650f889a8ab8887356bf (patch)
tree218266957f961e71a51a307b432b02ed9647243a /src/common/core.c
parent0285ddf7cee2f6569a513fe6118c43f99fd71279 (diff)
downloadhercules-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.c207
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();