summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/driver.c')
-rw-r--r--src/emu/driver.c482
1 files changed, 289 insertions, 193 deletions
diff --git a/src/emu/driver.c b/src/emu/driver.c
index 582d643168c..d39633d649a 100644
--- a/src/emu/driver.c
+++ b/src/emu/driver.c
@@ -2,10 +2,38 @@
driver.c
- Driver construction helpers.
-
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+ Driver enumeration helpers.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
@@ -14,264 +42,332 @@
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define DRIVER_LRU_SIZE 10
+//**************************************************************************
+// DRIVER LIST
+//**************************************************************************
+//-------------------------------------------------
+// driver_list - constructor
+//-------------------------------------------------
+driver_list::driver_list()
+{
+}
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-static int driver_lru[DRIVER_LRU_SIZE];
+//-------------------------------------------------
+// find - find a driver by name
+//-------------------------------------------------
+int driver_list::find(const char *name)
+{
+ // if no name, bail
+ if (name == NULL)
+ return -1;
+
+ // create a dummy item for comparison purposes
+ game_driver driver;
+ driver.name = name;
+ game_driver *driverptr = &driver;
+
+ // binary search to find it
+ const game_driver **result = reinterpret_cast<const game_driver **>(bsearch(&driverptr, s_drivers_sorted, s_driver_count, sizeof(*s_drivers_sorted), driver_sort_callback));
+ return (result == NULL) ? -1 : result - s_drivers_sorted;
+}
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+//-------------------------------------------------
+// driver_sort_callback - compare two items in
+// an array of game_driver pointers
+//-------------------------------------------------
-static int penalty_compare(const char *source, const char *target);
+int driver_list::driver_sort_callback(const void *elem1, const void *elem2)
+{
+ const game_driver * const *item1 = reinterpret_cast<const game_driver * const *>(elem1);
+ const game_driver * const *item2 = reinterpret_cast<const game_driver * const *>(elem2);
+ return mame_stricmp((*item1)->name, (*item2)->name);
+}
+//-------------------------------------------------
+// penalty_compare - compare two strings for
+// closeness and assign a score.
+//-------------------------------------------------
-/***************************************************************************
- MISC FUNCTIONS
-***************************************************************************/
+int driver_list::penalty_compare(const char *source, const char *target)
+{
+ int gaps = 1;
+ bool last = true;
-/*-------------------------------------------------
- driver_get_name - return a pointer to a
- driver given its name
--------------------------------------------------*/
+ // scan the strings
+ for ( ; *source && *target; target++)
+ {
+ // do a case insensitive match
+ bool match = (tolower((UINT8)*source) == tolower((UINT8)*target));
-const game_driver *driver_get_name(const char *name)
-{
- int lurnum, drvnum;
+ // if we matched, advance the source
+ if (match)
+ source++;
- /* scan the LRU list first */
- for (lurnum = 0; lurnum < DRIVER_LRU_SIZE; lurnum++)
- if (mame_stricmp(drivers[driver_lru[lurnum]]->name, name) == 0)
+ // if the match state changed, count gaps
+ if (match != last)
{
- /* if not first, swap with the head */
- if (lurnum != 0)
- {
- int temp = driver_lru[0];
- driver_lru[0] = driver_lru[lurnum];
- driver_lru[lurnum] = temp;
- }
- return drivers[driver_lru[0]];
+ last = match;
+ if (!match)
+ gaps++;
}
+ }
- /* scan for a match in the drivers -- slow! */
- for (drvnum = 0; drivers[drvnum] != NULL; drvnum++)
- if (mame_stricmp(drivers[drvnum]->name, name) == 0)
- {
- memmove((void *)&driver_lru[1], (void *)&driver_lru[0], sizeof(driver_lru[0]) * (DRIVER_LRU_SIZE - 1));
- driver_lru[0] = drvnum;
- return drivers[drvnum];
- }
+ // penalty if short string does not completely fit in
+ for ( ; *source; source++)
+ gaps++;
+
+ // if we matched perfectly, gaps == 0
+ if (gaps == 1 && *source == 0 && *target == 0)
+ gaps = 0;
- return NULL;
+ return gaps;
}
-/*-------------------------------------------------
- driver_get_clone - return a pointer to the
- clone of a game driver.
--------------------------------------------------*/
-const game_driver *driver_get_clone(const game_driver *driver)
-{
- /* if no clone, easy out */
- if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0))
- return NULL;
+//**************************************************************************
+// DRIVER ENUMERATOR
+//**************************************************************************
- /* convert the name to a game_driver */
- return driver_get_name(driver->parent);
+//-------------------------------------------------
+// driver_enumerator - constructor
+//-------------------------------------------------
+
+driver_enumerator::driver_enumerator(emu_options &options)
+ : m_current(-1),
+ m_filtered_count(0),
+ m_options(options),
+ m_included(global_alloc_array(UINT8, s_driver_count)),
+ m_config(global_alloc_array_clear(machine_config *, s_driver_count))
+{
+ include_all();
}
-/*-------------------------------------------------
- driver_get_searchpath - return a search path
- for a given driver
--------------------------------------------------*/
+driver_enumerator::driver_enumerator(emu_options &options, const char *string)
+ : m_current(-1),
+ m_filtered_count(0),
+ m_options(options),
+ m_included(global_alloc_array(UINT8, s_driver_count)),
+ m_config(global_alloc_array_clear(machine_config *, s_driver_count))
+{
+ filter(string);
+}
+
-const char *driver_get_searchpath(const game_driver &driver, astring &string)
+driver_enumerator::driver_enumerator(emu_options &options, const game_driver &driver)
+ : m_current(-1),
+ m_filtered_count(0),
+ m_options(options),
+ m_included(global_alloc_array(UINT8, s_driver_count)),
+ m_config(global_alloc_array_clear(machine_config *, s_driver_count))
{
- // create the search path consisting of gamedrv[;parent[;...]]
- string = driver.name;
- for (const game_driver *parent = driver_get_clone(&driver); parent != NULL; parent = driver_get_clone(parent))
- string.cat(";").cat(parent->name);
- return string;
+ filter(driver);
}
-/*-------------------------------------------------
- driver_list_get_approx_matches - find the best
- n matches to a driver name.
--------------------------------------------------*/
+//-------------------------------------------------
+// ~driver_enumerator - destructor
+//-------------------------------------------------
-void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list)
+driver_enumerator::~driver_enumerator()
{
-#undef rand
+ // free any configs
+ for (int index = 0; index < s_driver_count; index++)
+ global_free(m_config[index]);
- int matchnum, drvnum;
- int *penalty;
+ // free the arrays
+ global_free(m_included);
+ global_free(m_config);
+}
- /* if no name, pick random entries */
- if (name == NULL || name[0] == 0)
- {
- const game_driver **templist;
- int driver_count;
- int shufnum;
- /* allocate a temporary list */
- templist = global_alloc_array(const game_driver *, driver_list_get_count(driverlist));
+//-------------------------------------------------
+// config - return a machine_config for the given
+// driver, allocating on demand if needed
+//-------------------------------------------------
- /* build up a list of valid entries */
- for (drvnum = driver_count = 0; driverlist[drvnum] != NULL; drvnum++)
- if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) == 0)
- templist[driver_count++] = driverlist[drvnum];
+machine_config &driver_enumerator::config(int index) const
+{
+ assert(index >= 0 && index < s_driver_count);
+ if (m_config[index] == NULL)
+ m_config[index] = global_alloc(machine_config(*s_drivers_sorted[index], m_options));
+ return *m_config[index];
+}
- /* seed the RNG first */
- srand(osd_ticks());
- /* shuffle */
- for (shufnum = 0; shufnum < 4 * driver_count; shufnum++)
- {
- int item1 = rand() % driver_count;
- int item2 = rand() % driver_count;
- const game_driver *temp;
+//-------------------------------------------------
+// filter - filter the driver list against the
+// given string
+//-------------------------------------------------
- temp = templist[item1];
- templist[item1] = templist[item2];
- templist[item2] = temp;
- }
+int driver_enumerator::filter(const char *filterstring)
+{
+ // reset the count
+ exclude_all();
+
+ // match name against each driver in the list
+ for (int index = 0; index < s_driver_count; index++)
+ if (matches(filterstring, s_drivers_sorted[index]->name))
+ include(index);
+
+ return m_filtered_count;
+}
- /* copy out the first few entries */
- for (matchnum = 0; matchnum < matches; matchnum++)
- list[matchnum] = templist[matchnum % driver_count];
- global_free(templist);
- return;
- }
+//-------------------------------------------------
+// filter - filter the driver list against the
+// given driver
+//-------------------------------------------------
- /* allocate some temp memory */
- penalty = global_alloc_array(int, matches);
+int driver_enumerator::filter(const game_driver &driver)
+{
+ // reset the count
+ exclude_all();
+
+ // match name against each driver in the list
+ for (int index = 0; index < s_driver_count; index++)
+ if (s_drivers_sorted[index] == &driver)
+ include(index);
+
+ return m_filtered_count;
+}
- /* initialize everyone's states */
- for (matchnum = 0; matchnum < matches; matchnum++)
- {
- penalty[matchnum] = 9999;
- list[matchnum] = NULL;
- }
- /* scan the entire drivers array */
- for (drvnum = 0; driverlist[drvnum] != NULL; drvnum++)
+//-------------------------------------------------
+// next - get the next driver matching the given
+// filter
+//-------------------------------------------------
+
+bool driver_enumerator::next()
+{
+ // always advance one
+ m_current++;
+
+ // if we have a filter, scan forward to the next match
+ while (m_current < s_driver_count)
{
- int curpenalty, tmp;
+ if (m_included[m_current])
+ break;
+ m_current++;
+ }
- /* skip things that can't run */
- if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) != 0)
- continue;
+ // return true if we end up in range
+ return (m_current >= 0 && m_current < s_driver_count);
+}
- /* pick the best match between driver name and description */
- curpenalty = penalty_compare(name, driverlist[drvnum]->description);
- tmp = penalty_compare(name, driverlist[drvnum]->name);
- curpenalty = MIN(curpenalty, tmp);
- /* insert into the sorted table of matches */
- for (matchnum = matches - 1; matchnum >= 0; matchnum--)
- {
- /* stop if we're worse than the current entry */
- if (curpenalty >= penalty[matchnum])
- break;
+//-------------------------------------------------
+// next_excluded - get the next driver that is
+// not currently included in the list
+//-------------------------------------------------
- /* as lng as this isn't the last entry, bump this one down */
- if (matchnum < matches - 1)
- {
- penalty[matchnum + 1] = penalty[matchnum];
- list[matchnum + 1] = list[matchnum];
- }
- list[matchnum] = driverlist[drvnum];
- penalty[matchnum] = curpenalty;
- }
+bool driver_enumerator::next_excluded()
+{
+ // always advance one
+ m_current++;
+
+ // if we have a filter, scan forward to the next match
+ while (m_current < s_driver_count)
+ {
+ if (!m_included[m_current])
+ break;
+ m_current++;
}
- /* free our temp memory */
- global_free(penalty);
+ // return true if we end up in range
+ return (m_current >= 0 && m_current < s_driver_count);
}
-/*-------------------------------------------------
- penalty_compare - compare two strings for
- closeness and assign a score.
--------------------------------------------------*/
+//-------------------------------------------------
+// driver_sort_callback - compare two items in
+// an array of game_driver pointers
+//-------------------------------------------------
-static int penalty_compare(const char *source, const char *target)
+void driver_enumerator::find_approximate_matches(const char *string, int count, int *results)
{
- int gaps = 1;
- int last = TRUE;
+#undef rand
- /* scan the strings */
- for ( ; *source && *target; target++)
+ // if no name, pick random entries
+ if (string == NULL || string[0] == 0)
{
- /* do a case insensitive match */
- int match = (tolower((UINT8)*source) == tolower((UINT8)*target));
+ // seed the RNG first
+ srand(osd_ticks());
- /* if we matched, advance the source */
- if (match)
- source++;
+ // allocate a temporary list
+ int *templist = global_alloc_array(int, m_filtered_count);
+ int arrayindex = 0;
+ for (int index = 0; index < s_driver_count; index++)
+ if (m_included[index])
+ templist[arrayindex++] = index;
+ assert(arrayindex == m_filtered_count);
- /* if the match state changed, count gaps */
- if (match != last)
+ // shuffle
+ for (int shufnum = 0; shufnum < 4 * s_driver_count; shufnum++)
{
- last = match;
- if (!match)
- gaps++;
+ int item1 = rand() % m_filtered_count;
+ int item2 = rand() % m_filtered_count;
+ int temp = templist[item1];
+ templist[item1] = templist[item2];
+ templist[item2] = temp;
}
- }
-
- /* penalty if short string does not completely fit in */
- for ( ; *source; source++)
- gaps++;
- /* if we matched perfectly, gaps == 0 */
- if (gaps == 1 && *source == 0 && *target == 0)
- gaps = 0;
+ // copy out the first few entries
+ for (int matchnum = 0; matchnum < count; matchnum++)
+ results[matchnum] = templist[matchnum % m_filtered_count];
- return gaps;
-}
+ global_free(templist);
+ return;
+ }
+ // allocate memory to track the penalty value
+ int *penalty = global_alloc_array(int, count);
-/*-------------------------------------------------
- driver_list_get_count - returns the amount of
- drivers
--------------------------------------------------*/
+ // initialize everyone's states
+ for (int matchnum = 0; matchnum < count; matchnum++)
+ {
+ penalty[matchnum] = 9999;
+ results[matchnum] = -1;
+ }
-int driver_list_get_count(const game_driver * const driverlist[])
-{
- int count;
+ // scan the entire drivers array
+ for (int index = 0; index < s_driver_count; index++)
+ if (m_included[index])
+ {
+ // skip things that can't run
+ if ((s_drivers_sorted[index]->flags & GAME_NO_STANDALONE) != 0)
+ continue;
- for (count = 0; driverlist[count] != NULL; count++) ;
- return count;
-}
+ // pick the best match between driver name and description
+ int curpenalty = penalty_compare(string, s_drivers_sorted[index]->description);
+ int tmp = penalty_compare(string, s_drivers_sorted[index]->name);
+ curpenalty = MIN(curpenalty, tmp);
-/*-------------------------------------------------
- driver_get_compatible - return a pointer to the
- compatible driver.
--------------------------------------------------*/
+ // insert into the sorted table of matches
+ for (int matchnum = count - 1; matchnum >= 0; matchnum--)
+ {
+ // stop if we're worse than the current entry
+ if (curpenalty >= penalty[matchnum])
+ break;
+
+ // as long as this isn't the last entry, bump this one down
+ if (matchnum < count - 1)
+ {
+ penalty[matchnum + 1] = penalty[matchnum];
+ results[matchnum + 1] = results[matchnum];
+ }
+ results[matchnum] = index;
+ penalty[matchnum] = curpenalty;
+ }
+ }
-const game_driver *driver_get_compatible(const game_driver *drv)
-{
- if (driver_get_clone(drv))
- drv = driver_get_clone(drv);
- else if (drv->compatible_with)
- drv = driver_get_name(drv->compatible_with);
- else
- drv = NULL;
- return drv;
+ // free our temp memory
+ global_free(penalty);
}