// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** options.h Core options code code ***************************************************************************/ #ifndef MAME_LIB_UTIL_OPTIONS_H #define MAME_LIB_UTIL_OPTIONS_H #include "corefile.h" #include //************************************************************************** // 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 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 { 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 }; // structure holding information about a collection of options class core_options { static const int MAX_UNADORNED_OPTIONS = 16; public: // information about a single entry in the options class entry { friend class core_options; friend class simple_list; // 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; } 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); 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 }; // 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); 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; } entry *get_entry(const char *name) const; // range iterators using auto_iterator = simple_list::auto_iterator; auto_iterator begin() const { return m_entrylist.begin(); } auto_iterator end() const { return m_entrylist.end(); } // 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_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); // parsing/input bool parse_command_line(std::vector &args, int priority, std::string &error_string); bool parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string); bool pluck_from_command_line(std::vector &args, const std::string &name, std::string &result); // reverting void revert(int priority_hi = OPTION_PRIORITY_MAXIMUM, int priority_lo = OPTION_PRIORITY_DEFAULT); // output std::string output_ini(const core_options *diff = nullptr) const; std::string output_help() const; // 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; // 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); // 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 { NONE, OVERRIDE, SKIP }; 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; } 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); // internal state simple_list m_entrylist; // head of list of entries std::unordered_map m_entrymap; // map for fast lookup std::string m_command; // command found static const char *const s_option_unadorned[]; // array of unadorned option "names" }; #endif // MAME_LIB_UTIL_OPTIONS_H