summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/options.h
blob: cf58bc6722241d1276c74d84f8af31aa6cabd08f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    options.h

    Core options code code

***************************************************************************/

#ifndef __OPTIONS_H__
#define __OPTIONS_H__

#include "corefile.h"
#include <unordered_map>



//**************************************************************************
//  CONSTANTS
//**************************************************************************

// option types
const UINT32 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 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              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<entry>;

		// construction/destruction
		entry(const char *name, const char *description, UINT32 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(); }
		UINT32 seqid() const { return m_seqid; }
		int type() const { return (m_flags & OPTION_TYPE_MASK); }
		UINT32 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 mask, UINT32 flag);
		void mark_changed() { m_changed = true; }
		void revert(int priority);

	private:
		// internal state
		entry *                 m_next;             // link to the next data
		UINT32                  m_flags;            // flags from the entry
		UINT32                  m_seqid;            // sequence ID; bumped on each change
		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 char *command() const { return m_command.c_str(); }

	// configuration
	void add_entry(const char *name, const char *description, UINT32 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(int argc, char **argv, int priority, std::string &error_string);
	bool parse_ini_file(core_file &inifile, int priority, int ignore_priority, std::string &error_string);

	// reverting
	void revert(int priority = OPTION_PRIORITY_MAXIMUM);

	// 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)); }
	UINT32 seqid(const char *name) const;
	bool exists(const char *name) const;
	bool is_changed(const char *name) const;

	// setting
	void set_command(const char *command);
	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 mask, UINT32 flags);
	void mark_changed(const char *name);

	// misc
	static const char *unadorned(int x = 0) { return s_option_unadorned[MIN(x, MAX_UNADORNED_OPTIONS)]; }
	int options_count() const { return m_entrylist.count(); }

private:
	// internal helpers
	void reset();
	void append_entry(entry &newentry);
	void copyfrom(const core_options &src);
	bool validate_and_set_data(entry &curentry, const char *newdata, int priority, std::string &error_string);

	// 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
	static const char *const s_option_unadorned[];  // array of unadorned option "names"
};



#endif /* __OPTIONS_H__ */