summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/options.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2011-03-03 17:05:24 +0000
committer Aaron Giles <aaron@aarongiles.com>2011-03-03 17:05:24 +0000
commit06ee6804dd5d1157a079e02d46abb6612571f21f (patch)
tree831cd82cc7cf6d493e6b5e9a7bf7d956733cf663 /src/lib/util/options.c
parente870e8d7bce1bda126a3ea06391d587dc9b57f01 (diff)
Converted core_options to a class. Removed a bunch of marginal
functionality in favor of alternate mechanisms. Errors are now reported via an astring rather than via callbacks. Every option must now specify a type (command, integer, float, string, boolean, etc). Command behavior has changed so that only one command is permitted. [Aaron Giles] Changed fileio system to accept just a raw searchpath instead of an options/option name combination. [Aaron Giles] Created emu_options class dervied from core_options which wraps core emulator options. Added mechanisms to cleanly change the system name and add/remove system-specific options, versus the old way using callbacks. Also added read accessors for all the options, to ensure consistency in how parameters are handled. Changed most core systems to access emu_options instead of core_options. Also changed machine->options() to return emu_options. [Aaron Giles] Created cli_options class derived from emu_options which adds the command-line specific options. Updated clifront code to leverage the new class and the new core behaviors. cli_execute() now accepts a cli_options object when called. [Aaron Giles] Updated both SDL and Windows to have their own options classes, derived from cli_options, which add the OSD-specific options on top of everything else. Added accessors for all the options so that queries are strongly typed and simplified. [Aaron Giles] Out of whatsnew: I've surely screwed up some stuff, though I have smoke tested a bunch of things. Let me know if you hit anything odd. Also I know this change will impact the WINUI stuff, please let me know if there are issues. All the functionality necessary should still be present. If it's not obvious, please talk to me before adding stuff to the core_options class.
Diffstat (limited to 'src/lib/util/options.c')
-rw-r--r--src/lib/util/options.c1440
1 files changed, 469 insertions, 971 deletions
diff --git a/src/lib/util/options.c b/src/lib/util/options.c
index 9c735d5f3bf..3b7fcfa200d 100644
--- a/src/lib/util/options.c
+++ b/src/lib/util/options.c
@@ -45,101 +45,11 @@
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define MAX_ENTRY_NAMES 4
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* forward references */
-typedef struct _options_data options_data;
-
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
-/* range parameter for minimum/maximum values */
-typedef union _options_range_parameter options_range_parameter;
-union _options_range_parameter
-{
- float f;
- int i;
-};
-
-
-/* hash table entries */
-typedef struct _options_hash_entry options_hash_entry;
-struct _options_hash_entry
-{
- options_hash_entry * next; /* link to the next entry */
- astring * name; /* name under the current link */
- options_data * data; /* link to associated options_data */
-};
-
-
-/* information about a single entry in the options */
-struct _options_data
-{
- options_hash_entry links[MAX_ENTRY_NAMES]; /* array of hash table entries (one per name) */
- options_data * next; /* link to the next data */
- UINT32 flags; /* flags from the entry */
- UINT32 seqid; /* sequence ID; bumped on each change */
- int error_reported; /* have we reported an error on this option yet? */
- int priority; /* priority of the data set */
- astring * data; /* data for this item */
- astring * defdata; /* default data for this item */
- const char * description; /* description for this item */
- options_range_type range_type; /* the type of range to apply to this item */
- options_range_parameter range_minimum; /* the minimum of the range */
- options_range_parameter range_maximum; /* the maximum of the range */
- void (*callback)(core_options *opts, const char *arg); /* callback to be invoked when parsing */
-};
-
-
-/* structure holding information about a collection of options */
-struct _core_options
-{
- void (*output[OPTMSG_COUNT])(const char *s);/* output callbacks */
-
- /* linked list, for sequential iteration */
- options_data * datalist; /* linked list for sequential iteration */
- options_data ** datalist_nextptr; /* pointer to pointer to tail entry */
-
- /* hashtable, for fast lookup */
- options_hash_entry * hashtable[101]; /* hash table for fast lookup */
-};
-
-
-/* information about an in-progress options enumeration */
-struct _options_enumerator
-{
- options_data * current;
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static options_data *find_entry_data(core_options *opts, const char *string, int is_command_line);
-static void update_data(core_options *opts, options_data *data, const char *newdata, int priority);
-static int parse_option_name(core_options *opts, const char *srcstring, options_data *data);
-
-static void message(core_options *opts, options_message msgtype, const char *format, ...) ATTR_PRINTF(3,4);
-static UINT32 hash_value(core_options *opts, const char *str);
-static void output_printf(void (*output)(const char *s), const char *format, ...) ATTR_PRINTF(2,3);
-
-
-
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-
-const char *const option_unadorned[MAX_UNADORNED_OPTIONS] =
+const char *const core_options::s_option_unadorned[MAX_UNADORNED_OPTIONS] =
{
"<UNADORNED0>",
"<UNADORNED1>",
@@ -161,448 +71,362 @@ const char *const option_unadorned[MAX_UNADORNED_OPTIONS] =
-/***************************************************************************
- OPTIONS COLLECTION MANAGEMENT
-***************************************************************************/
+//**************************************************************************
+// CORE OPTIONS ENTRY
+//**************************************************************************
-/*-------------------------------------------------
- options_create - creates a new instance of
- core options
--------------------------------------------------*/
+//-------------------------------------------------
+// entry - constructor
+//-------------------------------------------------
-core_options *options_create(void (*fail)(const char *message))
+core_options::entry::entry(const options_entry &entrylist)
+ : m_next(NULL),
+ m_flags(entrylist.flags),
+ m_seqid(0),
+ m_error_reported(false),
+ m_priority(OPTION_PRIORITY_DEFAULT),
+ m_description(entrylist.description)
{
- /* allocate memory for the option block */
- core_options *opts = (core_options *)malloc(sizeof(*opts));
- if (opts == NULL)
- goto error;
-
- /* and set up the structure */
- memset(opts, 0, sizeof(*opts));
- opts->datalist_nextptr = &opts->datalist;
- return opts;
-
-error:
- return NULL;
+ // copy in the name(s) as appropriate
+ if (entrylist.name != NULL)
+ {
+ // first extract any range
+ astring namestr(entrylist.name);
+ int lparen = namestr.chr(0, '(');
+ int dash = namestr.chr(lparen + 1, '-');
+ int rparen = namestr.chr(dash + 1, ')');
+ if (lparen != -1 && dash != -1 && rparen != -1)
+ {
+ m_minimum.cpysubstr(namestr, lparen + 1, dash - (lparen + 1)).trimspace();
+ m_maximum.cpysubstr(namestr, dash + 1, rparen - (dash + 1)).trimspace();
+ namestr.del(lparen, rparen + 1 - lparen);
+ }
+
+ // then chop up any semicolon-separated names
+ int semi;
+ int nameindex = 0;
+ while ((semi = namestr.chr(0, ';')) != -1 && nameindex < ARRAY_LENGTH(m_name))
+ {
+ m_name[nameindex++].cpysubstr(namestr, 0, semi);
+ namestr.del(0, semi + 1);
+ }
+
+ // finally add the last item
+ if (nameindex < ARRAY_LENGTH(m_name))
+ m_name[nameindex++] = namestr;
+ }
+
+ // set the default value
+ if (entrylist.defvalue != NULL)
+ m_defdata = entrylist.defvalue;
+ m_data = m_defdata;
}
-/*-------------------------------------------------
- options_free - frees an options object
--------------------------------------------------*/
+//-------------------------------------------------
+// set_value - update our data value
+//-------------------------------------------------
-void options_free(core_options *opts)
+void core_options::entry::set_value(const char *newdata, int priority)
{
- options_data *data, *next;
-
- /* loop over data items and free them */
- for (data = opts->datalist; data != NULL; data = next)
- {
- int linknum;
-
- next = data->next;
+ // ignore if we don't have priority
+ if (priority < m_priority)
+ return;
- /* free names */
- for (linknum = 0; linknum < ARRAY_LENGTH(data->links); linknum++)
- if (data->links[linknum].name != NULL)
- astring_free(data->links[linknum].name);
+ // set the data and priority, then bump the sequence
+ m_data = newdata;
+ m_priority = priority;
+ m_seqid++;
+}
- /* free strings */
- astring_free(data->data);
- astring_free(data->defdata);
- /* free the data itself */
- free(data);
- }
+//-------------------------------------------------
+// set_default_value - set the default value of
+// an option, and reset the current value to it
+//-------------------------------------------------
- /* free the options itself */
- free(opts);
+void core_options::entry::set_default_value(const char *defvalue)
+{
+ m_data = defvalue;
+ m_defdata = defvalue;
+ m_priority = OPTION_PRIORITY_DEFAULT;
}
-/*-------------------------------------------------
- options_set_output_callback - installs a callback
- to be invoked when data is outputted in the
- process of outputting options
--------------------------------------------------*/
+//-------------------------------------------------
+// revert - revert back to our default if we are
+// at or below the given priority
+//-------------------------------------------------
-void options_set_output_callback(core_options *opts, options_message msgtype, void (*callback)(const char *s))
+void core_options::entry::revert(int priority)
{
- opts->output[msgtype] = callback;
+ // if our priority is low enough, revert to the default
+ if (m_priority <= priority)
+ {
+ m_data = m_defdata;
+ m_priority = OPTION_PRIORITY_DEFAULT;
+ }
}
-/*-------------------------------------------------
- options_revert - revert options at or below
- a certain priority back to their defaults
--------------------------------------------------*/
-void options_revert(core_options *opts, int priority)
+//**************************************************************************
+// CORE OPTIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// core_options - constructor
+//-------------------------------------------------
+
+core_options::core_options()
+ : m_entrylist(NULL),
+ m_entrylist_tailptr(&m_entrylist)
{
- options_data *data;
+}
- /* iterate over options and revert to defaults if below the given priority */
- for (data = opts->datalist; data != NULL; data = data->next)
- if (data->priority <= priority)
- {
- astring_cpy(data->data, data->defdata);
- data->priority = OPTION_PRIORITY_DEFAULT;
- }
+core_options::core_options(const options_entry *entrylist)
+ : m_entrylist(NULL),
+ m_entrylist_tailptr(&m_entrylist)
+{
+ add_entries(entrylist);
}
-/*-------------------------------------------------
- options_revert_driver_only - revert options
- that are marked as driver only and are under
- priority level
--------------------------------------------------*/
+core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2)
+ : m_entrylist(NULL),
+ m_entrylist_tailptr(&m_entrylist)
+{
+ add_entries(entrylist1);
+ add_entries(entrylist2);
+}
-void options_revert_driver_only(core_options *opts, int priority)
+core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2, const options_entry *entrylist3)
+ : m_entrylist(NULL),
+ m_entrylist_tailptr(&m_entrylist)
{
- options_data *data;
+ add_entries(entrylist1);
+ add_entries(entrylist2);
+ add_entries(entrylist3);
+}
- /* iterate over options and revert to defaults if below the given priority */
- for (data = opts->datalist; data != NULL; data = data->next)
- if ((data->flags & OPTION_DRIVER_ONLY) && (data->priority < priority)) {
- astring_cpy(data->data, data->defdata);
- data->priority = OPTION_PRIORITY_DEFAULT;
- }
+core_options::core_options(const core_options &src)
+ : m_entrylist(NULL),
+ m_entrylist_tailptr(&m_entrylist)
+{
+ copyfrom(src);
}
-/*-------------------------------------------------
- options_copy - copy options from one core_options
- to another
--------------------------------------------------*/
-int options_copy(core_options *dest_opts, core_options *src_opts)
+//-------------------------------------------------
+// ~core_options - destructor
+//-------------------------------------------------
+
+core_options::~core_options()
{
- options_data *data;
+ // delete all entries from the list
+ while (m_entrylist != NULL)
+ remove_entry(*m_entrylist);
+}
- /* iterate over options in the destination */
- for (data = dest_opts->datalist; data != NULL; data = data->next)
- if (!(data->flags & OPTION_HEADER))
- {
- options_data *srcdata = find_entry_data(src_opts, astring_c(data->links[0].name), FALSE);
- /* if the option exists in the source, set it in the destination */
- if (srcdata != NULL)
- options_set_string(dest_opts, astring_c(srcdata->links[0].name), astring_c(srcdata->data), srcdata->priority);
- }
+//-------------------------------------------------
+// operator= - assignment operator
+//-------------------------------------------------
- return TRUE;
+core_options &core_options::operator=(const core_options &rhs)
+{
+ // ignore self-assignment
+ if (this != &rhs)
+ copyfrom(rhs);
+ return *this;
}
-/*-------------------------------------------------
- options_equal - compare two sets of options
--------------------------------------------------*/
+//-------------------------------------------------
+// operator== - compare two sets of options
+//-------------------------------------------------
-int options_equal(core_options *opts1, core_options *opts2)
+bool core_options::operator==(const core_options &rhs)
{
- options_data *data;
-
- /* iterate over options in the first list */
- for (data = opts1->datalist; data != NULL; data = data->next)
- if (!(data->flags & OPTION_HEADER))
+ // iterate over options in the first list
+ for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ if (!curentry->is_header())
{
- const char *value1 = options_get_string(opts1, astring_c(data->links[0].name));
- const char *value2 = options_get_string(opts2, astring_c(data->links[0].name));
-
- /* if the values differ, return false */
- if (strcmp(value1, value2) != 0)
- return FALSE;
+ // if the values differ, return false
+ if (strcmp(curentry->m_data, rhs.value(curentry->name())) != 0)
+ return false;
}
- return TRUE;
+ return true;
}
+//-------------------------------------------------
+// operator!= - compare two sets of options
+//-------------------------------------------------
-/***************************************************************************
- OPTION DEFINITIONS
-***************************************************************************/
+bool core_options::operator!=(const core_options &rhs)
+{
+ return !operator==(rhs);
+}
-/*-------------------------------------------------
- options_add_entries - add entries to the
- current options sets
--------------------------------------------------*/
-int options_add_entries(core_options *opts, const options_entry *entrylist, int force)
+//-------------------------------------------------
+// add_entries - add entries to the current
+// options sets
+//-------------------------------------------------
+
+void core_options::add_entries(const options_entry *entrylist, bool override_existing)
{
- /* loop over entries until we hit a NULL name */
- for ( ; entrylist->name != NULL || (entrylist->flags & OPTION_HEADER); entrylist++)
+ // loop over entries until we hit a NULL name
+ for ( ; entrylist->name != NULL || (entrylist->flags & OPTION_HEADER) != 0; entrylist++)
{
- options_data *match = NULL;
- int i;
-
- /* allocate a new item */
- options_data *data = (options_data *)malloc(sizeof(*data));
- if (data == NULL)
- return FALSE;
- memset(data, 0, sizeof(*data));
-
- /* parse the option name */
- if (entrylist->name != NULL)
- parse_option_name(opts, entrylist->name, data);
-
- /* do we match an existing entry? */
- for (i = 0; i < ARRAY_LENGTH(data->links) && match == NULL; i++)
- if (data->links[i].name != NULL)
- match = find_entry_data(opts, astring_c(data->links[i].name), FALSE);
-
- /* if so, throw away this entry and replace the data */
- if ((force == FALSE) && (match != NULL))
- {
- /* free what we've allocated so far */
- for (i = 0; i < ARRAY_LENGTH(data->links); i++)
- if (data->links[i].name != NULL)
- astring_free(data->links[i].name);
- free(data);
-
- /* use the matching entry as our data */
- data = match;
- }
-
- /* otherwise, finish making the new entry */
- else
+ // allocate a new entry
+ entry *newentry = new entry(*entrylist);
+ if (newentry->name() != NULL)
{
- /* allocate strings */
- data->data = astring_alloc();
- data->defdata = astring_alloc();
-
- /* copy the flags, and set the value equal to the default */
- data->flags = entrylist->flags;
- data->description = entrylist->description;
-
- /* add us to the end of the sequential list */
- *opts->datalist_nextptr = data;
- opts->datalist_nextptr = &data->next;
-
- /* add each name to the appropriate hash table with a link back to us */
- for (i = 0; i < ARRAY_LENGTH(data->links); i++)
- if (data->links[i].name != NULL)
+ // see if we match an existing entry
+ entry *existing = m_entrymap.find(newentry->name());
+ if (existing != NULL)
+ {
+ // if we're overriding existing entries, then remove the old one
+ if (override_existing)
+ remove_entry(*existing);
+
+ // otherwise, just override the default and current values and throw out the new entry
+ else
{
- int hash_entry = hash_value(opts, astring_c(data->links[i].name));
-
- /* set up link */
- data->links[i].data = data;
- data->links[i].next = opts->hashtable[hash_entry];
- opts->hashtable[hash_entry] = &data->links[i];
+ existing->set_default_value(newentry->value());
+ delete newentry;
+ continue;
}
+ }
}
-
- /* copy in the data and default data values */
- if (entrylist->defvalue != NULL)
- {
- astring_cpyc(data->data, entrylist->defvalue);
- astring_cpyc(data->defdata, entrylist->defvalue);
- }
- data->priority = OPTION_PRIORITY_DEFAULT;
+
+ // add us to the list and maps
+ append_entry(*newentry);
}
- return TRUE;
}
-int options_add_entries(core_options *opts, const options_entry *entrylist)
-{
- return options_add_entries(opts,entrylist,FALSE);
-}
-/*-------------------------------------------------
- options_set_option_default_value - change the
- default value of an option
--------------------------------------------------*/
+//-------------------------------------------------
+// set_default_value - change the default value
+// of an option
+//-------------------------------------------------
-int options_set_option_default_value(core_options *opts, const char *name, const char *defvalue)
+void core_options::set_default_value(const char *name, const char *defvalue)
{
- options_data *data = find_entry_data(opts, name, TRUE);
-
- /* if we don't have an entry for this, fail */
- if (data == NULL)
- return FALSE;
-
- /* update the data and default data; note that we assume that data == defdata */
- astring_cpyc(data->data, defvalue);
- astring_cpyc(data->defdata, defvalue);
- data->priority = OPTION_PRIORITY_DEFAULT;
- return TRUE;
+ // find the entry and bail if we can't
+ entry *curentry = m_entrymap.find(name);
+ if (curentry == NULL)
+ return;
+
+ // update the data and default data
+ curentry->set_default_value(defvalue);
}
-/*-------------------------------------------------
- options_set_option_callback - specifies a
- callback to be invoked when parsing options
--------------------------------------------------*/
+//-------------------------------------------------
+// parse_command_line - parse a series of
+// command line arguments
+//-------------------------------------------------
-int options_set_option_callback(core_options *opts, const char *name, void (*callback)(core_options *opts, const char *arg))
+bool core_options::parse_command_line(int argc, char **argv, int priority, astring &error_string)
{
- options_data *data = find_entry_data(opts, name, TRUE);
-
- /* if we don't find an entry, fail */
- if (data == NULL)
- return FALSE;
-
- /* set the callback */
- data->callback = callback;
- return TRUE;
-}
-
-
+ // reset the errors and the command
+ error_string.reset();
+ m_command.reset();
-/***************************************************************************
- OPTION DATA EXTRACTION
-***************************************************************************/
-
-/*-------------------------------------------------
- options_parse_command_line - parse a series
- of command line arguments
--------------------------------------------------*/
-
-int options_parse_command_line(core_options *opts, int argc, char **argv, int priority, int show_error)
-{
+ // iterate through arguments
int unadorned_index = 0;
- int arg;
- for (arg = 1; arg < argc; arg++)
+ for (int arg = 1; arg < argc; arg++)
{
- const char *optionname;
- options_data *data;
- int is_unadorned;
-
- /* determine the entry name to search for */
- is_unadorned = (argv[arg][0] != '-');
- if (!is_unadorned)
- optionname = &argv[arg][1];
- else
- optionname = OPTION_UNADORNED(unadorned_index);
-
- /* find our entry */
- data = find_entry_data(opts, optionname, TRUE);
- if (data == NULL) continue;
- if ((data->flags & OPTION_COMMAND) != 0) {
- // in case of any command force show error to TRUE
- show_error = TRUE;
- break;
+ // determine the entry name to search for
+ const char *curarg = argv[arg];
+ bool is_unadorned = (curarg[0] != '-');
+ const char *optionname = is_unadorned ? core_options::unadorned(unadorned_index++) : &curarg[1];
+
+ // find our entry; if not found, indicate invalid option
+ entry *curentry = m_entrymap.find(optionname);
+ if (curentry == NULL)
+ {
+ error_string.catprintf("Error: unknown option: %s\n", curarg);
+ return false;
}
- }
- /* loop over commands, looking for options */
- for (arg = 1; arg < argc; arg++)
- {
- const char *optionname, *newdata;
- options_data *data;
- int is_unadorned;
-
- /* determine the entry name to search for */
- is_unadorned = (argv[arg][0] != '-');
- if (!is_unadorned)
- optionname = &argv[arg][1];
- else
- optionname = OPTION_UNADORNED(unadorned_index);
-
- /* find our entry */
- data = find_entry_data(opts, optionname, TRUE);
- if (data == NULL)
+
+ // process commands first
+ if (curentry->type() == OPTION_COMMAND)
{
- if (!show_error) continue;
- message(opts, OPTMSG_ERROR, "Error: unknown option: %s\n", argv[arg]);
- return 1;
+ // can only have one command
+ if (m_command)
+ {
+ error_string.catprintf("Error: multiple commands specified -%s and %s\n", m_command.cstr(), curarg);
+ return false;
+ }
+ m_command = curentry->name();
+ continue;
}
- /* if unadorned, we have to bump the count (unless if the option repeats) */
- if (is_unadorned && !(data->flags & OPTION_REPEATS))
- unadorned_index++;
-
- /* get the data for this argument, special casing booleans */
- if ((data->flags & (OPTION_BOOLEAN | OPTION_COMMAND)) != 0)
- newdata = (strncmp(&argv[arg][1], "no", 2) == 0) ? "0" : "1";
- else if (argv[arg][0] != '-')
- newdata = argv[arg];
+ // get the data for this argument, special casing booleans
+ const char *newdata;
+ if (curentry->type() == OPTION_BOOLEAN)
+ newdata = (strncmp(&curarg[1], "no", 2) == 0) ? "0" : "1";
+ else if (is_unadorned)
+ newdata = curarg;
else if (arg + 1 < argc)
newdata = argv[++arg];
else
{
- message(opts, OPTMSG_ERROR, "Error: option %s expected a parameter\n", argv[arg]);
- return 1;
+ error_string.catprintf("Error: option %s expected a parameter\n", curarg);
+ return false;
}
- /* if the option is deprecated or internal, don't process further */
- if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) != 0)
- continue;
-
- /* invoke callback, if present */
- if (data->callback != NULL)
- (*data->callback)(opts, newdata);
-
- /* allocate a new copy of data for this */
- update_data(opts, data, newdata, priority);
+ // set the new data
+ validate_and_set_data(*curentry, newdata, priority, error_string);
}
- return 0;
-}
-
-
-/*-------------------------------------------------
- options_force_option_callback - set option value
- and execute callback call
--------------------------------------------------*/
-
-int options_force_option_callback(core_options *opts, const char *optionname, const char *newval, int priority)
-{
- options_data *data = find_entry_data(opts, optionname, TRUE);
- if (data == NULL)
- {
- message(opts, OPTMSG_ERROR, "Error: unknown option: %s\n", optionname);
- return 1;
- }
-
- /* invoke callback, if present */
- if (data->callback != NULL)
- (*data->callback)(opts, newval);
-
- /* allocate a new copy of data for this */
- update_data(opts, data, newval, priority);
- return 0;
+ return true;
}
-/*-------------------------------------------------
- options_parse_ini_file - parse a series
- of entries in an INI file
--------------------------------------------------*/
+//-------------------------------------------------
+// parse_ini_file - parse a series of entries in
+// an INI file
+//-------------------------------------------------
-int options_parse_ini_file(core_options *opts, core_file *inifile, int priority, int ignoreprio)
+bool core_options::parse_ini_file(core_file &inifile, int priority, int ignore_priority, astring &error_string)
{
+ // loop over lines in the file
char buffer[4096];
-
- /* loop over data */
- while (core_fgets(buffer, ARRAY_LENGTH(buffer), inifile) != NULL)
+ while (core_fgets(buffer, ARRAY_LENGTH(buffer), &inifile) != NULL)
{
- char *optionname, *optiondata, *temp;
- options_data *data;
- int inquotes = FALSE;
-
- /* find the name */
+ // find the extent of the name
+ char *optionname;
for (optionname = buffer; *optionname != 0; optionname++)
if (!isspace((UINT8)*optionname))
break;
- /* skip comments */
+ // skip comments
if (*optionname == 0 || *optionname == '#')
continue;
- /* scan forward to find the first space */
+ // scan forward to find the first space
+ char *temp;
for (temp = optionname; *temp != 0; temp++)
if (isspace((UINT8)*temp))
break;
- /* if we hit the end early, print a warning and continue */
+ // if we hit the end early, print a warning and continue
if (*temp == 0)
{
- message(opts, OPTMSG_WARNING, "Warning: invalid line in INI: %s", buffer);
+ error_string.catprintf("Warning: invalid line in INI: %s", buffer);
continue;
}
- /* NULL-terminate */
+ // NULL-terminate
*temp++ = 0;
- optiondata = temp;
+ char *optiondata = temp;
- /* scan the data, stopping when we hit a comment */
+ // scan the data, stopping when we hit a comment
+ bool inquotes = false;
for (temp = optiondata; *temp != 0; temp++)
{
if (*temp == '"')
@@ -612,645 +436,319 @@ int options_parse_ini_file(core_options *opts, core_file *inifile, int priority,
}
*temp = 0;
- /* find our entry */
- data = find_entry_data(opts, optionname, FALSE);
- if (data == NULL)
+ // find our entry
+ entry *curentry = m_entrymap.find(optionname);
+ if (curentry == NULL)
{
- if (priority >= ignoreprio) message(opts, OPTMSG_WARNING, "Warning: unknown option in INI: %s\n", optionname);
+ if (priority >= ignore_priority)
+ error_string.catprintf("Warning: unknown option in INI: %s\n", optionname);
continue;
}
- if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) != 0)
- continue;
- /* allocate a new copy of data for this */
- update_data(opts, data, optiondata, priority);
+ // set the new data
+ validate_and_set_data(*curentry, optiondata, priority, error_string);
}
- return 0;
+ return true;
}
+//-------------------------------------------------
+// revert - revert options at or below a certain
+// priority back to their defaults
+//-------------------------------------------------
+
+void core_options::revert(int priority)
+{
+ // iterate over options and revert to defaults if below the given priority
+ for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ curentry->revert(priority);
+}
-/***************************************************************************
- OPTIONS OUTPUT
-***************************************************************************/
-/*-------------------------------------------------
- options_output_diff_ini_file - output the diff
- of the current state from a base state to an
- INI file
--------------------------------------------------*/
+//-------------------------------------------------
+// output_ini - output the options in INI format,
+// only outputting entries that different from
+// the optional diff
+//-------------------------------------------------
-void options_output_diff_ini_file(core_options *opts, core_options *baseopts, core_file *inifile)
+const char *core_options::output_ini(astring &buffer, const core_options *diff)
{
- options_data *data;
- const char *last_header = NULL;
- const char *name;
- const char *value;
- options_data *basedata;
+ // INI files are complete, so always start with a blank buffer
+ buffer.reset();
- /* loop over all items */
- for (data = opts->datalist; data != NULL; data = data->next)
+ // loop over all items
+ const char *last_header = NULL;
+ for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
{
- /* header: record description */
- if ((data->flags & OPTION_HEADER) != 0)
- last_header = data->description;
+ // header: record description
+ if (curentry->is_header())
+ last_header = curentry->description();
- /* otherwise, output entries for all non-deprecated and non-command items (if not in baseopts) */
- else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL | OPTION_COMMAND)) == 0)
+ // otherwise, output entries for all non-command items
+ else if (!curentry->is_command())
{
- /* get name and data of this value */
- name = astring_c(data->links[0].name);
- value = astring_c(data->data);
-
- /* look up counterpart in baseopts, if baseopts is specified */
- basedata = (baseopts != NULL) ? find_entry_data(baseopts, name, FALSE) : NULL;
-
- /* is our data different, or not in baseopts? */
- if ((basedata == NULL) || (strcmp(value, astring_c(basedata->data)) != 0))
+ // look up counterpart in diff, if diff is specified
+ const char *name = curentry->name();
+ const char *value = curentry->value();
+ if (diff == NULL || strcmp(value, diff->value(name)) != 0)
{
- /* output header, if we have one */
+ // output header, if we have one
if (last_header != NULL)
{
- core_fprintf(inifile, "\n#\n# %s\n#\n", last_header);
+ buffer.catprintf("\n#\n# %s\n#\n", last_header);
last_header = NULL;
}
- /* and finally output the data */
+ // and finally output the data
if (strchr(value, ' ') != NULL)
- core_fprintf(inifile, "%-25s \"%s\"\n", name, value);
+ buffer.catprintf("%-25s \"%s\"\n", name, value);
else
- core_fprintf(inifile, "%-25s %s\n", name, value);
+ buffer.catprintf("%-25s %s\n", name, value);
}
}
}
+ return buffer;
}
-/*-------------------------------------------------
- options_output_ini_file - output the current
- state to an INI file
--------------------------------------------------*/
-
-void options_output_ini_file(core_options *opts, core_file *inifile)
-{
- options_output_diff_ini_file(opts, NULL, inifile);
-}
-
-
-/*-------------------------------------------------
- options_output_ini_file - output the current
- state to an INI file
--------------------------------------------------*/
-
-void options_output_ini_stdfile(core_options *opts, FILE *inifile)
-{
- options_data *data;
-
- /* loop over all items */
- for (data = opts->datalist; data != NULL; data = data->next)
- {
- /* header: just print */
- if ((data->flags & OPTION_HEADER) != 0)
- fprintf(inifile, "\n#\n# %s\n#\n", data->description);
-
- /* otherwise, output entries for all non-deprecated and non-command items */
- else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL | OPTION_COMMAND)) == 0)
- {
- if (astring_chr(data->data, 0, ' ') != -1)
- fprintf(inifile, "%-25s \"%s\"\n", astring_c(data->links[0].name), astring_c(data->data));
- else
- fprintf(inifile, "%-25s %s\n", astring_c(data->links[0].name), astring_c(data->data));
- }
- }
-}
-
-
-/*-------------------------------------------------
- options_output_help - output option help to
- a file
--------------------------------------------------*/
+//-------------------------------------------------
+// output_help - output option help to a string
+//-------------------------------------------------
-void options_output_help(core_options *opts, void (*output)(const char *))
+const char *core_options::output_help(astring &buffer)
{
- options_data *data;
-
- /* loop over all items */
- for (data = opts->datalist; data != NULL; data = data->next)
+ // start empty
+ buffer.reset();
+
+ // loop over all items
+ for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
{
- /* header: just print */
- if ((data->flags & OPTION_HEADER) != 0)
- output_printf(output, "\n#\n# %s\n#\n", data->description);
+ // header: just print
+ if (curentry->is_header())
+ buffer.catprintf("\n#\n# %s\n#\n", curentry->description());
- /* otherwise, output entries for all non-deprecated items */
- else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) == 0 && data->description != NULL)
- output_printf(output, "-%-20s%s\n", astring_c(data->links[0].name), data->description);
+ // otherwise, output entries for all non-deprecated items
+ else if (curentry->description() != NULL)
+ buffer.catprintf("-%-20s%s\n", curentry->name(), curentry->description());
}
+ return buffer;
}
+//-------------------------------------------------
+// value - return the raw option value
+//-------------------------------------------------
-/***************************************************************************
- OPTIONS READING
-***************************************************************************/
-
-/*-------------------------------------------------
- options_get_string - return data formatted
- as a string
--------------------------------------------------*/
-
-const char *options_get_string(core_options *opts, const char *name)
+const char *core_options::value(const char *name) const
{
- options_data *data = find_entry_data(opts, name, FALSE);
- const char *value = "";
-
- /* error if not found */
- if (data == NULL)
- message(opts, OPTMSG_ERROR, "Unexpected option %s queried\n", name);
-
- /* copy if non-NULL */
- else
- value = astring_c(data->data);
-
- return value;
+ entry *curentry = m_entrymap.find(name);
+ return (curentry != NULL) ? curentry->value() : "";
}
-/*-------------------------------------------------
- options_get_string_priority - return data
- formatted as a string if priority is equal
- or better
--------------------------------------------------*/
+//-------------------------------------------------
+// seqid - return the seqid for a given option
+//-------------------------------------------------
-const char *options_get_string_priority(core_options *opts, const char *name, int priority)
+UINT32 core_options::seqid(const char *name) const
{
- options_data *data = find_entry_data(opts, name, FALSE);
- const char *value = "";
-
- /* error if not found */
- if (data == NULL)
- message(opts, OPTMSG_ERROR, "Unexpected option %s queried\n", name);
-
- /* copy if non-NULL */
- else {
- if (data->priority!=OPTION_PRIORITY_DEFAULT) {
- if (priority > data->priority) return value;
- }
- value = astring_c(data->data);
- }
-
- return value;
+ entry *curentry = m_entrymap.find(name);
+ return (curentry != NULL) ? curentry->seqid() : 0;
}
-/*-------------------------------------------------
- options_get_bool - return data formatted as
- a boolean
--------------------------------------------------*/
+//-------------------------------------------------
+// set_value - set the raw option value
+//-------------------------------------------------
-int options_get_bool(core_options *opts, const char *name)
+bool core_options::set_value(const char *name, const char *value, int priority, astring &error_string)
{
- options_data *data = find_entry_data(opts, name, FALSE);
- int value = FALSE;
-
- /* error if not found */
- if (data == NULL)
- message(opts, OPTMSG_ERROR, "Unexpected boolean option %s queried\n", name);
-
- /* also error if we don't have a valid boolean value */
- else if (sscanf(astring_c(data->data), "%d", &value) != 1 || value < 0 || value > 1)
+ // find the entry first
+ entry *curentry = m_entrymap.find(name);
+ if (curentry == NULL)
{
- options_set_string(opts, name, astring_c(data->defdata), 0);
- sscanf(astring_c(data->data), "%d", &value);
- if (!data->error_reported)
- {
- message(opts, OPTMSG_ERROR, "Illegal boolean value for %s; reverting to %d\n", astring_c(data->links[0].name), value);
- data->error_reported = TRUE;
- }
+ error_string.catprintf("Attempted to set unknown option %s\n", name);
+ return false;
}
- return value;
+
+ // validate and set the item normally
+ return validate_and_set_data(*curentry, value, priority, error_string);
}
-
-/*-------------------------------------------------
- options_get_int - return data formatted as
- an integer
--------------------------------------------------*/
-
-int options_get_int(core_options *opts, const char *name)
+bool core_options::set_value(const char *name, int value, int priority, astring &error_string)
{
- options_data *data = find_entry_data(opts, name, FALSE);
- int value = 0;
-
- /* error if not found */
- if (data == NULL)
- message(opts, OPTMSG_ERROR, "Unexpected integer option %s queried\n", name);
-
- /* also error if we don't have a valid integer value */
- else if (sscanf(astring_c(data->data), "%d", &value) != 1)
- {
- options_set_string(opts, name, astring_c(data->defdata), 0);
- sscanf(astring_c(data->data), "%d", &value);
- if (!data->error_reported)
- {
- message(opts, OPTMSG_ERROR, "Illegal integer value for %s; reverting to %d\n", astring_c(data->links[0].name), value);
- data->error_reported = TRUE;
- }
- }
- return value;
+ astring tempstr;
+ tempstr.printf("%d", value);
+ return set_value(name, tempstr.cstr(), priority, error_string);
}
-
-/*-------------------------------------------------
- options_get_float - return data formatted as
- a float
--------------------------------------------------*/
-
-float options_get_float(core_options *opts, const char *name)
+bool core_options::set_value(const char *name, float value, int priority, astring &error_string)
{
- options_data *data = find_entry_data(opts, name, FALSE);
- float value = 0;
-
- /* error if not found */
- if (data == NULL)
- message(opts, OPTMSG_ERROR, "Unexpected float option %s queried\n", name);
-
- /* also error if we don't have a valid floating point value */
- else if (sscanf(astring_c(data->data), "%f", &value) != 1)
- {
- options_set_string(opts, name, astring_c(data->defdata), 0);
- sscanf(astring_c(data->data), "%f", &value);
- if (!data->error_reported)
- {
- message(opts, OPTMSG_ERROR, "Illegal float value for %s; reverting to %f\n", astring_c(data->links[0].name), (double)value);
- data->error_reported = TRUE;
- }
- }
- return value;
-}
-
-
-/*-------------------------------------------------
- options_get_seqid - return the seqid for an
- entry
--------------------------------------------------*/
-
-UINT32 options_get_seqid(core_options *opts, const char *name)
-{
- options_data *data = find_entry_data(opts, name, FALSE);
- return (data == NULL) ? 0 : data->seqid;
-}
-
-
-
-/***************************************************************************
- OPTIONS SETTING
-***************************************************************************/
-
-/*-------------------------------------------------
- options_set_string - set a string value
--------------------------------------------------*/
-
-void options_set_string(core_options *opts, const char *name, const char *value, int priority)
-{
- options_data *data = find_entry_data(opts, name, FALSE);
- update_data(opts, data, value, priority);
-}
-
-
-/*-------------------------------------------------
- options_set_bool - set a boolean value
--------------------------------------------------*/
-
-void options_set_bool(core_options *opts, const char *name, int value, int priority)
-{
- char temp[4];
- sprintf(temp, "%d", value ? 1 : 0);
- options_set_string(opts, name, temp, priority);
-}
-
-
-/*-------------------------------------------------
- options_set_int - set an integer value
--------------------------------------------------*/
-
-void options_set_int(core_options *opts, const char *name, int value, int priority)
-{
- char temp[20];
- sprintf(temp, "%d", value);
- options_set_string(opts, name, temp, priority);
+ astring tempstr;
+ tempstr.printf("%f", value);
+ return set_value(name, tempstr.cstr(), priority, error_string);
}
-/*-------------------------------------------------
- options_set_float - set a float value
--------------------------------------------------*/
+//-------------------------------------------------
+// reset - reset the options state, removing
+// everything
+//-------------------------------------------------
-void options_set_float(core_options *opts, const char *name, float value, int priority)
+void core_options::reset()
{
- char temp[100];
- sprintf(temp, "%f", value);
- options_set_string(opts, name, temp, priority);
-}
-
-
-
-/***************************************************************************
- OPTION DEFINITION QUERIES
-***************************************************************************/
-
-/*-------------------------------------------------
- options_enumerator_begin - retrieve the range of
- a float option
--------------------------------------------------*/
-
-options_enumerator *options_enumerator_begin(core_options *opts)
-{
- options_enumerator *enumerator;
-
- /* allocate memory for the enumerator */
- enumerator = (options_enumerator *)malloc(sizeof(*enumerator));
- if (enumerator == NULL)
- return NULL;
-
- /* start at the head of the list */
- enumerator->current = opts->datalist;
- return enumerator;
+ // remove all entries from the list
+ while (m_entrylist != NULL)
+ remove_entry(*m_entrylist);
+
+ // reset the map
+ m_entrymap.reset();
}
+//-------------------------------------------------
+// append_entry - append an entry to our list
+// and index it in the map
+//-------------------------------------------------
-/*-------------------------------------------------
- options_enumerator_next - returns the current
- option and advances the enumerator
--------------------------------------------------*/
-
-const char *options_enumerator_next(options_enumerator *enumerator)
+void core_options::append_entry(core_options::entry &newentry)
{
- astring *option_name = NULL;
-
- /* be sure to skip over false options */
- while (option_name == NULL && enumerator->current != NULL)
- {
- /* retrieve the current option name and advance the enumerator */
- option_name = enumerator->current->links[0].name;
- enumerator->current = enumerator->current->next;
- }
- return (option_name != NULL) ? astring_c(option_name) : NULL;
-}
-
-
+ // append to the list
+ *m_entrylist_tailptr = &newentry;
+ m_entrylist_tailptr = &newentry.m_next;
-/*-------------------------------------------------
- options_enumerator_free - disposes an options
- enumerator
--------------------------------------------------*/
-
-void options_enumerator_free(options_enumerator *enumerator)
-{
- free(enumerator);
+ // if we have names, add them to the map
+ for (int name = 0; name < ARRAY_LENGTH(newentry.m_name); name++)
+ if (newentry.m_name[name])
+ m_entrymap.add(newentry.m_name[name], &newentry);
}
-/*-------------------------------------------------
- options_get_range_type - determine the type
- of range for a particular option
--------------------------------------------------*/
+//-------------------------------------------------
+// remove_entry - remove an entry from our list
+// and map
+//-------------------------------------------------
-options_range_type options_get_range_type(core_options *opts, const char *name)
+void core_options::remove_entry(core_options::entry &delentry)
{
- options_data *data = find_entry_data(opts, name, FALSE);
- return data->range_type;
-}
-
-
-/*-------------------------------------------------
- options_get_range_int - retrieve the range of
- an integer option
--------------------------------------------------*/
+ // remove us from the list
+ entry *preventry = NULL;
+ for (entry *curentry = m_entrylist; curentry != NULL; curentry = curentry->next())
+ if (curentry == &delentry)
+ {
+ // update link from previous to us
+ if (preventry != NULL)
+ preventry->m_next = delentry.m_next;
+ else
+ m_entrylist = delentry.m_next;
+
+ // if we're the last item, update the next pointer
+ if (delentry.m_next == NULL)
+ {
+ if (preventry != NULL)
+ m_entrylist_tailptr = &preventry->m_next;
+ else
+ m_entrylist_tailptr = &m_entrylist;
+ }
-void options_get_range_int(core_options *opts, const char *name, int *minval, int *maxval)
-{
- options_data *data = find_entry_data(opts, name, FALSE);
- *minval = data->range_minimum.i;
- *maxval = data->range_maximum.i;
+ // remove all entries from the map
+ for (int name = 0; name < ARRAY_LENGTH(delentry.m_name); name++)
+ if (delentry.m_name[name])
+ m_entrymap.remove(delentry.m_name[name]);
+ break;
+ }
}
+//-------------------------------------------------
+// copyfrom - copy options from another set
+//-------------------------------------------------
-/*-------------------------------------------------
- options_get_range_float - retrieve the range of
- a float option
--------------------------------------------------*/
-
-void options_get_range_float(core_options *opts, const char *name, float *minval, float *maxval)
+void core_options::copyfrom(const core_options &src)
{
- options_data *data = find_entry_data(opts, name, FALSE);
- *minval = data->range_minimum.f;
- *maxval = data->range_maximum.f;
+ // reset ourselves first
+ reset();
+
+ // iterate through the src options and make our own
+ for (entry *curentry = src.m_entrylist; curentry != NULL; curentry = curentry->next())
+ append_entry(*new entry(*curentry));
}
+//-------------------------------------------------
+// validate_and_set_data - make sure the data is
+// of the appropriate type and within range,
+// then set it
+//-------------------------------------------------
-/***************************************************************************
- INTERNAL UTILITIES
-***************************************************************************/
-
-/*-------------------------------------------------
- find_entry_data - locate an entry whose name
- matches the given string
--------------------------------------------------*/
-
-static options_data *find_entry_data(core_options *opts, const char *string, int is_command_line)
+bool core_options::validate_and_set_data(core_options::entry &curentry, const char *newdata, int priority, astring &error_string)
{
- int hash_entry = hash_value(opts, string);
- options_hash_entry *link;
-
- /* scan all entries */
- for (link = opts->hashtable[hash_entry]; link != NULL; link = link->next)
- if (!(link->data->flags & OPTION_HEADER) && link->name != NULL && astring_cmpc(link->name, string) == 0)
- return link->data;
-
- /* haven't found it? if we are prefixed with "no", then try to search for that */
- if (is_command_line && string[0] == 'n' && string[1] == 'o')
+ // trim any whitespace
+ astring data(newdata);
+ data.trimspace();
+
+ // trim quotes
+ if (data.chr(0, '"') == 0 && data.rchr(0, '"') == data.len() - 1)
{
- options_data *data = find_entry_data(opts, &string[2], FALSE);
- if (data != NULL && (data->flags & OPTION_BOOLEAN))
- return data;
+ data.del(0, 1);
+ data.del(data.len() - 1, 1);
}
-
- /* didn't find it at all */
- return NULL;
-}
-
-
-/*-------------------------------------------------
- update_data - update the data value for a
- given entry
--------------------------------------------------*/
-
-static void update_data(core_options *opts, options_data *data, const char *newdata, int priority)
-{
- const char *dataend = newdata + strlen(newdata) - 1;
- const char *datastart = newdata;
- float f;
- int i;
-
- /* strip off leading/trailing spaces */
- while (isspace((UINT8)*datastart) && datastart <= dataend)
- datastart++;
- while (isspace((UINT8)*dataend) && datastart <= dataend)
- dataend--;
-
- /* strip off quotes */
- if (datastart != dataend && *datastart == '"' && *dataend == '"')
- datastart++, dataend--;
-
- /* check against range */
- switch (data->range_type)
+
+ // validate the type of data and optionally the range
+ float fval;
+ int ival;
+ switch (curentry.type())
{
- case OPTION_RANGE_NONE:
- /* do nothing */
+ // booleans must be 0 or 1
+ case OPTION_BOOLEAN:
+ if (sscanf(data, "%d", &ival) != 1 || ival < 0 || ival > 1)
+ {
+ error_string.catprintf("Illegal boolean value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.cstr(), curentry.value());
+ return false;
+ }
break;
-
- case OPTION_RANGE_INT:
- /* check against integer range */
- i = 0;
- if (sscanf(datastart, "%d", &i) != 1)
+
+ // integers must be integral
+ case OPTION_INTEGER:
+ if (sscanf(data, "%d", &ival) != 1)
{
- message(opts, OPTMSG_ERROR, "Illegal integer value for %s; keeping value of %s\n", astring_c(data->links[0].name), astring_c(data->data));
- data->error_reported = TRUE;
- return;
+ error_string.catprintf("Illegal integer value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.cstr(), curentry.value());
+ return false;
}
- if (i < data->range_minimum.i || i > data->range_maximum.i)
+ if (curentry.has_range() && (ival < atoi(curentry.minimum()) || ival > atoi(curentry.maximum())))
{
- message(opts, OPTMSG_ERROR, "Invalid %s value (must be between %i and %i); keeping value of %s\n",
- astring_c(data->links[0].name), data->range_minimum.i, data->range_maximum.i, astring_c(data->data));
- data->error_reported = TRUE;
- return;
+ error_string.catprintf("Out-of-range integer value for %s: \"%s\" (must be between %s and %s); reverting to %s\n", curentry.name(), data.cstr(), curentry.minimum(), curentry.maximum(), curentry.value());
+ return false;
}
break;
-
- case OPTION_RANGE_FLOAT:
- /* check against float range */
- f = 0;
- if (sscanf(datastart, "%f", &f) != 1)
+
+ // floating-point values must be numeric
+ case OPTION_FLOAT:
+ if (sscanf(data, "%f", &fval) != 1)
{
- message(opts, OPTMSG_ERROR, "Illegal float value for %s; keeping value of %s\n", astring_c(data->links[0].name), astring_c(data->data));
- data->error_reported = TRUE;
- return;
+ error_string.catprintf("Illegal float value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.cstr(), curentry.value());
+ return false;
}
- if (f < data->range_minimum.f || f > data->range_maximum.f)
+ if (curentry.has_range() && (fval < atof(curentry.minimum()) || fval > atof(curentry.maximum())))
{
- message(opts, OPTMSG_ERROR, "Invalid %s value (must be between %f and %f); keeping value of %s\n",
- astring_c(data->links[0].name), data->range_minimum.f, data->range_maximum.f, astring_c(data->data));
- data->error_reported = TRUE;
- return;
+ error_string.catprintf("Out-of-range float value for %s: \"%s\" (must be between %s and %s); reverting to %s\n", curentry.name(), data.cstr(), curentry.minimum(), curentry.maximum(), curentry.value());
+ return false;
}
break;
- }
-
- /* ignore if we don't have priority */
- if (priority < data->priority) {
- return;
- }
- /* allocate a copy of the data */
- astring_cpych(data->data, datastart, dataend + 1 - datastart);
- data->priority = priority;
-
- /* bump the seqid and clear the error reporting */
- data->seqid++;
- data->error_reported = FALSE;
-}
-
-
-/*-------------------------------------------------
- parse_option_name - read data from an option_entry
- name into an option_data structure
--------------------------------------------------*/
-
-static int parse_option_name(core_options *opts, const char *srcstring, options_data *data)
-{
- const char *start;
- const char *end = NULL;
- int curentry;
-
- /* start with the original string and loop over entries */
- start = srcstring;
- for (curentry = 0; curentry < ARRAY_LENGTH(data->links); curentry++)
- {
- /* find the end of this entry and copy the string */
- for (end = start; *end != 0 && *end != ';' && *end != '('; end++)
- ;
- data->links[curentry].name = astring_dupch(start, end - start);
-
- /* if we hit the end of the source, stop */
- if (*end != ';')
+
+ // strings can be anything
+ case OPTION_STRING:
break;
- start = end + 1;
- }
-
- /* have we found a range? */
- if (end != NULL && *end == '(')
- {
- if (sscanf(end, "(%d-%d)", &data->range_minimum.i, &data->range_maximum.i) == 2)
- data->range_type = OPTION_RANGE_INT;
- else if (sscanf(end, "(%f-%f)", &data->range_minimum.f, &data->range_maximum.f) == 2)
- data->range_type = OPTION_RANGE_FLOAT;
- }
- return curentry;
-}
-
-
-/*-------------------------------------------------
- message - outputs a message to a listener
--------------------------------------------------*/
-
-static void message(core_options *opts, options_message msgtype, const char *format, ...)
-{
- char buf[1024];
- va_list argptr;
-
- /* output a message if there is a non-NULL handler for it */
- if (opts->output[msgtype] != NULL)
- {
- va_start(argptr, format);
- vsprintf(buf, format, argptr);
- va_end(argptr);
-
- (*opts->output[msgtype])(buf);
+
+ // anything else is invalid
+ case OPTION_INVALID:
+ case OPTION_HEADER:
+ default:
+ error_string.catprintf("Attempted to set invalid option %s\n", curentry.name());
+ return false;
}
-}
-
-
-/*-------------------------------------------------
- hash_value - computes the hash value for a string
--------------------------------------------------*/
-
-static UINT32 hash_value(core_options *opts, const char *str)
-{
- UINT32 hash = 5381;
- int c;
-
- while ((c = *str++) != 0)
- hash = ((hash << 5) + hash) + c;
-
- return hash % ARRAY_LENGTH(opts->hashtable);
-}
-
-
-/*-------------------------------------------------
- output_printf - outputs an arbitrary message
- to a callback
--------------------------------------------------*/
-
-static void output_printf(void (*output)(const char *s), const char *format, ...)
-{
- char buf[1024];
- va_list argptr;
-
- va_start(argptr, format);
- vsprintf(buf, format, argptr);
- va_end(argptr);
-
- output(buf);
+
+ // set the data
+ curentry.set_value(data, priority);
+ return true;
}