diff options
Diffstat (limited to 'src/emu/driver.c')
-rw-r--r-- | src/emu/driver.c | 482 |
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); } |