diff options
Diffstat (limited to 'src/lib/util/options.h')
-rw-r--r-- | src/lib/util/options.h | 298 |
1 files changed, 181 insertions, 117 deletions
diff --git a/src/lib/util/options.h b/src/lib/util/options.h index 71431ce870c..533f5cf4628 100644 --- a/src/lib/util/options.h +++ b/src/lib/util/options.h @@ -13,26 +13,13 @@ #include "corefile.h" #include <unordered_map> - +#include <sstream> //************************************************************************** // CONSTANTS //************************************************************************** -// option types -const uint32_t OPTION_TYPE_MASK = 0x0007; // up to 8 different types -enum -{ - OPTION_INVALID, // invalid - OPTION_HEADER, // a header item - OPTION_COMMAND, // a command - OPTION_BOOLEAN, // boolean option - OPTION_INTEGER, // integer option - OPTION_FLOAT, // floating-point option - OPTION_STRING // string option -}; - // option priorities const int OPTION_PRIORITY_DEFAULT = 0; // defaults are at 0 priority const int OPTION_PRIORITY_LOW = 50; // low priority @@ -40,20 +27,55 @@ const int OPTION_PRIORITY_NORMAL = 100; // normal priority const int OPTION_PRIORITY_HIGH = 150; // high priority const int OPTION_PRIORITY_MAXIMUM = 255; // maximum priority -const uint32_t OPTION_FLAG_INTERNAL = 0x40000000; - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// static structure describing a single option with its description and default value -struct options_entry +struct options_entry; + +// exception thrown by core_options when an illegal request is made +class options_exception : public std::exception { - const char * name; // name on the command line - const char * defvalue; // default value of this argument - uint32_t flags; // flags to describe the option - const char * description; // description for -showusage +public: + const std::string &message() const { return m_message; } + virtual const char *what() const noexcept override { return message().c_str(); } + +protected: + options_exception(std::string &&message); + +private: + std::string m_message; +}; + +class options_warning_exception : public options_exception +{ +public: + template <typename... Params> options_warning_exception(const char *fmt, Params &&...args) + : options_warning_exception(util::string_format(fmt, std::forward<Params>(args)...)) + { + } + + options_warning_exception(std::string &&message); + options_warning_exception(const options_warning_exception &) = default; + options_warning_exception(options_warning_exception &&) = default; + options_warning_exception& operator=(const options_warning_exception &) = default; + options_warning_exception& operator=(options_warning_exception &&) = default; +}; + +class options_error_exception : public options_exception +{ +public: + template <typename... Params> options_error_exception(const char *fmt, Params &&...args) + : options_error_exception(util::string_format(fmt, std::forward<Params>(args)...)) + { + } + + options_error_exception(std::string &&message); + options_error_exception(const options_error_exception &) = default; + options_error_exception(options_error_exception &&) = default; + options_error_exception& operator=(const options_error_exception &) = default; + options_error_exception& operator=(options_error_exception &&) = default; }; @@ -63,95 +85,97 @@ class core_options static const int MAX_UNADORNED_OPTIONS = 16; public: + enum class option_type + { + INVALID, // invalid + HEADER, // a header item + COMMAND, // a command + BOOLEAN, // boolean option + INTEGER, // integer option + FLOAT, // floating-point option + STRING // string option + }; + // information about a single entry in the options class entry { - friend class core_options; - friend class simple_list<entry>; - - // construction/destruction - entry(const char *name, const char *description, uint32_t flags = 0, const char *defvalue = nullptr); - public: - // getters - entry *next() const { return m_next; } - const char *name(int index = 0) const { return (index < ARRAY_LENGTH(m_name) && !m_name[index].empty()) ? m_name[index].c_str() : nullptr; } + typedef std::shared_ptr<entry> shared_ptr; + typedef std::weak_ptr<entry> weak_ptr; + + // constructor/destructor + entry(std::vector<std::string> &&names, option_type type = option_type::STRING, const char *description = nullptr); + entry(std::string &&name, option_type type = option_type::STRING, const char *description = nullptr); + entry(const entry &) = delete; + entry(entry &&) = delete; + entry& operator=(const entry &) = delete; + entry& operator=(entry &&) = delete; + virtual ~entry(); + + // accessors + const std::vector<std::string> &names() const { return m_names; } + const std::string &name() const { return m_names[0]; } + virtual const char *value() const; + int priority() const { return m_priority; } + void set_priority(int priority) { m_priority = priority; } + option_type type() const { return m_type; } const char *description() const { return m_description; } - const char *value() const { return m_data.c_str(); } - const char *default_value() const { return m_defdata.c_str(); } - const char *minimum() const { return m_minimum.c_str(); } - const char *maximum() const { return m_maximum.c_str(); } - int type() const { return (m_flags & OPTION_TYPE_MASK); } - uint32_t flags() const { return m_flags; } - bool is_header() const { return type() == OPTION_HEADER; } - bool is_command() const { return type() == OPTION_COMMAND; } - bool is_internal() const { return m_flags & OPTION_FLAG_INTERNAL; } - bool has_range() const { return (!m_minimum.empty() && !m_maximum.empty()); } - int priority() const { return m_priority; } - bool is_changed() const { return m_changed; } - - // setters - void set_value(const char *newvalue, int priority); - void set_default_value(const char *defvalue); - void set_description(const char *description); - void set_flag(uint32_t mask, uint32_t flag); - void mark_changed() { m_changed = true; } - void revert(int priority_hi, int priority_lo); + virtual const std::string &default_value() const; + virtual const char *minimum() const; + virtual const char *maximum() const; + bool has_range() const; + + // mutators + void set_value(std::string &&newvalue, int priority, bool always_override = false); + virtual void set_default_value(std::string &&newvalue); + void set_description(const char *description) { m_description = description; } + void set_value_changed_handler(std::function<void(const char *)> &&handler) { m_value_changed_handler = std::move(handler); } + + protected: + virtual void internal_set_value(std::string &&newvalue) = 0; private: - // internal state - entry * m_next; // link to the next data - uint32_t m_flags; // flags from the entry - bool m_error_reported; // have we reported an error on this option yet? - int m_priority; // priority of the data set - const char * m_description; // description for this item - std::string m_name[4]; // up to 4 names for the item - std::string m_data; // data for this item - std::string m_defdata; // default data for this item - std::string m_minimum; // minimum value - std::string m_maximum; // maximum value - bool m_changed; // changed flag + void validate(const std::string &value); + + std::vector<std::string> m_names; + int m_priority; + core_options::option_type m_type; + const char * m_description; + std::function<void(const char *)> m_value_changed_handler; }; // construction/destruction core_options(); - core_options(const options_entry *entrylist); - core_options(const options_entry *entrylist1, const options_entry *entrylist2); - core_options(const options_entry *entrylist1, const options_entry *entrylist2, const options_entry *entrylist3); - core_options(const core_options &src); + core_options(const core_options &) = delete; + core_options(core_options &&) = delete; + core_options& operator=(const core_options &) = delete; + core_options& operator=(core_options &&) = delete; virtual ~core_options(); - // operators - core_options &operator=(const core_options &rhs); - bool operator==(const core_options &rhs); - bool operator!=(const core_options &rhs); - // getters - entry *first() const { return m_entrylist.first(); } const std::string &command() const { return m_command; } const std::vector<std::string> &command_arguments() const { assert(!m_command.empty()); return m_command_arguments; } - entry *get_entry(const char *name) const; - - // range iterators - using auto_iterator = simple_list<entry>::auto_iterator; - auto_iterator begin() const { return m_entrylist.begin(); } - auto_iterator end() const { return m_entrylist.end(); } + const entry::shared_ptr get_entry(const std::string &name) const; + entry::shared_ptr get_entry(const std::string &name); + const std::vector<entry::shared_ptr> &entries() const { return m_entries; } + bool exists(const std::string &name) const { return get_entry(name) != nullptr; } + bool header_exists(const char *description) const; // configuration - void add_entry(const char *name, const char *description, uint32_t flags = 0, const char *defvalue = nullptr, bool override_existing = false); - void add_entry(const options_entry &data, bool override_existing = false) { add_entry(data.name, data.description, data.flags, data.defvalue, override_existing); } + void add_entry(entry::shared_ptr &&entry, const char *after_header = nullptr); + void add_entry(const options_entry &entry, bool override_existing = false); + void add_entry(std::vector<std::string> &&names, const char *description, option_type type, std::string &&default_value = "", std::string &&minimum = "", std::string &&maximum = ""); + void add_header(const char *description); void add_entries(const options_entry *entrylist, bool override_existing = false); void set_default_value(const char *name, const char *defvalue); void set_description(const char *name, const char *description); void remove_entry(entry &delentry); + void set_value_changed_handler(const std::string &name, std::function<void(const char *)> &&handler); // parsing/input - bool parse_command_line(std::vector<std::string> &args, int priority, std::string &error_string); - bool parse_ini_file(util::core_file &inifile, int priority, bool ignore_unknown_options, std::string &error_string); - bool pluck_from_command_line(std::vector<std::string> &args, const std::string &name, std::string &result); - - // reverting - void revert(int priority_hi = OPTION_PRIORITY_MAXIMUM, int priority_lo = OPTION_PRIORITY_DEFAULT); + void parse_command_line(const std::vector<std::string> &args, int priority, bool ignore_unknown_options = false); + void parse_ini_file(util::core_file &inifile, int priority, bool ignore_unknown_options, bool always_override); + void copy_from(const core_options &that); // output std::string output_ini(const core_options *diff = nullptr) const; @@ -160,52 +184,92 @@ public: // reading const char *value(const char *option) const; const char *description(const char *option) const; - int priority(const char *option) const; - bool bool_value(const char *name) const { return (atoi(value(name)) != 0); } - int int_value(const char *name) const { return atoi(value(name)); } - float float_value(const char *name) const { return atof(value(name)); } - bool exists(const char *name) const; + bool bool_value(const char *option) const { return int_value(option) != 0; } + int int_value(const char *option) const { return atoi(value(option)); } + float float_value(const char *option) const { return atof(value(option)); } // setting - bool set_value(const char *name, const char *value, int priority, std::string &error_string); - bool set_value(const char *name, int value, int priority, std::string &error_string); - bool set_value(const char *name, float value, int priority, std::string &error_string); - void set_flag(const char *name, uint32_t mask, uint32_t flags); - void mark_changed(const char *name); + void set_value(const std::string &name, const std::string &value, int priority); + void set_value(const std::string &name, std::string &&value, int priority); + void set_value(const std::string &name, int value, int priority); + void set_value(const std::string &name, float value, int priority); // misc static const char *unadorned(int x = 0) { return s_option_unadorned[std::min(x, MAX_UNADORNED_OPTIONS - 1)]; } - int options_count() const { return m_entrylist.count(); } protected: - // This is a hook to allow option value retrieval to be overridden for various reasons; this is a crude - // extensibility mechanism that should really be replaced by something better - enum class override_get_value_result + virtual void command_argument_processed() { } + +private: + class simple_entry : public entry { - NONE, - OVERRIDE, - SKIP + public: + // construction/destruction + simple_entry(std::vector<std::string> &&names, const char *description, core_options::option_type type, std::string &&defdata, std::string &&minimum, std::string &&maximum); + simple_entry(const simple_entry &) = delete; + simple_entry(simple_entry &&) = delete; + simple_entry& operator=(const simple_entry &) = delete; + simple_entry& operator=(simple_entry &&) = delete; + ~simple_entry(); + + // getters + virtual const char *value() const override; + virtual const char *minimum() const override; + virtual const char *maximum() const override; + virtual const std::string &default_value() const override; + + virtual void set_default_value(std::string &&newvalue) override; + + protected: + virtual void internal_set_value(std::string &&newvalue) override; + + private: + // internal state + std::string m_data; // data for this item + std::string m_defdata; // default data for this item + std::string m_minimum; // minimum value + std::string m_maximum; // maximum value }; - virtual void value_changed(const std::string &name, const std::string &value) {} - virtual override_get_value_result override_get_value(const char *name, std::string &value) const { return override_get_value_result::NONE; } - virtual bool override_set_value(const char *name, const std::string &value) { return false; } + // used internally in core_options + enum class condition_type + { + NONE, + WARN, + ERR + }; -private: // internal helpers - void reset(); - void append_entry(entry &newentry); - void copyfrom(const core_options &src); - bool validate_and_set_data(entry &curentry, std::string &&newdata, int priority, std::string &error_string); + void add_to_entry_map(std::string &&name, entry::shared_ptr &entry); + void do_set_value(entry &curentry, std::string &&data, int priority, std::ostream &error_stream, condition_type &condition); + void throw_options_exception_if_appropriate(condition_type condition, std::ostringstream &error_stream); // internal state - simple_list<entry> m_entrylist; // head of list of entries - std::unordered_map<std::string,entry *> m_entrymap; // map for fast lookup - std::string m_command; // command found - std::vector<std::string> m_command_arguments; // command arguments - static const char *const s_option_unadorned[]; // array of unadorned option "names" + std::vector<entry::shared_ptr> m_entries; // cannonical list of entries + std::unordered_map<std::string, entry::weak_ptr> m_entrymap; // map for fast lookup + std::string m_command; // command found + std::vector<std::string> m_command_arguments; // command arguments + static const char *const s_option_unadorned[]; // array of unadorned option "names" +}; + + +// static structure describing a single option with its description and default value +struct options_entry +{ + const char * name; // name on the command line + const char * defvalue; // default value of this argument + core_options::option_type type; // type of option + const char * description; // description for -showusage }; +// legacy option types +const core_options::option_type OPTION_INVALID = core_options::option_type::INVALID; +const core_options::option_type OPTION_HEADER = core_options::option_type::HEADER; +const core_options::option_type OPTION_COMMAND = core_options::option_type::COMMAND; +const core_options::option_type OPTION_BOOLEAN = core_options::option_type::BOOLEAN; +const core_options::option_type OPTION_INTEGER = core_options::option_type::INTEGER; +const core_options::option_type OPTION_FLOAT = core_options::option_type::FLOAT; +const core_options::option_type OPTION_STRING = core_options::option_type::STRING; #endif // MAME_LIB_UTIL_OPTIONS_H |