Commit 735a3712 authored by Max Kellermann's avatar Max Kellermann

util/OptionParser: pass array of OptionDefs to constructor

parent 5ab086e3
...@@ -76,24 +76,29 @@ ...@@ -76,24 +76,29 @@
#define USER_CONFIG_FILE_LOCATION_XDG PATH_LITERAL("mpd/mpd.conf") #define USER_CONFIG_FILE_LOCATION_XDG PATH_LITERAL("mpd/mpd.conf")
#endif #endif
static constexpr OptionDef opt_kill( enum Option {
"kill", "kill the currently running mpd session"); OPTION_KILL,
static constexpr OptionDef opt_no_config( OPTION_NO_CONFIG,
"no-config", "don't read from config"); OPTION_NO_DAEMON,
static constexpr OptionDef opt_no_daemon( OPTION_STDOUT,
"no-daemon", "don't detach from console"); OPTION_STDERR,
static constexpr OptionDef opt_stdout( OPTION_VERBOSE,
"stdout", nullptr); // hidden, compatibility with old versions OPTION_VERSION,
static constexpr OptionDef opt_stderr( OPTION_HELP,
"stderr", "print messages to stderr"); OPTION_HELP2,
static constexpr OptionDef opt_verbose( };
"verbose", 'v', "verbose logging");
static constexpr OptionDef opt_version( static constexpr OptionDef option_defs[] = {
"version", 'V', "print version number"); {"kill", "kill the currently running mpd session"},
static constexpr OptionDef opt_help( {"no-config", "don't read from config"},
"help", 'h', "show help options"); {"no-daemon", "don't detach from console"},
static constexpr OptionDef opt_help_alt( {"stdout", nullptr}, // hidden, compatibility with old versions
nullptr, '?', nullptr); // hidden, standard alias for --help {"stderr", "print messages to stderr"},
{"verbose", 'v', "verbose logging"},
{"version", 'V', "print version number"},
{"help", 'h', "show help options"},
{nullptr, '?', nullptr}, // hidden, standard alias for --help
};
static constexpr Domain cmdline_domain("cmdline"); static constexpr Domain cmdline_domain("cmdline");
...@@ -265,13 +270,8 @@ static void help(void) ...@@ -265,13 +270,8 @@ static void help(void)
"\n" "\n"
"Options:\n"); "Options:\n");
PrintOption(opt_help); for (const auto &i : option_defs)
PrintOption(opt_kill); PrintOption(i);
PrintOption(opt_no_config);
PrintOption(opt_no_daemon);
PrintOption(opt_stderr);
PrintOption(opt_verbose);
PrintOption(opt_version);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
...@@ -312,35 +312,38 @@ ParseCommandLine(int argc, char **argv, struct options *options) ...@@ -312,35 +312,38 @@ ParseCommandLine(int argc, char **argv, struct options *options)
options->verbose = false; options->verbose = false;
// First pass: handle command line options // First pass: handle command line options
OptionParser parser(argc, argv); OptionParser parser(option_defs, argc, argv);
while (parser.ParseNext()) { int option_index;
if (parser.CheckOption(opt_kill)) { while ((option_index = parser.Next()) >= 0) {
switch (Option(option_index)) {
case OPTION_KILL:
options->kill = true; options->kill = true;
continue; break;
}
if (parser.CheckOption(opt_no_config)) { case OPTION_NO_CONFIG:
use_config_file = false; use_config_file = false;
continue; break;
}
if (parser.CheckOption(opt_no_daemon)) { case OPTION_NO_DAEMON:
options->daemon = false; options->daemon = false;
continue; break;
}
if (parser.CheckOption(opt_stderr, opt_stdout)) { case OPTION_STDOUT:
case OPTION_STDERR:
options->log_stderr = true; options->log_stderr = true;
continue; break;
}
if (parser.CheckOption(opt_verbose)) { case OPTION_VERBOSE:
options->verbose = true; options->verbose = true;
continue; break;
}
if (parser.CheckOption(opt_version)) case OPTION_VERSION:
version(); version();
if (parser.CheckOption(opt_help, opt_help_alt))
help();
throw FormatRuntimeError("invalid option: %s", case OPTION_HELP:
parser.GetOption()); case OPTION_HELP2:
help();
}
} }
/* initialize the logging library, so the configuration file /* initialize the logging library, so the configuration file
......
/* /*
* Copyright 2003-2017 The Music Player Daemon Project * Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org * http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -19,43 +19,41 @@ ...@@ -19,43 +19,41 @@
#include "OptionParser.hxx" #include "OptionParser.hxx"
#include "OptionDef.hxx" #include "OptionDef.hxx"
#include "util/RuntimeError.hxx"
#include <string.h> #include <string.h>
bool inline unsigned
OptionParser::CheckOption(const OptionDef &opt) const noexcept OptionParser::IdentifyOption(const char *s) const
{ {
assert(option != nullptr); assert(s != nullptr);
assert(*s == '-');
if (is_long)
return opt.HasLongOption() && if (s[1] == '-') {
strcmp(option, opt.GetLongOption()) == 0; for (const auto &i : options)
if (i.HasLongOption() &&
strcmp(s + 2, i.GetLongOption()) == 0)
return &i - options.data;
} else if (s[1] != 0 && s[2] == 0) {
const char ch = s[1];
for (const auto &i : options)
if (i.HasShortOption() && ch == i.GetShortOption())
return &i - options.data;
}
return opt.HasShortOption() && throw FormatRuntimeError("Unknown option: %s", s);
option[0] == opt.GetShortOption() &&
option[1] == '\0';
} }
bool int
OptionParser::ParseNext() noexcept OptionParser::Next()
{ {
while (!args.empty()) { while (!args.empty()) {
const char *arg = args.shift(); const char *arg = args.shift();
if (arg[0] == '-') { if (arg[0] == '-')
if (arg[1] == '-') { return IdentifyOption(arg);
option = arg + 2;
is_long = true;
}
else {
option = arg + 1;
is_long = false;
}
option_raw = arg;
return true;
}
*remaining_tail++ = arg; *remaining_tail++ = arg;
} }
return false; return -1;
} }
/* /*
* Copyright 2003-2017 The Music Player Daemon Project * Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org * http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -29,10 +29,9 @@ class OptionDef; ...@@ -29,10 +29,9 @@ class OptionDef;
*/ */
class OptionParser class OptionParser
{ {
ConstBuffer<OptionDef> options;
ConstBuffer<const char *> args; ConstBuffer<const char *> args;
const char *option;
const char *option_raw;
bool is_long = false;
const char **const remaining_head, **remaining_tail; const char **const remaining_head, **remaining_tail;
...@@ -40,41 +39,23 @@ public: ...@@ -40,41 +39,23 @@ public:
/** /**
* Constructs #OptionParser. * Constructs #OptionParser.
*/ */
OptionParser(int _argc, char **_argv) noexcept OptionParser(ConstBuffer<OptionDef> _options,
:args(_argv + 1, _argc - 1), int _argc, char **_argv) noexcept
:options(_options), args(_argv + 1, _argc - 1),
remaining_head(const_cast<const char **>(_argv + 1)), remaining_head(const_cast<const char **>(_argv + 1)),
remaining_tail(remaining_head) {} remaining_tail(remaining_head) {}
/** /**
* Gets the last parsed option.
*/
const char *GetOption() noexcept {
return option_raw;
}
/**
* Checks if current option is a specified option.
*/
bool CheckOption(const OptionDef &opt) const noexcept;
/**
* Checks if current option is a specified option
* or specified alternative option.
*/
bool CheckOption(const OptionDef &opt,
const OptionDef &alt_opt) const noexcept {
return CheckOption(opt) || CheckOption(alt_opt);
}
/**
* Parses current command line entry. * Parses current command line entry.
* Regardless of result, advances current position to the next * Regardless of result, advances current position to the next
* command line entry. * command line entry.
* *
* @return true if an option was found, false if there are no * Throws on error.
* more options *
* @return the index if an option was found, -1 if there are
* no more options
*/ */
bool ParseNext() noexcept; int Next();
/** /**
* Returns the remaining non-option arguments. * Returns the remaining non-option arguments.
...@@ -82,6 +63,9 @@ public: ...@@ -82,6 +63,9 @@ public:
ConstBuffer<const char *> GetRemaining() const noexcept { ConstBuffer<const char *> GetRemaining() const noexcept {
return {remaining_head, remaining_tail}; return {remaining_head, remaining_tail};
} }
private:
unsigned IdentifyOption(const char *s) const;
}; };
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment