diff options
Diffstat (limited to 'src/emu')
36 files changed, 3139 insertions, 2853 deletions
diff --git a/src/emu/audit.c b/src/emu/audit.c index 76b9ab5dbee..1393a335737 100644 --- a/src/emu/audit.c +++ b/src/emu/audit.c @@ -4,8 +4,36 @@ ROM set auditing functions. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + 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. ***************************************************************************/ @@ -17,510 +45,419 @@ #include "sound/samples.h" +//************************************************************************** +// CORE FUNCTIONS +//************************************************************************** -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record); -static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record); -static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ +//------------------------------------------------- +// media_auditor - constructor +//------------------------------------------------- -/*------------------------------------------------- - set_status - shortcut for setting status and - substatus values --------------------------------------------------*/ - -INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus) +media_auditor::media_auditor(const driver_enumerator &enumerator) + : m_enumerator(enumerator), + m_validation(AUDIT_VALIDATE_FULL), + m_searchpath(NULL) { - record->status = status; - record->substatus = substatus; } +//------------------------------------------------- +// audit_media - audit the media described by the +// currently-enumerated driver +//------------------------------------------------- -/*************************************************************************** - CORE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - audit_images - validate the ROM and disk - images for a game --------------------------------------------------*/ - -int audit_images(emu_options &options, const game_driver *gamedrv, const char *validation, audit_record **audit) +media_auditor::summary media_auditor::audit_media(const char *validation) { - machine_config config(*gamedrv, options); - const rom_entry *region, *rom; - const rom_source *source; - audit_record *record; - int anyfound = FALSE; - int anyrequired = FALSE; - int allshared = TRUE; - int records; - - /* determine the number of records we will generate */ - records = 0; - bool source_is_gamedrv = true; - for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - { - for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) - for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) - if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region)) - { - if (source_is_gamedrv && !ROM_ISOPTIONAL(rom)) - { - hash_collection hashes(ROM_GETHASHDATA(rom)); - if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) - { - anyrequired = TRUE; - if (allshared && !rom_used_by_parent(options, gamedrv, hashes, NULL)) - allshared = FALSE; - } - } - records++; - } + // start fresh + m_record_list.reset(); - source_is_gamedrv = false; - } + // store validation for later + m_validation = validation; - if (records > 0) + // iterate over ROM sources and regions + bool anyfound = false; + bool anyrequired = false; + for (const rom_source *source = rom_first_source(m_enumerator.config()); source != NULL; source = rom_next_source(*source)) { - /* allocate memory for the records */ - *audit = global_alloc_array_clear(audit_record, records); - record = *audit; - - /* iterate over ROM sources and regions */ - bool source_is_gamedrv = true; - for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - { - for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + // determine the search path for this source and iterate through the regions + m_searchpath = source->searchpath(); + + // also determine if this is the driver's specific ROMs or not + bool source_is_gamedrv = (dynamic_cast<const driver_device_config_base *>(source) != NULL); + + // now iterate over regions and ROMs within + for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { - const char *regiontag = ROMREGION_ISLOADBYNAME(region) ? ROM_GETNAME(region) : NULL; - for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) - { - /* audit a file */ - if (ROMREGION_ISROMDATA(region)) - { - audit_one_rom(options, rom, regiontag, gamedrv, validation, record); - } - - /* audit a disk */ - else if (ROMREGION_ISDISKDATA(region)) - { - audit_one_disk(options, rom, gamedrv, validation, record); - } - - else - { - continue; - } - - if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(options, gamedrv, record->exphashes, NULL))) - anyfound = TRUE; - - record++; - } + hash_collection hashes(ROM_GETHASHDATA(rom)); + + // if a dump exists, then at least one entry is required + if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) + anyrequired = true; + + // audit a file + audit_record *record = NULL; + if (ROMREGION_ISROMDATA(region)) + record = audit_one_rom(rom); + + // audit a disk + else if (ROMREGION_ISDISKDATA(region)) + record = audit_one_disk(rom); + + // skip if no record + if (record == NULL) + continue; + + // if we got a record back, + if (record->status() != audit_record::STATUS_NOT_FOUND && source_is_gamedrv && also_used_by_parent(hashes) == -1) + anyfound = true; } - source_is_gamedrv = false; - } } - /* if we found nothing, we don't have the set at all */ + // if we found nothing, we don't have the set at all if (!anyfound && anyrequired) - { - global_free(*audit); - *audit = NULL; - records = 0; - } - - return records; + m_record_list.reset(); + + // return a summary + return summarize(); } -/*------------------------------------------------- - audit_samples - validate the samples for a - game --------------------------------------------------*/ +//------------------------------------------------- +// audit_samples - validate the samples for the +// currently-enumerated driver +//------------------------------------------------- -int audit_samples(emu_options &options, const game_driver *gamedrv, audit_record **audit) +media_auditor::summary media_auditor::audit_samples() { - machine_config config(*gamedrv, options); - audit_record *record; - int records = 0; - int sampnum; - - /* count the number of sample records attached to this driver */ - const device_config_sound_interface *sound = NULL; - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) - { - const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config(); - - if (intf->samplenames != NULL) - { - /* iterate over samples in this entry */ - for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) - if (intf->samplenames[sampnum][0] != '*') - records++; - } - } - - /* if no records, just quit now */ - if (records == 0) - goto skip; - - /* allocate memory for the records */ - *audit = global_alloc_array_clear(audit_record, records); - record = *audit; + // start fresh + m_record_list.reset(); - /* now iterate over sample entries */ - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) + // iterate over sample entries + for (const device_config *devconfig = m_enumerator.config().first_device(); devconfig != NULL; devconfig = devconfig->next()) + if (devconfig->type() == SAMPLES) { - const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config(); - const char *sharedname = NULL; - + const samples_interface *intf = reinterpret_cast<const samples_interface *>(devconfig->static_config()); if (intf->samplenames != NULL) { - /* iterate over samples in this entry */ - for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) + // by default we just search using the driver name + astring searchpath(m_enumerator.driver().name); + + // iterate over samples in this entry + for (int sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) + { + // starred entries indicate an additional searchpath if (intf->samplenames[sampnum][0] == '*') - sharedname = &intf->samplenames[sampnum][1]; - else { - /* attempt to access the file from the game driver name */ - emu_file file(options.sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - file_error filerr = file.open(gamedrv->name, PATH_SEPARATOR, intf->samplenames[sampnum]); - - /* attempt to access the file from the shared driver name */ - if (filerr != FILERR_NONE && sharedname != NULL) - filerr = file.open(sharedname, PATH_SEPARATOR, intf->samplenames[sampnum]); - - /* fill in the record */ - record->type = AUDIT_FILE_SAMPLE; - record->name = intf->samplenames[sampnum]; + searchpath.cat(";").cat(&intf->samplenames[sampnum][1]); + continue; + } + + // create a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(intf->samplenames[sampnum], audit_record::MEDIA_SAMPLE))); + + // look for the files + emu_file file(m_enumerator.options().sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); + path_iterator path(searchpath); + astring curpath; + while (path.next(curpath, intf->samplenames[sampnum])) + { + // attempt to access the file + file_error filerr = file.open(curpath); if (filerr == FILERR_NONE) - set_status(record++, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD); else - set_status(record++, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND); } + } } } - -skip: - return records; + + // return a summary + return summarize(); } -/*------------------------------------------------- - audit_summary - output a summary given a - list of audit records --------------------------------------------------*/ +//------------------------------------------------- +// summary - generate a summary, with an optional +// string format +//------------------------------------------------- -int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output) +media_auditor::summary media_auditor::summarize(astring *string) { - int overall_status = CORRECT; - int recnum; - - /* no count AND no records means not found */ - if (count == 0 && records == NULL) + // no count AND no records means not found + if (m_record_list.count() == 0) return NOTFOUND; - /* loop over records */ - for (recnum = 0; recnum < count; recnum++) + // loop over records + summary overall_status = CORRECT; + for (audit_record *record = m_record_list.first(); record != NULL; record = record->next()) { - const audit_record *record = &records[recnum]; - int best_new_status = INCORRECT; + summary best_new_status = INCORRECT; - /* skip anything that's fine */ - if (record->substatus == SUBSTATUS_GOOD) + // skip anything that's fine + if (record->substatus() == audit_record::SUBSTATUS_GOOD) continue; - /* output the game name, file name, and length (if applicable) */ - if (output) + // output the game name, file name, and length (if applicable) + if (string != NULL) { - mame_printf_info("%-8s: %s", gamedrv->name, record->name); - if (record->explength > 0) - mame_printf_info(" (%d bytes)", record->explength); - mame_printf_info(" - "); + string->catprintf("%-12s: %s", m_enumerator.driver().name, record->name()); + if (record->expected_length() > 0) + string->catprintf(" (%d bytes)", record->expected_length()); + string->catprintf(" - "); } - /* use the substatus for finer details */ - switch (record->substatus) + // use the substatus for finer details + switch (record->substatus()) { - case SUBSTATUS_GOOD_NEEDS_REDUMP: - if (output) mame_printf_info("NEEDS REDUMP\n"); + case audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP: + if (string != NULL) string->catprintf("NEEDS REDUMP\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_FOUND_NODUMP: - if (output) mame_printf_info("NO GOOD DUMP KNOWN\n"); + case audit_record::SUBSTATUS_FOUND_NODUMP: + if (string != NULL) string->catprintf("NO GOOD DUMP KNOWN\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_FOUND_BAD_CHECKSUM: - if (output) + case audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM: + if (string != NULL) { astring tempstr; - mame_printf_info("INCORRECT CHECKSUM:\n"); - mame_printf_info("EXPECTED: %s\n", record->exphashes.macro_string(tempstr)); - mame_printf_info(" FOUND: %s\n", record->hashes.macro_string(tempstr)); + string->catprintf("INCORRECT CHECKSUM:\n"); + string->catprintf("EXPECTED: %s\n", record->expected_hashes().macro_string(tempstr)); + string->catprintf(" FOUND: %s\n", record->actual_hashes().macro_string(tempstr)); } break; - case SUBSTATUS_FOUND_WRONG_LENGTH: - if (output) mame_printf_info("INCORRECT LENGTH: %d bytes\n", record->length); + case audit_record::SUBSTATUS_FOUND_WRONG_LENGTH: + if (string != NULL) string->catprintf("INCORRECT LENGTH: %d bytes\n", record->actual_length()); break; - case SUBSTATUS_NOT_FOUND: - if (output) mame_printf_info("NOT FOUND\n"); + case audit_record::SUBSTATUS_NOT_FOUND: + if (string != NULL) string->catprintf("NOT FOUND\n"); break; - case SUBSTATUS_NOT_FOUND_NODUMP: - if (output) mame_printf_info("NOT FOUND - NO GOOD DUMP KNOWN\n"); + case audit_record::SUBSTATUS_NOT_FOUND_NODUMP: + if (string != NULL) string->catprintf("NOT FOUND - NO GOOD DUMP KNOWN\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_NOT_FOUND_OPTIONAL: - if (output) mame_printf_info("NOT FOUND BUT OPTIONAL\n"); + case audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL: + if (string != NULL) string->catprintf("NOT FOUND BUT OPTIONAL\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_NOT_FOUND_PARENT: - if (output) mame_printf_info("NOT FOUND (shared with parent)\n"); + case audit_record::SUBSTATUS_NOT_FOUND_PARENT: + if (string != NULL) string->catprintf("NOT FOUND (shared with parent)\n"); break; - case SUBSTATUS_NOT_FOUND_BIOS: - if (output) mame_printf_info("NOT FOUND (BIOS)\n"); + case audit_record::SUBSTATUS_NOT_FOUND_BIOS: + if (string != NULL) string->catprintf("NOT FOUND (BIOS)\n"); break; + + default: + assert(false); } - /* downgrade the overall status if necessary */ + // downgrade the overall status if necessary overall_status = MAX(overall_status, best_new_status); } - return overall_status; } +//------------------------------------------------- +// audit_one_rom - validate a single ROM entry +//------------------------------------------------- -/*************************************************************************** - UTILITIES -***************************************************************************/ - -/*------------------------------------------------- - audit_one_rom - validate a single ROM entry --------------------------------------------------*/ - -static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record) +audit_record *media_auditor::audit_one_rom(const rom_entry *rom) { - const game_driver *drv; - UINT32 crc = 0; + // allocate and append a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_ROM))); - /* fill in the record basics */ - record->type = AUDIT_FILE_ROM; - record->name = ROM_GETNAME(rom); - record->exphashes.from_internal_string(ROM_GETHASHDATA(rom)); - record->length = 0; - record->explength = rom_file_size(rom); - - /* see if we have a CRC and extract it if so */ - bool has_crc = record->exphashes.crc(crc); + // see if we have a CRC and extract it if so + UINT32 crc = 0; + bool has_crc = record.expected_hashes().crc(crc); - /* find the file and checksum it, getting the file length along the way */ - for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv)) + // find the file and checksum it, getting the file length along the way + emu_file file(m_enumerator.options().media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); + path_iterator path(m_searchpath); + astring curpath; + while (path.next(curpath, record.name())) { - emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - - /* open the file if we can */ + // open the file if we can file_error filerr; if (has_crc) - filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom), crc); + filerr = file.open(curpath, crc); else - filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom)); + filerr = file.open(curpath); + + // if it worked, get the actual length and hashes, then stop if (filerr == FILERR_NONE) { - record->hashes = file.hashes(validation); - record->length = (UINT32)file.size(); + record.set_actual(file.hashes(m_validation), file.size()); break; } } + + // compute the final status + compute_status(record, rom, record.actual_length() != 0); + return &record; +} - /* if not found, check the region as a backup */ - if (record->length == 0 && regiontag != NULL) - { - emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - - /* open the file if we can */ - file_error filerr; - if (has_crc) - filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom), crc); - else - filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom)); - if (filerr == FILERR_NONE) - { - record->hashes = file.hashes(validation); - record->length = (UINT32)file.size(); - } - } - - /* if we failed to find the file, set the appropriate status */ - if (record->length == 0) - { - const game_driver *parent; - - /* no good dump */ - if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP); - - /* optional ROM */ - else if (ROM_ISOPTIONAL(rom)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL); - /* not found and used by parent */ - else if (rom_used_by_parent(options, gamedrv, record->exphashes, &parent)) - set_status(record, AUDIT_STATUS_NOT_FOUND, (parent->flags & GAME_IS_BIOS_ROOT) ? SUBSTATUS_NOT_FOUND_BIOS : SUBSTATUS_NOT_FOUND_PARENT); +//------------------------------------------------- +// audit_one_disk - validate a single disk entry +//------------------------------------------------- - /* just plain old not found */ - else - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); - } +audit_record *media_auditor::audit_one_disk(const rom_entry *rom) +{ + // allocate and append a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_DISK))); - /* if we did find the file, do additional verification */ - else + // open the disk + emu_file *source_file; + chd_file *source; + chd_error err = open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, &source_file, &source, NULL); + + // if we succeeded, get the hashes + if (err == CHDERR_NONE) { - /* length mismatch */ - if (record->explength != record->length) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH); - - /* found but needs a dump */ - else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP); - - /* incorrect hash */ - else if (record->exphashes != record->hashes) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM); + static const UINT8 nullhash[20] = { 0 }; + chd_header header = *chd_get_header(source); + hash_collection hashes; - /* correct hash but needs a redump */ - else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP); + // if there's an MD5 or SHA1 hash, add them to the output hash + if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) + hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); + if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) + hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + + // update the actual values + record.set_actual(hashes); - /* just plain old good */ - else - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); + // close the file and release the source + chd_close(source); + global_free(source_file); } + + // compute the final status + compute_status(record, rom, record.actual_length() != 0); + return &record; } -/*------------------------------------------------- - audit_one_disk - validate a single disk entry --------------------------------------------------*/ +//------------------------------------------------- +// compute_status - compute a detailed status +// based on the information we have +//------------------------------------------------- -static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record) +void media_auditor::compute_status(audit_record &record, const rom_entry *rom, bool found) { - emu_file *source_file; - chd_file *source; - chd_error err; - - /* fill in the record basics */ - record->type = AUDIT_FILE_DISK; - record->name = ROM_GETNAME(rom); - record->exphashes.from_internal_string(ROM_GETHASHDATA(rom)); - - /* open the disk */ - err = open_disk_image(options, gamedrv, rom, &source_file, &source, NULL); - - /* if we failed, report the error */ - if (err != CHDERR_NONE) + // if not found, provide more details + if (!found) { - /* out of memory */ - if (err == CHDERR_OUT_OF_MEMORY) - set_status(record, AUDIT_STATUS_ERROR, SUBSTATUS_ERROR); + int parent; + + // no good dump + if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP)) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_NODUMP); - /* not found but it's not good anyway */ - else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP); + // optional ROM + else if (ROM_ISOPTIONAL(rom)) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL); - /* not found but optional */ - else if (DISK_ISOPTIONAL(rom)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL); + // not found and used by parent + else if ((parent = also_used_by_parent(record.expected_hashes())) != -1) + { + if (m_enumerator.driver(parent).flags & GAME_IS_BIOS_ROOT) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_BIOS); + else + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_PARENT); + } - /* not found at all */ + // just plain old not found else - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND); } - - /* if we succeeded, validate it */ + + // if found, provide more details else { - static const UINT8 nullhash[20] = { 0 }; - chd_header header = *chd_get_header(source); - - /* if there's an MD5 or SHA1 hash, add them to the output hash */ - if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) - record->hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); - if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) - record->hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + // length mismatch + if (record.expected_length() != record.actual_length()) + record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_WRONG_LENGTH); - /* found but needs a dump */ - if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP); + // found but needs a dump + else if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP)) + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_FOUND_NODUMP); - /* incorrect hash */ - else if (record->exphashes != record->hashes) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM); + // incorrect hash + else if (record.expected_hashes() != record.actual_hashes()) + record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM); - /* correct hash but needs a redump */ - else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP); + // correct hash but needs a redump + else if (record.expected_hashes().flag(hash_collection::FLAG_BAD_DUMP)) + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP); - /* just plain good */ + // just plain old good else - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); - - chd_close(source); - global_free(source_file); + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD); } } -/*------------------------------------------------- - rom_used_by_parent - determine if a given - ROM is also used by the parent --------------------------------------------------*/ +//------------------------------------------------- +// also_used_by_parent - return the index in the +// enumerator of the parent who also owns a media +// entry with the same hashes +//------------------------------------------------- -static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent) +int media_auditor::also_used_by_parent(const hash_collection &romhashes) { - const game_driver *drv; + // iterate up the parent chain + for (int drvindex = m_enumerator.find(m_enumerator.driver().parent); drvindex != -1; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent)) - /* iterate up the parent chain */ - for (drv = driver_get_clone(gamedrv); drv != NULL; drv = driver_get_clone(drv)) - { - machine_config config(*drv, options); - const rom_entry *region; - const rom_entry *rom; - - /* see if the parent has the same ROM or not */ - for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - for (region = rom_first_region(*source); region; region = rom_next_region(region)) - for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) + // see if the parent has the same ROM or not + for (const rom_source *source = rom_first_source(m_enumerator.config(drvindex)); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { hash_collection hashes(ROM_GETHASHDATA(rom)); if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes) - { - if (parent != NULL) - *parent = drv; - return TRUE; - } + return drvindex; } - } - return FALSE; + // nope, return -1 + return -1; +} + + +//------------------------------------------------- +// audit_record - constructor +//------------------------------------------------- + +audit_record::audit_record(const rom_entry &media, media_type type) + : m_next(NULL), + m_type(type), + m_status(STATUS_ERROR), + m_substatus(SUBSTATUS_ERROR), + m_name(ROM_GETNAME(&media)), + m_explength(rom_file_size(&media)), + m_length(0) +{ + m_exphashes.from_internal_string(ROM_GETHASHDATA(&media)); +} + +audit_record::audit_record(const char *name, media_type type) + : m_next(NULL), + m_type(type), + m_status(STATUS_ERROR), + m_substatus(SUBSTATUS_ERROR), + m_name(name), + m_explength(0), + m_length(0) +{ } diff --git a/src/emu/audit.h b/src/emu/audit.h index 3b6eaffd4a2..00964e91417 100644 --- a/src/emu/audit.h +++ b/src/emu/audit.h @@ -4,8 +4,36 @@ ROM, disk, and sample auditing functions. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + 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. ***************************************************************************/ @@ -18,84 +46,145 @@ -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -/* hashes to use for validation */ +// hashes to use for validation #define AUDIT_VALIDATE_FAST "R" /* CRC only */ #define AUDIT_VALIDATE_FULL "RS" /* CRC + SHA1 */ -/* return values from audit_verify_roms and audit_verify_samples */ -enum -{ - CORRECT = 0, - BEST_AVAILABLE, - INCORRECT, - NOTFOUND -}; -/* image types for audit_record.type */ -enum -{ - AUDIT_FILE_ROM = 0, - AUDIT_FILE_DISK, - AUDIT_FILE_SAMPLE -}; -/* status values for audit_record.status */ -enum -{ - AUDIT_STATUS_GOOD = 0, - AUDIT_STATUS_FOUND_INVALID, - AUDIT_STATUS_NOT_FOUND, - AUDIT_STATUS_ERROR -}; +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** -/* substatus values for audit_record.substatus */ -enum -{ - SUBSTATUS_GOOD = 0, - SUBSTATUS_GOOD_NEEDS_REDUMP, - SUBSTATUS_FOUND_NODUMP, - SUBSTATUS_FOUND_BAD_CHECKSUM, - SUBSTATUS_FOUND_WRONG_LENGTH, - SUBSTATUS_NOT_FOUND, - SUBSTATUS_NOT_FOUND_NODUMP, - SUBSTATUS_NOT_FOUND_OPTIONAL, - SUBSTATUS_NOT_FOUND_PARENT, - SUBSTATUS_NOT_FOUND_BIOS, - SUBSTATUS_ERROR = 100 -}; +// ======================> audit_record - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -typedef struct _audit_record audit_record; -struct _audit_record +// holds the result of auditing a single item +class audit_record { - UINT8 type; /* type of item that was audited */ - UINT8 status; /* status of audit on this item */ - UINT8 substatus; /* finer-detail status */ - const char * name; /* name of item */ - UINT32 explength; /* expected length of item */ - UINT32 length; /* actual length of item */ - hash_collection exphashes; /* expected hash data */ - hash_collection hashes; /* actual hash information */ + friend class simple_list<audit_record>; + +public: + // media types + enum media_type + { + MEDIA_ROM = 0, + MEDIA_DISK, + MEDIA_SAMPLE + }; + + // status values + enum audit_status + { + STATUS_GOOD = 0, + STATUS_FOUND_INVALID, + STATUS_NOT_FOUND, + STATUS_ERROR + }; + + // substatus values + enum audit_substatus + { + SUBSTATUS_GOOD = 0, + SUBSTATUS_GOOD_NEEDS_REDUMP, + SUBSTATUS_FOUND_NODUMP, + SUBSTATUS_FOUND_BAD_CHECKSUM, + SUBSTATUS_FOUND_WRONG_LENGTH, + SUBSTATUS_NOT_FOUND, + SUBSTATUS_NOT_FOUND_NODUMP, + SUBSTATUS_NOT_FOUND_OPTIONAL, + SUBSTATUS_NOT_FOUND_PARENT, + SUBSTATUS_NOT_FOUND_BIOS, + SUBSTATUS_ERROR = 100 + }; + + // construction/destruction + audit_record(const rom_entry &media, media_type type); + audit_record(const char *name, media_type type); + + // getters + audit_record *next() const { return m_next; } + media_type type() const { return m_type; } + audit_status status() const { return m_status; } + audit_substatus substatus() const { return m_substatus; } + const char *name() const { return m_name; } + UINT64 expected_length() const { return m_explength; } + UINT64 actual_length() const { return m_length; } + const hash_collection &expected_hashes() const { return m_exphashes; } + const hash_collection &actual_hashes() const { return m_hashes; } + + // setters + void set_status(audit_status status, audit_substatus substatus) + { + m_status = status; + m_substatus = substatus; + } + + void set_actual(const hash_collection &hashes, UINT64 length = 0) + { + m_hashes = hashes; + m_length = length; + } + +private: + // internal state + audit_record * m_next; + media_type m_type; /* type of item that was audited */ + audit_status m_status; /* status of audit on this item */ + audit_substatus m_substatus; /* finer-detail status */ + const char * m_name; /* name of item */ + UINT64 m_explength; /* expected length of item */ + UINT64 m_length; /* actual length of item */ + hash_collection m_exphashes; /* expected hash data */ + hash_collection m_hashes; /* actual hash information */ }; +// ======================> media_auditor -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -int audit_images(emu_options &options, const game_driver *gamedrv, const char *validation, audit_record **audit); -int audit_samples(emu_options &options, const game_driver *gamedrv, audit_record **audit); -int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output); +// class which manages auditing of items +class media_auditor +{ +public: + // summary values + enum summary + { + CORRECT = 0, + NONE_NEEDED, + BEST_AVAILABLE, + INCORRECT, + NOTFOUND + }; + + // construction/destruction + media_auditor(const driver_enumerator &enumerator); + + // getters + audit_record *first() const { return m_record_list.first(); } + int count() const { return m_record_list.count(); } + + // audit operations + summary audit_media(const char *validation = AUDIT_VALIDATE_FULL); + summary audit_samples(); + summary summarize(astring *output = NULL); + +private: + // internal helpers + audit_record *audit_one_rom(const rom_entry *rom); + audit_record *audit_one_disk(const rom_entry *rom); + void compute_status(audit_record &record, const rom_entry *rom, bool found); + int also_used_by_parent(const hash_collection &romhashes); + + // internal state + simple_list<audit_record> m_record_list; + const driver_enumerator & m_enumerator; + const char * m_validation; + const char * m_searchpath; +}; #endif /* __AUDIT_H__ */ diff --git a/src/emu/clifront.c b/src/emu/clifront.c index 81435650c34..6035aa0e77f 100644 --- a/src/emu/clifront.c +++ b/src/emu/clifront.c @@ -56,42 +56,6 @@ #endif -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct romident_status -{ - int total; /* total files processed */ - int matches; /* number of matches found */ - int nonroms; /* number of non-ROM files found */ -}; - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void execute_commands(cli_options &options, const char *exename); -static void display_help(void); - -/* informational functions */ -static void info_verifyroms(emu_options &options, const char *gamename); -static void info_verifysamples(emu_options &options, const char *gamename); -static void info_romident(emu_options &options, const char *gamename); -static void info_listmedia(emu_options &options, const char *gamename); -static void info_listsoftware(emu_options &options, const char *gamename); - -/* utilities */ -static void romident(emu_options &options, const char *filename, romident_status *status); -static void identify_file(emu_options &options, const char *name, romident_status *status); -static void identify_data(emu_options &options, const char *name, const UINT8 *data, int length, romident_status *status); -static void match_roms(emu_options &options, const hash_collection &hashes, int length, int *found); -static void display_suggestions(const char *gamename); - - - //************************************************************************** // COMMAND-LINE OPTIONS //************************************************************************** @@ -146,45 +110,55 @@ cli_options::cli_options() -/*************************************************************************** - CORE IMPLEMENTATION -***************************************************************************/ +//************************************************************************** +// CLI FRONTEND +//************************************************************************** + +//------------------------------------------------- +// cli_frontend - constructor +//------------------------------------------------- + +cli_frontend::cli_frontend(cli_options &options, osd_interface &osd) + : m_options(options), + m_osd(osd), + m_result(MAMERR_NONE) +{ + // begin tracking memory + track_memory(true); +} + + +//------------------------------------------------- +// ~cli_frontend - destructor +//------------------------------------------------- -static void display_suggestions(const char *gamename) +cli_frontend::~cli_frontend() { - const game_driver *matches[10]; - int drvnum; - - /* get the top 10 approximate matches */ - driver_list_get_approx_matches(drivers, gamename, ARRAY_LENGTH(matches), matches); - - /* print them out */ - fprintf(stderr, "\n\"%s\" approximately matches the following\n" - "supported " GAMESNOUN " (best match first):\n\n", gamename); - for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++) - if (matches[drvnum] != NULL) - fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description); + // report any unfreed memory on clean exits + track_memory(false); + if (m_result == MAMERR_NONE) + dump_unfreed_mem(); } //------------------------------------------------- -// cli_execute - execute a game via the standard +// execute - execute a game via the standard // command line interface //------------------------------------------------- -int cli_execute(cli_options &options, osd_interface &osd, int argc, char **argv) +int cli_frontend::execute(int argc, char **argv) { // wrap the core execution in a try/catch to field all fatal errors - int result = MAMERR_NONE; + m_result = MAMERR_NONE; try { // parse the command line, adding any system-specific options astring option_errors; - if (!options.parse_command_line(argc, argv, option_errors)) + if (!m_options.parse_command_line(argc, argv, option_errors)) { // if we failed, check for no command and a system name first; in that case error on the name - if (strlen(options.command()) == 0 && options.system() == NULL && strlen(options.system_name()) > 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", options.system_name()); + if (strlen(m_options.command()) == 0 && m_options.system() == NULL && strlen(m_options.system_name()) > 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); // otherwise, error on the options throw emu_fatalerror(MAMERR_INVALID_CONFIG, "%s", option_errors.trimspace().cstr()); @@ -197,19 +171,19 @@ int cli_execute(cli_options &options, osd_interface &osd, int argc, char **argv) core_filename_extract_base(&exename, argv[0], TRUE); // if we have a command, execute that - if (strlen(options.command()) != 0) - execute_commands(options, exename); + if (strlen(m_options.command()) != 0) + execute_commands(exename); // otherwise, check for a valid system else { // if we can't find it, give an appropriate error - const game_driver *system = options.system(); - if (system == NULL && strlen(options.system_name()) > 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", options.system_name()); + const game_driver *system = m_options.system(); + if (system == NULL && strlen(m_options.system_name()) > 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); // otherwise just run the game - result = mame_execute(options, osd); + m_result = mame_execute(m_options, m_osd); } } @@ -218,577 +192,605 @@ int cli_execute(cli_options &options, osd_interface &osd, int argc, char **argv) { astring string(fatal.string()); fprintf(stderr, "%s\n", string.trimspace().cstr()); - result = (fatal.exitcode() != 0) ? fatal.exitcode() : MAMERR_FATALERROR; + m_result = (fatal.exitcode() != 0) ? fatal.exitcode() : MAMERR_FATALERROR; // if a game was specified, wasn't a wildcard, and our error indicates this was the // reason for failure, offer some suggestions - if (result == MAMERR_NO_SUCH_GAME && strlen(options.system_name()) > 0 && strchr(options.system_name(), '*') == NULL && options.system() == NULL) - display_suggestions(options.system_name()); + if (m_result == MAMERR_NO_SUCH_GAME && strlen(m_options.system_name()) > 0 && strchr(m_options.system_name(), '*') == NULL && m_options.system() == NULL) + { + // get the top 10 approximate matches + driver_enumerator drivlist(m_options); + int matches[10]; + drivlist.find_approximate_matches(m_options.system_name(), ARRAY_LENGTH(matches), matches); + + // print them out + fprintf(stderr, "\n\"%s\" approximately matches the following\n" + "supported " GAMESNOUN " (best match first):\n\n", m_options.system_name()); + for (int matchnum = 0; matchnum < ARRAY_LENGTH(matches); matchnum++) + if (matches[matchnum] != -1) + fprintf(stderr, "%-18s%s\n", drivlist.driver(matches[matchnum]).name, drivlist.driver(matches[matchnum]).description); + } } catch (emu_exception &) { fprintf(stderr, "Caught unhandled emulator exception\n"); - result = MAMERR_FATALERROR; + m_result = MAMERR_FATALERROR; } catch (std::bad_alloc &) { fprintf(stderr, "Out of memory!\n"); - result = MAMERR_FATALERROR; + m_result = MAMERR_FATALERROR; } // handle any other exceptions catch (...) { fprintf(stderr, "Caught unhandled exception\n"); - result = MAMERR_FATALERROR; + m_result = MAMERR_FATALERROR; } - // report any unfreed memory on clean exits - if (result == MAMERR_NONE) - dump_unfreed_mem(); - return result; + return m_result; } //------------------------------------------------- -// execute_commands - execute various frontend -// commands +// listxml - output the XML data for one or more +// games //------------------------------------------------- -static void execute_commands(cli_options &options, const char *exename) +void cli_frontend::listxml(const char *gamename) { - // help? - if (strcmp(options.command(), CLICOMMAND_HELP) == 0) - { - display_help(); - return; - } - - // showusage? - if (strcmp(options.command(), CLICOMMAND_SHOWUSAGE) == 0) - { - astring helpstring; -#ifndef MESS - mame_printf_info("Usage: %s [%s] [options]\n\nOptions:\n%s", exename, GAMENOUN, options.output_help(helpstring)); -#else - mame_printf_info("Usage: %s [%s] [media] [software] [options]\n\nOptions:\n%s", exename, GAMENOUN, options.output_help(helpstring)); -#endif - return; - } - - // validate? - if (strcmp(options.command(), CLICOMMAND_VALIDATE) == 0) - { - validate_drivers(options); - return; - } - - // other commands need the INIs parsed - astring option_errors; - options.parse_standard_inis(option_errors); - if (option_errors) - printf("%s\n", option_errors.cstr()); - - // createconfig? - if (strcmp(options.command(), CLICOMMAND_CREATECONFIG) == 0) - { - // attempt to open the output file - emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(CONFIGNAME ".ini") != FILERR_NONE) - throw emu_fatalerror("Unable to create file " CONFIGNAME ".ini\n"); - - // generate the updated INI - astring initext; - file.puts(options.output_ini(initext)); - return; - } - - // showconfig? - if (strcmp(options.command(), CLICOMMAND_SHOWCONFIG) == 0) - { - // print the INI text - astring initext; - printf("%s\n", options.output_ini(initext)); - return; - } - - // all other commands call out to one of these helpers - static const struct - { - const char *option; - void (*function)(emu_options &options, const char *gamename); - } info_commands[] = - { - { CLICOMMAND_LISTXML, cli_info_listxml }, - { CLICOMMAND_LISTFULL, cli_info_listfull }, - { CLICOMMAND_LISTSOURCE, cli_info_listsource }, - { CLICOMMAND_LISTCLONES, cli_info_listclones }, - { CLICOMMAND_LISTBROTHERS, cli_info_listbrothers }, - { CLICOMMAND_LISTCRC, cli_info_listcrc }, - { CLICOMMAND_LISTDEVICES, cli_info_listdevices }, - { CLICOMMAND_LISTROMS, cli_info_listroms }, - { CLICOMMAND_LISTSAMPLES, cli_info_listsamples }, - { CLICOMMAND_VERIFYROMS, info_verifyroms }, - { CLICOMMAND_VERIFYSAMPLES, info_verifysamples }, - { CLICOMMAND_LISTMEDIA, info_listmedia }, - { CLICOMMAND_LISTSOFTWARE, info_listsoftware }, - { CLICOMMAND_ROMIDENT, info_romident } - }; - - // find the command - for (int cmdindex = 0; cmdindex < ARRAY_LENGTH(info_commands); cmdindex++) - if (strcmp(options.command(), info_commands[cmdindex].option) == 0) - { - // parse any relevant INI files before proceeding - const char *sysname = options.system_name(); - (*info_commands[cmdindex].function)(options, (sysname[0] == 0) ? "*" : sysname); - return; - } + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - // if we get here, we don't know what has been requested - throw emu_fatalerror(MAMERR_INVALID_CONFIG, "Unknown command '%s' specified", options.command()); + // create the XML and print it to stdout + info_xml_creator creator(drivlist); + creator.output(stdout); } -/*------------------------------------------------- - display_help - display help to standard - output --------------------------------------------------*/ - -static void display_help(void) +//------------------------------------------------- +// listfull - output the name and description of +// one or more games +//------------------------------------------------- + +void cli_frontend::listfull(const char *gamename) { -#ifndef MESS - mame_printf_info("M.A.M.E. v%s - Multiple Arcade Machine Emulator\n" - "Copyright Nicola Salmoria and the MAME Team\n\n", build_version); - mame_printf_info("%s\n", mame_disclaimer); - mame_printf_info("Usage: MAME gamename [options]\n\n" - " MAME -showusage for a brief list of options\n" - " MAME -showconfig for a list of configuration options\n" - " MAME -createconfig to create a " CONFIGNAME ".ini\n\n" - "For usage instructions, please consult the file windows.txt\n"); -#else - mess_display_help(); -#endif -} - - - -/*************************************************************************** - INFORMATIONAL FUNCTIONS -***************************************************************************/ + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); -/*------------------------------------------------- - cli_info_listxml - output the XML data for one - or more games --------------------------------------------------*/ + // print the header + mame_printf_info("Name: Description:\n"); -void cli_info_listxml(emu_options &options, const char *gamename) -{ - print_mame_xml(stdout, drivers, gamename, options); + // iterate through drivers and output the info + while (drivlist.next()) + if ((drivlist.driver().flags & GAME_NO_STANDALONE) == 0) + mame_printf_info("%-18s\"%s\"\n", drivlist.driver().name, drivlist.driver().description); } -/*------------------------------------------------- - cli_info_listfull - output the name and - description of one or more games --------------------------------------------------*/ +//------------------------------------------------- +// listsource - output the name and source +// filename of one or more games +//------------------------------------------------- -void cli_info_listfull(emu_options &options, const char *gamename) +void cli_frontend::listsource(const char *gamename) { - int count = 0; - - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if ((drivers[drvindex]->flags & GAME_NO_STANDALONE) == 0 && mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - /* print the header on the first one */ - if (count == 0) - mame_printf_info("Name: Description:\n"); - - /* output the remaining information */ - mame_printf_info("%-18s\"%s\"\n", drivers[drvindex]->name, drivers[drvindex]->description); - count++; - } - - /* return an error if none found */ - if (count == 0) + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + + // iterate through drivers and output the info + astring filename; + while (drivlist.next()) + mame_printf_info("%-16s %s\n", drivlist.driver().name, core_filename_extract_base(&filename, drivlist.driver().source_file, FALSE)->cstr()); } -/*------------------------------------------------- - cli_info_listsource - output the name and source - filename of one or more games --------------------------------------------------*/ +//------------------------------------------------- +// listclones - output the name and parent of all +// clones matching the given pattern +//------------------------------------------------- -void cli_info_listsource(emu_options &options, const char *gamename) +void cli_frontend::listclones(const char *gamename) { - int count = 0; - astring filename; + // start with a filtered list of drivers + driver_enumerator drivlist(m_options, gamename); + int original_count = drivlist.count(); + + // iterate through the remaining ones to see if their parent matches + while (drivlist.next_excluded()) + { + // if we have a non-bios clone and it matches, keep it + int clone_of = drivlist.clone(); + if (clone_of != -1 && (drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT) == 0) + if (drivlist.matches(gamename, drivlist.driver(clone_of).name)) + drivlist.include(); + } + + // return an error if none found + if (drivlist.count() == 0) + { + // see if we match but just weren't a clone + if (original_count == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + else + mame_printf_info("Found %d matches for '%s' but none were clones\n", drivlist.count(), gamename); + return; + } - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - /* output the remaining information */ - mame_printf_info("%-16s %s\n", drivers[drvindex]->name, core_filename_extract_base(&filename, drivers[drvindex]->source_file, FALSE)->cstr()); - count++; - } + // print the header + mame_printf_info("Name: Clone of:\n"); - /* return an error if none found */ - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + // iterate through drivers and output the info + drivlist.reset(); + while (drivlist.next()) + { + int clone_of = drivlist.clone(); + if (clone_of != -1) + mame_printf_info("%-16s %-8s\n", drivlist.driver().name, drivlist.driver(clone_of).name); + } } -/*------------------------------------------------- - cli_info_listclones - output the name and source - filename of one or more games --------------------------------------------------*/ +//------------------------------------------------- +// listbrothers - for each matching game, output +// the list of other games that share the same +// source file +//------------------------------------------------- -void cli_info_listclones(emu_options &options, const char *gamename) +void cli_frontend::listbrothers(const char *gamename) { - int count = 0, drvcnt = 0; - - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - drvcnt++; - - if (drvcnt == 0) + // start with a filtered list of drivers; return an error if none found + driver_enumerator initial_drivlist(m_options, gamename); + if (initial_drivlist.count() == 0) throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - { - const game_driver *clone_of = driver_get_clone(drivers[drvindex]); + // for the final list, start with an empty driver list + driver_enumerator drivlist(m_options); + drivlist.exclude_all(); - /* if we are a clone, and either our name matches the gamename, or the clone's name matches, display us */ - if (clone_of != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0 || mame_strwildcmp(gamename, clone_of->name) == 0) - { - /* print the header on the first one */ - if (count == 0) - mame_printf_info("Name: Clone of:\n"); + // scan through the initially-selected drivers + while (initial_drivlist.next()) + { + // if we are already marked in the final list, we don't need to do anything + if (drivlist.included(initial_drivlist.current())) + continue; + + // otherwise, walk excluded items in the final list and mark any that match + drivlist.reset(); + while (drivlist.next_excluded()) + if (strcmp(drivlist.driver().source_file, initial_drivlist.driver().source_file) == 0) + drivlist.include(); + } + + // print the header + mame_printf_info("Source file: Name: Parent:\n"); - /* output the remaining information */ - mame_printf_info("%-16s %-8s\n", drivers[drvindex]->name, clone_of->name); - count++; - } + // output the entries found + drivlist.reset(); + astring filename; + while (drivlist.next()) + { + int clone_of = drivlist.clone(); + mame_printf_info("%-16s %-16s %-16s\n", core_filename_extract_base(&filename, drivlist.driver().source_file, FALSE)->cstr(), drivlist.driver().name, (clone_of == -1 ? "" : drivlist.driver(clone_of).name)); } } -/*------------------------------------------------- - cli_info_listbrothers - output the name and - source filename of one or more games --------------------------------------------------*/ +//------------------------------------------------- +// listcrc - output the CRC and name of all ROMs +// referenced by the emulator +//------------------------------------------------- -void cli_info_listbrothers(emu_options &options, const char *gamename) +void cli_frontend::listcrc(const char *gamename) { - UINT8 *didit = global_alloc_array_clear(UINT8, driver_list_get_count(drivers)); - int count = 0; - astring filename; + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (!didit[drvindex] && mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - didit[drvindex] = TRUE; - if (count > 0) - mame_printf_info("\n"); - mame_printf_info("%s ... other drivers in %s:\n", drivers[drvindex]->name, core_filename_extract_base(&filename, drivers[drvindex]->source_file, FALSE)->cstr()); - - /* now iterate again over drivers, finding those with the same source file */ - for (int matchindex = 0; drivers[matchindex]; matchindex++) - if (matchindex != drvindex && strcmp(drivers[drvindex]->source_file, drivers[matchindex]->source_file) == 0) + // iterate through matches, and then through ROMs + while (drivlist.next()) + for (const rom_source *source = rom_first_source(drivlist.config()); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { - const char *matchstring = (mame_strwildcmp(gamename, drivers[matchindex]->name) == 0) ? "-> " : " "; - const game_driver *clone_of = driver_get_clone(drivers[matchindex]); - - if (clone_of != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0) - mame_printf_info("%s%-16s [%s]\n", matchstring, drivers[matchindex]->name, clone_of->name); - else - mame_printf_info("%s%s\n", matchstring, drivers[matchindex]->name); - didit[matchindex] = TRUE; + // if we have a CRC, display it + UINT32 crc; + if (hash_collection(ROM_GETHASHDATA(rom)).crc(crc)) + mame_printf_info("%08x %-16s %s\n", crc, ROM_GETNAME(rom), drivlist.driver().description); } - - count++; - } - - /* return an error if none found */ - global_free(didit); - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); } -/*------------------------------------------------- - cli_info_listcrc - output the CRC and name of - all ROMs referenced by MAME --------------------------------------------------*/ +//------------------------------------------------- +// listroms - output the list of ROMs referenced +// by a given game or set of games +//------------------------------------------------- -void cli_info_listcrc(emu_options &options, const char *gamename) +void cli_frontend::listroms(const char *gamename) { - int count = 0; + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - machine_config config(*drivers[drvindex], options); - const rom_entry *region, *rom; - const rom_source *source; - - /* iterate over sources, regions, and then ROMs within the region */ - for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - for (region = rom_first_region(*source); region; region = rom_next_region(region)) - for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) + // iterate through matches + astring tempstr; + bool first = true; + while (drivlist.next()) + { + // print a header + if (!first) + mame_printf_info("\n"); + first = false; + mame_printf_info("ROMs required for driver \"%s\".\n" + "Name Size Checksum\n", drivlist.driver().name); + + // iterate through roms + for (const rom_source *source = rom_first_source(drivlist.config()); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) + { + // accumulate the total length of all chunks + int length = -1; + if (ROMREGION_ISROMDATA(region)) + length = rom_file_size(rom); + + // start with the name + const char *name = ROM_GETNAME(rom); + mame_printf_info("%-20s ", name); + + // output the length next + if (length >= 0) + mame_printf_info("%7d", length); + else + mame_printf_info(" "); + + // output the hash data + hash_collection hashes(ROM_GETHASHDATA(rom)); + if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) { - /* if we have a CRC, display it */ - UINT32 crc; - if (hash_collection(ROM_GETHASHDATA(rom)).crc(crc)) - mame_printf_info("%08x %-12s %s\n", crc, ROM_GETNAME(rom), drivers[drvindex]->description); + if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) + mame_printf_info(" BAD"); + mame_printf_info(" %s", hashes.macro_string(tempstr)); } + else + mame_printf_info(" NO GOOD DUMP KNOWN"); - count++; - } - - /* return an error if none found */ - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + // end with a CR + mame_printf_info("\n"); + } + } } -/*------------------------------------------------- - cli_info_listroms - output the list of ROMs - referenced by a given game or set of games --------------------------------------------------*/ +//------------------------------------------------- +// listsamples - output the list of samples +// referenced by a given game or set of games +//------------------------------------------------- -void cli_info_listroms(emu_options &options, const char *gamename) +void cli_frontend::listsamples(const char *gamename) { - int count = 0; - astring tempstr; + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - machine_config config(*drivers[drvindex], options); - - /* print the header */ - if (count > 0) - mame_printf_info("\n"); - mame_printf_info("This is the list of the ROMs required for driver \"%s\".\n" - "Name Size Checksum\n", drivers[drvindex]->name); - - /* iterate over sources, regions and then ROMs within the region */ - for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) - for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) - { - /* accumulate the total length of all chunks */ - int length = -1; - if (ROMREGION_ISROMDATA(region)) - length = rom_file_size(rom); - - /* start with the name */ - const char *name = ROM_GETNAME(rom); - mame_printf_info("%-20s ", name); - - /* output the length next */ - if (length >= 0) - mame_printf_info("%7d", length); - else - mame_printf_info(" "); - - /* output the hash data */ - hash_collection hashes(ROM_GETHASHDATA(rom)); - if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) - { - if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) - mame_printf_info(" BAD"); - mame_printf_info(" %s", hashes.macro_string(tempstr)); - } - else - mame_printf_info(" NO GOOD DUMP KNOWN"); + // iterate over drivers, looking for SAMPLES devices + bool first = true; + while (drivlist.next()) + { + // see if we have samples + const device_config *devconfig; + for (devconfig = drivlist.config().first_device(); devconfig != NULL; devconfig = devconfig->next()) + if (devconfig->type() == SAMPLES) + break; + if (devconfig == NULL) + continue; + + // print a header + if (!first) + mame_printf_info("\n"); + first = false; + mame_printf_info("Samples required for driver \"%s\".\n", drivlist.driver().name); + + // iterate over samples devices + for ( ; devconfig != NULL; devconfig = devconfig->next()) + if (devconfig->type() == SAMPLES) + { + // if the list is legit, walk it and print the sample info + const char *const *samplenames = reinterpret_cast<const samples_interface *>(devconfig->static_config())->samplenames; + if (samplenames != NULL) + for (int sampnum = 0; samplenames[sampnum] != NULL; sampnum++) + if (samplenames[sampnum][0] != '*') + mame_printf_info("%s\n", samplenames[sampnum]); + } + } +} - /* end with a CR */ - mame_printf_info("\n"); - } - count++; - } +//------------------------------------------------- +// listdevices - output the list of devices +// referenced by a given game or set of games +//------------------------------------------------- - if (count == 0) +void cli_frontend::listdevices(const char *gamename) +{ + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + + // iterate over drivers, looking for SAMPLES devices + bool first = true; + while (drivlist.next()) + { + // print a header + if (!first) + printf("\n"); + first = false; + printf("Driver %s (%s):\n", drivlist.driver().name, drivlist.driver().description); + + // iterate through devices + for (const device_config *devconfig = drivlist.config().first_device(); devconfig != NULL; devconfig = devconfig->next()) + { + printf(" %s ('%s')", devconfig->name(), devconfig->tag()); + + UINT32 clock = devconfig->clock(); + if (clock >= 1000000000) + printf(" @ %d.%02d GHz\n", clock / 1000000000, (clock / 10000000) % 100); + else if (clock >= 1000000) + printf(" @ %d.%02d MHz\n", clock / 1000000, (clock / 10000) % 100); + else if (clock >= 1000) + printf(" @ %d.%02d kHz\n", clock / 1000, (clock / 10) % 100); + else if (clock > 0) + printf(" @ %d Hz\n", clock); + else + printf("\n"); + } + } } -/*------------------------------------------------- - cli_info_listsamples - output the list of samples - referenced by a given game or set of games --------------------------------------------------*/ +//------------------------------------------------- +// listmedia - output the list of image devices +// referenced by a given game or set of games +//------------------------------------------------- -void cli_info_listsamples(emu_options &options, const char *gamename) +void cli_frontend::listmedia(const char *gamename) { - int count = 0; + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - machine_config config(*drivers[drvindex], options); - const device_config_sound_interface *sound = NULL; + // print header + printf(" SYSTEM MEDIA NAME (brief) IMAGE FILE EXTENSIONS SUPPORTED \n"); + printf("---------- -------------------- ------------------------------------\n"); - /* find samples interfaces */ - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) - { - const char *const *samplenames = ((const samples_interface *)sound->devconfig().static_config())->samplenames; - int sampnum; + // iterate over drivers + while (drivlist.next()) + { + // iterate + const device_config_image_interface *imagedev = NULL; + bool first = true; + for (bool gotone = drivlist.config().m_devicelist.first(imagedev); gotone; gotone = imagedev->next(imagedev)) + { + // extract the shortname with parentheses + astring paren_shortname; + paren_shortname.format("(%s)", imagedev->brief_instance_name()); - /* if the list is legit, walk it and print the sample info */ - if (samplenames != NULL) - for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++) - mame_printf_info("%s\n", samplenames[sampnum]); - } + // output the line, up to the list of extensions + printf("%-13s%-12s%-8s ", first ? drivlist.driver().name : "", imagedev->instance_name(), paren_shortname.cstr()); - count++; + // get the extensions and print them + astring extensions(imagedev->file_extensions()); + for (int start = 0, end = extensions.chr(0, ','); ; start = end + 1, end = extensions.chr(start, ',')) + { + astring curext(extensions, start, (end == -1) ? -1 : end - 1); + printf(".%-5s", curext.cstr()); + if (end == -1) + break; + } + + // end the line + printf("\n"); + first = false; } - - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + + // if we didn't get any at all, just print a none line + if (first) + printf("%-13s(none)\n", drivlist.driver().name); + } } -/*------------------------------------------------- - cli_info_listdevices - output the list of - devices referenced by a given game or set of - games --------------------------------------------------*/ +//------------------------------------------------- +// verifyroms - verify the ROM sets of one or +// more games +//------------------------------------------------- -void cli_info_listdevices(emu_options &options, const char *gamename) +void cli_frontend::verifyroms(const char *gamename) { - int count = 0; - - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - machine_config config(*drivers[drvindex], options); + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - if (count != 0) - printf("\n"); - printf("Driver %s (%s):\n", drivers[drvindex]->name, drivers[drvindex]->description); + int correct = 0; + int incorrect = 0; + int notfound = 0; - /* iterate through devices */ - for (const device_config *devconfig = config.m_devicelist.first(); devconfig != NULL; devconfig = devconfig->next()) + // iterate over drivers + media_auditor auditor(drivlist); + while (drivlist.next()) + { + // audit the ROMs in this set + media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST); + + // output the summary of the audit + astring summary_string; + auditor.summarize(&summary_string); + mame_printf_info("%s", summary_string.cstr()); + + // if not found, count that and leave it at that + if (summary == media_auditor::NOTFOUND) + notfound++; + + // else display information about what we discovered + else + { + // output the name of the driver and its clone + mame_printf_info("romset %s ", drivlist.driver().name); + int clone_of = drivlist.clone(); + if (clone_of != -1) + mame_printf_info("[%s] ", drivlist.driver(clone_of).name); + + // switch off of the result + switch (summary) { - printf(" %s ('%s')", devconfig->name(), devconfig->tag()); - - UINT32 clock = devconfig->clock(); - if (clock >= 1000000000) - printf(" @ %d.%02d GHz\n", clock / 1000000000, (clock / 10000000) % 100); - else if (clock >= 1000000) - printf(" @ %d.%02d MHz\n", clock / 1000000, (clock / 10000) % 100); - else if (clock >= 1000) - printf(" @ %d.%02d kHz\n", clock / 1000, (clock / 10) % 100); - else if (clock > 0) - printf(" @ %d Hz\n", clock); - else - printf("\n"); + case media_auditor::INCORRECT: + mame_printf_info("is bad\n"); + incorrect++; + break; + + case media_auditor::CORRECT: + mame_printf_info("is good\n"); + correct++; + break; + + case media_auditor::BEST_AVAILABLE: + mame_printf_info("is best available\n"); + correct++; + break; + + default: + break; } - - count++; } + } - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + // clear out any cached files + zip_file_cache_clear(); + + // if we didn't get anything at all, display a generic end message + if (correct + incorrect == 0) + { + if (notfound > 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "romset \"%s\" not found!\n", gamename); + else + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "romset \"%s\" not supported!\n", gamename); + } + + // otherwise, print a summary + else + { + if (incorrect > 0) + throw emu_fatalerror(MAMERR_MISSING_FILES, "%d romsets found, %d were OK.\n", correct + incorrect, correct); + mame_printf_info("%d romsets found, %d were OK.\n", correct, correct); + } } -/*------------------------------------------------- - info_verifyroms - verify the ROM sets of - one or more games --------------------------------------------------*/ +//------------------------------------------------- +// info_verifysamples - verify the sample sets of +// one or more games +//------------------------------------------------- -static void info_verifyroms(emu_options &options, const char *gamename) +void cli_frontend::verifysamples(const char *gamename) { + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + int correct = 0; int incorrect = 0; int notfound = 0; - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + // iterate over drivers + media_auditor auditor(drivlist); + while (drivlist.next()) + { + // audit the samples in this set + media_auditor::summary summary = auditor.audit_samples(); + + // output the summary of the audit + astring summary_string; + auditor.summarize(&summary_string); + mame_printf_info("%s", summary_string.cstr()); + + // if not found, print a message and set the flag + if (summary == media_auditor::NOTFOUND) { - audit_record *audit; - int audit_records; - int res; - - /* audit the ROMs in this set */ - audit_records = audit_images(options, drivers[drvindex], AUDIT_VALIDATE_FAST, &audit); - res = audit_summary(drivers[drvindex], audit_records, audit, TRUE); - if (audit_records > 0) - global_free(audit); - - /* if not found, count that and leave it at that */ - if (res == NOTFOUND) - notfound++; + mame_printf_error("sampleset \"%s\" not found!\n", drivlist.driver().name); + notfound++; + } - /* else display information about what we discovered */ - else + // else display information about what we discovered + else + { + // output the name of the driver and its clone + mame_printf_info("sampleset %s ", drivlist.driver().name); + int clone_of = drivlist.clone(); + if (clone_of != -1) + mame_printf_info("[%s] ", drivlist.driver(clone_of).name); + + // switch off of the result + switch (summary) { - const game_driver *clone_of; - - /* output the name of the driver and its clone */ - mame_printf_info("romset %s ", drivers[drvindex]->name); - clone_of = driver_get_clone(drivers[drvindex]); - if (clone_of != NULL) - mame_printf_info("[%s] ", clone_of->name); - - /* switch off of the result */ - switch (res) - { - case INCORRECT: - mame_printf_info("is bad\n"); - incorrect++; - break; - - case CORRECT: - mame_printf_info("is good\n"); - correct++; - break; - - case BEST_AVAILABLE: - mame_printf_info("is best available\n"); - correct++; - break; - } + case media_auditor::INCORRECT: + mame_printf_info("is bad\n"); + incorrect++; + break; + + case media_auditor::CORRECT: + mame_printf_info("is good\n"); + correct++; + break; + + case media_auditor::BEST_AVAILABLE: + mame_printf_info("is best available\n"); + correct++; + break; + + default: + break; } } + } - /* clear out any cached files */ + // clear out any cached files zip_file_cache_clear(); - /* if we didn't get anything at all, display a generic end message */ + // if we didn't get anything at all, display a generic end message if (correct + incorrect == 0) { if (notfound > 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "romset \"%s\" not found!\n", gamename); + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "sampleset \"%s\" not found!\n", gamename); else - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "romset \"%s\" not supported!\n", gamename); + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "sampleset \"%s\" not supported!\n", gamename); } - /* otherwise, print a summary */ + // otherwise, print a summary else { if (incorrect > 0) - throw emu_fatalerror(MAMERR_MISSING_FILES, "%d romsets found, %d were OK.\n", correct + incorrect, correct); - mame_printf_info("%d romsets found, %d were OK.\n", correct, correct); + throw emu_fatalerror(MAMERR_MISSING_FILES, "%d samplesets found, %d were OK.\n", correct + incorrect, correct); + mame_printf_info("%d samplesets found, %d were OK.\n", correct, correct); } } + + +#if 0 /*------------------------------------------------- info_listsoftware - output the list of software supported by a given game or set of @@ -798,37 +800,31 @@ static void info_verifyroms(emu_options &options, const char *gamename) identifying duplicate lists. -------------------------------------------------*/ -static void info_listsoftware(emu_options &options, const char *gamename) +static void info_listsoftware(const char *gamename) { FILE *out = stdout; - int nr_lists = 0; - char ** lists = NULL; - int list_idx = 0; - /* First determine the maximum number of lists we might encounter */ - for ( int drvindex = 0; drivers[drvindex] != NULL; drvindex++ ) - { - if ( mame_strwildcmp( gamename, drivers[drvindex]->name ) == 0 ) - { - /* allocate the machine config */ - machine_config config(*drivers[drvindex], options); + // determine which drivers to output; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (drivlist.count() == 0) + throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) - { - software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); + // first determine the maximum number of lists we might encounter + int list_count = 0; + while (drivlist.next()) + for (const device_config *dev = drivlist.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) + { + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); - for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) - { - if ( swlist->list_name[i] && *swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM)) - nr_lists++; - } - } + for (int listnum = 0; listnum < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; listnum++) + if (swlist->list_name[listnum] && *swlist->list_name[listnum] && swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM) + list_count++; } - } - lists = global_alloc_array( char *, nr_lists ); + // allocate a list + astring *lists = global_alloc_array(astring, list_count); - if (nr_lists) + if (list_count) { fprintf( out, "<?xml version=\"1.0\"?>\n" @@ -902,664 +898,602 @@ static void info_listsoftware(emu_options &options, const char *gamename) ); } - for ( int drvindex = 0; drivers[drvindex] != NULL; drvindex++ ) - { - if ( mame_strwildcmp( gamename, drivers[drvindex]->name ) == 0 ) + drivlist.reset(); + list_count = 0; + while (drivlist.next()) + for (const device_config *dev = drivlist.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) { - /* allocate the machine config */ - machine_config config(*drivers[drvindex], options); + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); - for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) + for (int listnum = 0; listnum < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; listnum++) { - software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); - - for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) + if (swlist->list_name[listnum] && *swlist->list_name[listnum] && swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM) { - if ( swlist->list_name[i] && *swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM)) + software_list *list = software_list_open(m_options, swlist->list_name[listnum], FALSE, NULL); + + if ( list ) { - software_list *list = software_list_open( options, swlist->list_name[i], FALSE, NULL ); + /* Verify if we have encountered this list before */ + bool seen_before = false; + for (int seen_index = 0; seen_index < list_count && !seen_before; seen_index++) + if (lists[seen_index] == swlist->list_name[listnum]) + seen_before = true; - if ( list ) + if (!seen_before) { - /* Verify if we have encountered this list before */ - bool seen_before = false; - for ( int l = 0; l < list_idx && !seen_before; l++ ) - { - if ( ! strcmp( swlist->list_name[i], lists[l] ) ) - { - seen_before = true; - } - } + lists[list_count++] = swlist->list_name[i]; + software_list_parse( list, NULL, NULL ); + + fprintf(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlist->list_name[i], xml_normalize_string(software_list_get_description(list)) ); - if ( ! seen_before ) + for ( software_info *swinfo = software_list_find( list, "*", NULL ); swinfo != NULL; swinfo = software_list_find( list, "*", swinfo ) ) { - lists[list_idx] = core_strdup( swlist->list_name[i] ); - list_idx++; - software_list_parse( list, NULL, NULL ); + fprintf( out, "\t\t<software name=\"%s\"", swinfo->shortname ); + if ( swinfo->parentname != NULL ) + fprintf( out, " cloneof=\"%s\"", swinfo->parentname ); + if ( swinfo->supported == SOFTWARE_SUPPORTED_PARTIAL ) + fprintf( out, " supported=\"partial\"" ); + if ( swinfo->supported == SOFTWARE_SUPPORTED_NO ) + fprintf( out, " supported=\"no\"" ); + fprintf( out, ">\n" ); + fprintf( out, "\t\t\t<description>%s</description>\n", xml_normalize_string(swinfo->longname) ); + fprintf( out, "\t\t\t<year>%s</year>\n", xml_normalize_string( swinfo->year ) ); + fprintf( out, "\t\t\t<publisher>%s</publisher>\n", xml_normalize_string( swinfo->publisher ) ); + + for ( software_part *part = software_find_part( swinfo, NULL, NULL ); part != NULL; part = software_part_next( part ) ) + { + fprintf( out, "\t\t\t<part name=\"%s\"", part->name ); + if ( part->interface_ ) + fprintf( out, " interface=\"%s\"", part->interface_ ); - fprintf(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlist->list_name[i], xml_normalize_string(software_list_get_description(list)) ); + fprintf( out, ">\n"); - for ( software_info *swinfo = software_list_find( list, "*", NULL ); swinfo != NULL; swinfo = software_list_find( list, "*", swinfo ) ) - { - fprintf( out, "\t\t<software name=\"%s\"", swinfo->shortname ); - if ( swinfo->parentname != NULL ) - fprintf( out, " cloneof=\"%s\"", swinfo->parentname ); - if ( swinfo->supported == SOFTWARE_SUPPORTED_PARTIAL ) - fprintf( out, " supported=\"partial\"" ); - if ( swinfo->supported == SOFTWARE_SUPPORTED_NO ) - fprintf( out, " supported=\"no\"" ); - fprintf( out, ">\n" ); - fprintf( out, "\t\t\t<description>%s</description>\n", xml_normalize_string(swinfo->longname) ); - fprintf( out, "\t\t\t<year>%s</year>\n", xml_normalize_string( swinfo->year ) ); - fprintf( out, "\t\t\t<publisher>%s</publisher>\n", xml_normalize_string( swinfo->publisher ) ); - - for ( software_part *part = software_find_part( swinfo, NULL, NULL ); part != NULL; part = software_part_next( part ) ) + if ( part->featurelist ) { - fprintf( out, "\t\t\t<part name=\"%s\"", part->name ); - if ( part->interface_ ) - fprintf( out, " interface=\"%s\"", part->interface_ ); + feature_list *list = part->featurelist; - fprintf( out, ">\n"); - - if ( part->featurelist ) + while( list ) { - feature_list *list = part->featurelist; - - while( list ) - { - fprintf( out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", list->name, list->value ); - list = list->next; - } + fprintf( out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", list->name, list->value ); + list = list->next; } + } - /* TODO: display rom region information */ - for ( const rom_entry *region = part->romdata; region; region = rom_next_region( region ) ) - { - int is_disk = ROMREGION_ISDISKDATA(region); + /* TODO: display rom region information */ + for ( const rom_entry *region = part->romdata; region; region = rom_next_region( region ) ) + { + int is_disk = ROMREGION_ISDISKDATA(region); - if (!is_disk) - fprintf( out, "\t\t\t\t<dataarea name=\"%s\" size=\"%d\">\n", ROMREGION_GETTAG(region), ROMREGION_GETLENGTH(region) ); - else - fprintf( out, "\t\t\t\t<diskarea name=\"%s\">\n", ROMREGION_GETTAG(region) ); + if (!is_disk) + fprintf( out, "\t\t\t\t<dataarea name=\"%s\" size=\"%d\">\n", ROMREGION_GETTAG(region), ROMREGION_GETLENGTH(region) ); + else + fprintf( out, "\t\t\t\t<diskarea name=\"%s\">\n", ROMREGION_GETTAG(region) ); - for ( const rom_entry *rom = rom_first_file( region ); rom && !ROMENTRY_ISREGIONEND(rom); rom++ ) + for ( const rom_entry *rom = rom_first_file( region ); rom && !ROMENTRY_ISREGIONEND(rom); rom++ ) + { + if ( ROMENTRY_ISFILE(rom) ) { - if ( ROMENTRY_ISFILE(rom) ) + if (!is_disk) + fprintf( out, "\t\t\t\t\t<rom name=\"%s\" size=\"%d\"", xml_normalize_string(ROM_GETNAME(rom)), rom_file_size(rom) ); + else + fprintf( out, "\t\t\t\t\t<disk name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom)) ); + + /* dump checksum information only if there is a known dump */ + hash_collection hashes(ROM_GETHASHDATA(rom)); + if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) { - if (!is_disk) - fprintf( out, "\t\t\t\t\t<rom name=\"%s\" size=\"%d\"", xml_normalize_string(ROM_GETNAME(rom)), rom_file_size(rom) ); - else - fprintf( out, "\t\t\t\t\t<disk name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom)) ); - - /* dump checksum information only if there is a known dump */ - hash_collection hashes(ROM_GETHASHDATA(rom)); - if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) - { - astring tempstr; - for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next()) - fprintf(out, " %s=\"%s\"", hash->name(), hash->string(tempstr)); - } - - if (!is_disk) - fprintf( out, " offset=\"0x%x\"", ROM_GETOFFSET(rom) ); - - if ( hashes.flag(hash_collection::FLAG_BAD_DUMP) ) - fprintf( out, " status=\"baddump\"" ); - if ( hashes.flag(hash_collection::FLAG_NO_DUMP) ) - fprintf( out, " status=\"nodump\"" ); - - if (is_disk) - fprintf( out, " writeable=\"%s\"", (ROM_GETFLAGS(rom) & DISK_READONLYMASK) ? "no" : "yes"); - - if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(1)) - fprintf( out, " loadflag=\"load16_byte\"" ); - - if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(3)) - fprintf( out, " loadflag=\"load32_byte\"" ); - - if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(2)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) - { - if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) - fprintf( out, " loadflag=\"load32_word\"" ); - else - fprintf( out, " loadflag=\"load32_word_swap\"" ); - } - - if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(6)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) - { - if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) - fprintf( out, " loadflag=\"load64_word\"" ); - else - fprintf( out, " loadflag=\"load64_word_swap\"" ); - } - - if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_NOSKIP) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) - { - if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) - fprintf( out, " loadflag=\"load32_dword\"" ); - else - fprintf( out, " loadflag=\"load16_word_swap\"" ); - } - - fprintf( out, "/>\n" ); + astring tempstr; + for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next()) + fprintf(out, " %s=\"%s\"", hash->name(), hash->string(tempstr)); } - else if ( ROMENTRY_ISRELOAD(rom) ) + + if (!is_disk) + fprintf( out, " offset=\"0x%x\"", ROM_GETOFFSET(rom) ); + + if ( hashes.flag(hash_collection::FLAG_BAD_DUMP) ) + fprintf( out, " status=\"baddump\"" ); + if ( hashes.flag(hash_collection::FLAG_NO_DUMP) ) + fprintf( out, " status=\"nodump\"" ); + + if (is_disk) + fprintf( out, " writeable=\"%s\"", (ROM_GETFLAGS(rom) & DISK_READONLYMASK) ? "no" : "yes"); + + if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(1)) + fprintf( out, " loadflag=\"load16_byte\"" ); + + if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(3)) + fprintf( out, " loadflag=\"load32_byte\"" ); + + if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(2)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) { - fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"reload\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) + fprintf( out, " loadflag=\"load32_word\"" ); + else + fprintf( out, " loadflag=\"load32_word_swap\"" ); } - else if ( ROMENTRY_ISCONTINUE(rom) ) + + if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(6)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) { - fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"continue\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) + fprintf( out, " loadflag=\"load64_word\"" ); + else + fprintf( out, " loadflag=\"load64_word_swap\"" ); } - else if ( ROMENTRY_ISFILL(rom) ) + + if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_NOSKIP) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD)) { - fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"fill\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK)) + fprintf( out, " loadflag=\"load32_dword\"" ); + else + fprintf( out, " loadflag=\"load16_word_swap\"" ); } - } - if (!is_disk) - fprintf( out, "\t\t\t\t</dataarea>\n" ); - else - fprintf( out, "\t\t\t\t</diskarea>\n" ); + fprintf( out, "/>\n" ); + } + else if ( ROMENTRY_ISRELOAD(rom) ) + { + fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"reload\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + } + else if ( ROMENTRY_ISCONTINUE(rom) ) + { + fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"continue\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + } + else if ( ROMENTRY_ISFILL(rom) ) + { + fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"fill\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) ); + } } - fprintf( out, "\t\t\t</part>\n" ); + if (!is_disk) + fprintf( out, "\t\t\t\t</dataarea>\n" ); + else + fprintf( out, "\t\t\t\t</diskarea>\n" ); } - fprintf( out, "\t\t</software>\n" ); + fprintf( out, "\t\t\t</part>\n" ); } - fprintf(out, "\t</softwarelist>\n" ); + fprintf( out, "\t\t</software>\n" ); } - software_list_close( list ); + fprintf(out, "\t</softwarelist>\n" ); } + + software_list_close( list ); } } } } - } - if (nr_lists) + if (list_count > 0) fprintf( out, "</softwarelists>\n" ); else fprintf( out, "No software lists found for this system\n" ); global_free( lists ); } +#endif -/*------------------------------------------------- - softlist_match_roms - scan for a matching - software ROM by hash --------------------------------------------------*/ -void softlist_match_roms(machine_config &config, const hash_collection &hashes, int length, int *found) -{ - for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) - { - software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); - - for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) - { - if ( swlist->list_name[i] ) - { - software_list *list = software_list_open( config.options(), swlist->list_name[i], FALSE, NULL ); - - for ( software_info *swinfo = software_list_find( list, "*", NULL ); swinfo != NULL; swinfo = software_list_find( list, "*", swinfo ) ) - { - for ( software_part *part = software_find_part( swinfo, NULL, NULL ); part != NULL; part = software_part_next( part ) ) - { - for ( const rom_entry *region = part->romdata; region != NULL; region = rom_next_region(region) ) - { - for ( const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom) ) - { - hash_collection romhashes(ROM_GETHASHDATA(rom)); - if ( hashes == romhashes ) - { - bool baddump = romhashes.flag(hash_collection::FLAG_BAD_DUMP); - - /* output information about the match */ - if (*found != 0) - mame_printf_info(" "); - mame_printf_info("= %s%-20s %s:%s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), swlist->list_name[i], swinfo->shortname, swinfo->longname); - (*found)++; - } - } - } - } - } - - software_list_close( list ); - } - } - } -} - -/*------------------------------------------------- - info_listmedia - output the list of image - devices referenced by a given game or set of - games --------------------------------------------------*/ +//------------------------------------------------- +// romident - identify ROMs by looking for +// matches in our internal database +//------------------------------------------------- -static void info_listmedia(emu_options &options, const char *gamename) +void cli_frontend::romident(const char *filename) { - int count = 0, devcount; - const device_config_image_interface *dev = NULL; - const char *src; - const char *driver_name; - const char *name; - const char *shortname; - char paren_shortname[16]; + media_identifier ident(m_options); - printf(" SYSTEM MEDIA NAME (brief) IMAGE FILE EXTENSIONS SUPPORTED \n"); - printf("---------- -------------------- ------------------------------------\n"); - - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - /* allocate the machine config */ - machine_config config(*drivers[drvindex], options); + // identify the file, then output results + mame_printf_info("Identifying %s....\n", filename); + ident.identify(filename); + mame_printf_info("%s\n", ident.result()); - driver_name = drivers[drvindex]->name; - - devcount = 0; - - for (bool gotone = config.m_devicelist.first(dev); gotone; gotone = dev->next(dev)) - { - src = downcast<const legacy_image_device_config_base *>(dev)->file_extensions(); - name = downcast<const legacy_image_device_config_base *>(dev)->instance_name(); - shortname = downcast<const legacy_image_device_config_base *>(dev)->brief_instance_name(); - - sprintf(paren_shortname, "(%s)", shortname); - - printf("%-13s%-12s%-8s ", driver_name, name, paren_shortname); - driver_name = " "; - - astring extensions(src); - char *ext = strtok((char*)extensions.cstr(),","); - while (ext != NULL) - { - printf(".%-5s",ext); - ext = strtok (NULL, ","); - devcount++; - } - printf("\n"); - } - if (!devcount) - printf("%-13s(none)\n",driver_name); - - count++; - } - - if (!count) - printf("There are no Computers or Consoles named %s\n", gamename); - - if (count == 0) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); + // return the appropriate error code + if (ident.matches() == ident.total()) + return; + else if (ident.matches() == ident.total() - ident.nonroms()) + throw emu_fatalerror(MAMERR_IDENT_NONROMS, ""); + else if (ident.matches() > 0) + throw emu_fatalerror(MAMERR_IDENT_PARTIAL, ""); + else + throw emu_fatalerror(MAMERR_IDENT_NONE, ""); } -/*------------------------------------------------- - info_verifysamples - verify the sample sets of - one or more games --------------------------------------------------*/ +//------------------------------------------------- +// execute_commands - execute various frontend +// commands +//------------------------------------------------- -static void info_verifysamples(emu_options &options, const char *gamename) +void cli_frontend::execute_commands(const char *exename) { - int correct = 0; - int incorrect = 0; - int notfound = FALSE; + // help? + if (strcmp(m_options.command(), CLICOMMAND_HELP) == 0) + { + display_help(); + return; + } - /* now iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) - { - audit_record *audit; - int audit_records; - int res; - - /* audit the samples in this set */ - audit_records = audit_samples(options, drivers[drvindex], &audit); - res = audit_summary(drivers[drvindex], audit_records, audit, TRUE); - if (audit_records > 0) - global_free(audit); - else - continue; + // showusage? + if (strcmp(m_options.command(), CLICOMMAND_SHOWUSAGE) == 0) + { + astring helpstring; +#ifndef MESS + mame_printf_info("Usage: %s [%s] [options]\n\nOptions:\n%s", exename, GAMENOUN, m_options.output_help(helpstring)); +#else + mame_printf_info("Usage: %s [%s] [media] [software] [options]\n\nOptions:\n%s", exename, GAMENOUN, m_options.output_help(helpstring)); +#endif + return; + } - /* if not found, print a message and set the flag */ - if (res == NOTFOUND) - { - mame_printf_error("sampleset \"%s\" not found!\n", drivers[drvindex]->name); - notfound = TRUE; - } + // validate? + if (strcmp(m_options.command(), CLICOMMAND_VALIDATE) == 0) + { + validate_drivers(m_options); + return; + } - /* else display information about what we discovered */ - else - { - mame_printf_info("sampleset %s ", drivers[drvindex]->name); + // other commands need the INIs parsed + astring option_errors; + m_options.parse_standard_inis(option_errors); + if (option_errors) + printf("%s\n", option_errors.cstr()); - /* switch off of the result */ - switch (res) - { - case INCORRECT: - mame_printf_info("is bad\n"); - incorrect++; - break; - - case CORRECT: - mame_printf_info("is good\n"); - correct++; - break; - - case BEST_AVAILABLE: - mame_printf_info("is best available\n"); - correct++; - break; - } - } - } + // createconfig? + if (strcmp(m_options.command(), CLICOMMAND_CREATECONFIG) == 0) + { + // attempt to open the output file + emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (file.open(CONFIGNAME ".ini") != FILERR_NONE) + throw emu_fatalerror("Unable to create file " CONFIGNAME ".ini\n"); - /* clear out any cached files */ - zip_file_cache_clear(); + // generate the updated INI + astring initext; + file.puts(m_options.output_ini(initext)); + return; + } - /* if we didn't get anything at all because of an unsupported set, display message */ - if (correct + incorrect == 0) + // showconfig? + if (strcmp(m_options.command(), CLICOMMAND_SHOWCONFIG) == 0) { - if (!notfound) - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename); - else - throw emu_fatalerror(MAMERR_NO_SUCH_GAME, "No sample sets found for '%s'", gamename); + // print the INI text + astring initext; + printf("%s\n", m_options.output_ini(initext)); + return; } - /* otherwise, print a summary */ - else + // all other commands call out to one of these helpers + static const struct { - if (incorrect > 0) - throw emu_fatalerror(MAMERR_MISSING_FILES, "%d sample sets found, %d were OK.\n", correct + incorrect, correct); - mame_printf_info("%d sample sets found, %d were OK.\n", correct, correct); - } + const char *option; + void (cli_frontend::*function)(const char *gamename); + } info_commands[] = + { + { CLICOMMAND_LISTXML, &cli_frontend::listxml }, + { CLICOMMAND_LISTFULL, &cli_frontend::listfull }, + { CLICOMMAND_LISTSOURCE, &cli_frontend::listsource }, + { CLICOMMAND_LISTCLONES, &cli_frontend::listclones }, + { CLICOMMAND_LISTBROTHERS, &cli_frontend::listbrothers }, + { CLICOMMAND_LISTCRC, &cli_frontend::listcrc }, + { CLICOMMAND_LISTDEVICES, &cli_frontend::listdevices }, + { CLICOMMAND_LISTROMS, &cli_frontend::listroms }, + { CLICOMMAND_LISTSAMPLES, &cli_frontend::listsamples }, + { CLICOMMAND_VERIFYROMS, &cli_frontend::verifyroms }, + { CLICOMMAND_VERIFYSAMPLES, &cli_frontend::verifysamples }, + { CLICOMMAND_LISTMEDIA, &cli_frontend::listmedia }, +// { CLICOMMAND_LISTSOFTWARE, &cli_frontend::listsoftware }, + { CLICOMMAND_ROMIDENT, &cli_frontend::romident } + }; + + // find the command + for (int cmdindex = 0; cmdindex < ARRAY_LENGTH(info_commands); cmdindex++) + if (strcmp(m_options.command(), info_commands[cmdindex].option) == 0) + { + // parse any relevant INI files before proceeding + const char *sysname = m_options.system_name(); + (this->*info_commands[cmdindex].function)((sysname[0] == 0) ? "*" : sysname); + return; + } + + // if we get here, we don't know what has been requested + throw emu_fatalerror(MAMERR_INVALID_CONFIG, "Unknown command '%s' specified", m_options.command()); } -/*------------------------------------------------- - info_romident - identify ROMs by looking for - matches in our internal database --------------------------------------------------*/ +//------------------------------------------------- +// display_help - display help to standard +// output +//------------------------------------------------- -static void info_romident(emu_options &options, const char *gamename) +void cli_frontend::display_help() { - romident_status status; +#ifndef MESS + mame_printf_info("M.A.M.E. v%s - Multiple Arcade Machine Emulator\n" + "Copyright Nicola Salmoria and the MAME Team\n\n", build_version); + mame_printf_info("%s\n", mame_disclaimer); + mame_printf_info("Usage: MAME gamename [options]\n\n" + " MAME -showusage for a brief list of options\n" + " MAME -showconfig for a list of configuration options\n" + " MAME -createconfig to create a " CONFIGNAME ".ini\n\n" + "For usage instructions, please consult the file windows.txt\n"); +#else + mess_display_help(); +#endif +} - /* do the identification */ - romident(options, gamename, &status); - /* clear out any cached files */ - zip_file_cache_clear(); +//------------------------------------------------- +// display_suggestions - display 10 possible +// matches for a given invalid gamename +//------------------------------------------------- - /* return the appropriate error code */ - if (status.matches == status.total) - return; - else if (status.matches == status.total - status.nonroms) - throw emu_fatalerror(MAMERR_IDENT_NONROMS, ""); - else if (status.matches > 0) - throw emu_fatalerror(MAMERR_IDENT_PARTIAL, ""); - else - throw emu_fatalerror(MAMERR_IDENT_NONE, ""); +void cli_frontend::display_suggestions(const char *gamename) +{ } +//************************************************************************** +// MEDIA IDENTIFIER +//************************************************************************** -/*************************************************************************** - UTILITIES -***************************************************************************/ - -/*------------------------------------------------- - romident - identify files --------------------------------------------------*/ +//------------------------------------------------- +// media_identifier - constructor +//------------------------------------------------- -static void romident(emu_options &options, const char *filename, romident_status *status) +media_identifier::media_identifier(cli_options &options) + : m_drivlist(options), + m_total(0), + m_matches(0), + m_nonroms(0) { - osd_directory *directory; +} - /* reset the status */ - memset(status, 0, sizeof(*status)); - /* first try to open as a directory */ - directory = osd_opendir(filename); +//------------------------------------------------- +// identify - identify a directory, ZIP file, +// or raw file +//------------------------------------------------- + +void media_identifier::identify(const char *filename) +{ + // first try to open as a directory + osd_directory *directory = osd_opendir(filename); if (directory != NULL) { - const osd_directory_entry *entry; - - /* iterate over all files in the directory */ - while ((entry = osd_readdir(directory)) != NULL) + // iterate over all files in the directory + for (const osd_directory_entry *entry = osd_readdir(directory); entry != NULL; entry = osd_readdir(directory)) if (entry->type == ENTTYPE_FILE) { astring curfile(filename, PATH_SEPARATOR, entry->name); - identify_file(options, curfile, status); + identify_file(curfile); } + + // close the directory and be done osd_closedir(directory); } - /* if that failed, and the filename ends with .zip, identify as a ZIP file */ + // if that failed, and the filename ends with .zip, identify as a ZIP file else if (core_filename_ends_with(filename, ".zip")) { - /* first attempt to examine it as a valid ZIP file */ + // first attempt to examine it as a valid ZIP file zip_file *zip = NULL; zip_error ziperr = zip_file_open(filename, &zip); if (ziperr == ZIPERR_NONE && zip != NULL) { - const zip_file_header *entry; - - /* loop over entries in the ZIP, skipping empty files and directories */ - for (entry = zip_file_first_file(zip); entry; entry = zip_file_next_file(zip)) + // loop over entries in the ZIP, skipping empty files and directories + for (const zip_file_header *entry = zip_file_first_file(zip); entry != NULL; entry = zip_file_next_file(zip)) if (entry->uncompressed_length != 0) { UINT8 *data = global_alloc_array(UINT8, entry->uncompressed_length); if (data != NULL) { - /* decompress data into RAM and identify it */ + // decompress data into RAM and identify it ziperr = zip_file_decompress(zip, data, entry->uncompressed_length); if (ziperr == ZIPERR_NONE) - identify_data(options, entry->filename, data, entry->uncompressed_length, status); + identify_data(entry->filename, data, entry->uncompressed_length); global_free(data); } } - /* close up */ + // close up zip_file_close(zip); } + + // clear out any cached files + zip_file_cache_clear(); } - /* otherwise, identify as a raw file */ + // otherwise, identify as a raw file else - identify_file(options, filename, status); + identify_file(filename); } -/*------------------------------------------------- - identify_file - identify a file; if it is a - ZIP file, scan it and identify all enclosed - files --------------------------------------------------*/ +//------------------------------------------------- +// identify_file - identify a file +//------------------------------------------------- -static void identify_file(emu_options &options, const char *name, romident_status *status) +void media_identifier::identify_file(const char *name) { - file_error filerr; - osd_file *file; - UINT64 length; - + // CHD files need to be parsed and their hashes extracted from the header if (core_filename_ends_with(name, ".chd")) { - chd_file *chd; - chd_error err; + // output the name astring basename; - int found = 0; - - core_filename_extract_base(&basename, name, FALSE); - mame_printf_info("%-20s", basename.cstr()); + m_result.catprintf("%-20s", core_filename_extract_base(&basename, name, FALSE)->cstr()); + m_total++; - status->total++; - - err = chd_open(name, CHD_OPEN_READ, NULL, &chd); + // attempt to open as a CHD; fail if not + chd_file *chd; + chd_error err = chd_open(name, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { - mame_printf_info("NOT A CHD\n"); - status->nonroms++; + m_result.catprintf("NOT A CHD\n"); + m_nonroms++; + return; } - else - { - chd_header header; - - header = *chd_get_header(chd); - if (header.flags & CHDFLAGS_IS_WRITEABLE) - { - mame_printf_info("is a writeable CHD\n"); - } - else - { - static const UINT8 nullhash[20] = { 0 }; - hash_collection hashes; - - /* if there's an MD5 or SHA1 hash, add them to the output hash */ - if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) - hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); - if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) - hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); - length = header.logicalbytes; + // fetch the header and close the file + chd_header header = *chd_get_header(chd); + chd_close(chd); - match_roms(options, hashes, length, &found); - - if (found == 0) - { - mame_printf_info("NO MATCH\n"); - } - - /* if we did find it, count it as a match */ - else - status->matches++; - } - - chd_close(chd); + // error on writable CHDs + if (header.flags & CHDFLAGS_IS_WRITEABLE) + { + m_result.catprintf("is a writeable CHD\n"); + return; } + + // otherwise, get the hash collection for this CHD + static const UINT8 nullhash[20] = { 0 }; + hash_collection hashes; + + if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) + hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); + if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) + hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + + // determine whether this file exists + int found = find_by_hash(hashes, header.logicalbytes); + if (found == 0) + m_result.catprintf("NO MATCH\n"); + else + m_matches++; } + + // all other files have their hashes computed directly else { - /* open for read and process if it opens and has a valid length */ - filerr = osd_open(name, OPEN_FLAG_READ, &file, &length); - if (filerr == FILERR_NONE && length > 0 && (UINT32)length == length) - { - UINT8 *data = global_alloc_array(UINT8, length); - if (data != NULL) - { - UINT32 bytes; - - /* read file data into RAM and identify it */ - filerr = osd_read(file, data, 0, length, &bytes); - if (filerr == FILERR_NONE) - identify_data(options, name, data, bytes, status); - global_free(data); - } - osd_close(file); - } + // load the file and process if it opens and has a valid length + UINT32 length; + void *data; + file_error filerr = core_fload(name, &data, &length); + if (filerr == FILERR_NONE && length > 0) + identify_data(name, reinterpret_cast<UINT8 *>(data), length); } } -/*------------------------------------------------- - identify_data - identify a buffer full of - data; if it comes from a .JED file, parse the - fusemap into raw data first --------------------------------------------------*/ +//------------------------------------------------- +// identify_data - identify a buffer full of +// data; if it comes from a .JED file, parse the +// fusemap into raw data first +//------------------------------------------------- -static void identify_data(emu_options &options, const char *name, const UINT8 *data, int length, romident_status *status) +void media_identifier::identify_data(const char *name, const UINT8 *data, int length) { + // if this is a '.jed' file, process it into raw bits first UINT8 *tempjed = NULL; - astring basename; - int found = 0; jed_data jed; - - /* if this is a '.jed' file, process it into raw bits first */ if (core_filename_ends_with(name, ".jed") && jed_parse(data, length, &jed) == JEDERR_NONE) { - /* now determine the new data length and allocate temporary memory for it */ + // now determine the new data length and allocate temporary memory for it length = jedbin_output(&jed, NULL, 0); tempjed = global_alloc_array(UINT8, length); - if (tempjed == NULL) - return; - - /* create a binary output of the JED data and use that instead */ jedbin_output(&jed, tempjed, length); data = tempjed; } - /* compute the hash of the data */ + // compute the hash of the data hash_collection hashes; hashes.compute(data, length, hash_collection::HASH_TYPES_CRC_SHA1); - /* output the name */ - status->total++; - core_filename_extract_base(&basename, name, FALSE); - mame_printf_info("%-20s", basename.cstr()); + // output the name + m_total++; + astring basename; + m_result.catprintf("%-20s", core_filename_extract_base(&basename, name, FALSE)->cstr()); - /* see if we can find a match in the ROMs */ - match_roms(options, hashes, length, &found); + // see if we can find a match in the ROMs + int found = find_by_hash(hashes, length); - /* if we didn't find it, try to guess what it might be */ + // if we didn't find it, try to guess what it might be if (found == 0) { - /* if not a power of 2, assume it is a non-ROM file */ + // if not a power of 2, assume it is a non-ROM file if ((length & (length - 1)) != 0) { - mame_printf_info("NOT A ROM\n"); - status->nonroms++; + m_result.catprintf("NOT A ROM\n"); + m_nonroms++; } - /* otherwise, it's just not a match */ + // otherwise, it's just not a match else - mame_printf_info("NO MATCH\n"); + m_result.catprintf("NO MATCH\n"); } - /* if we did find it, count it as a match */ + // if we did find it, count it as a match else - status->matches++; + m_matches++; - /* free any temporary JED data */ + // free any temporary JED data global_free(tempjed); } -/*------------------------------------------------- - match_roms - scan for a matching ROM by hash --------------------------------------------------*/ +//------------------------------------------------- +// find_by_hash - scan for a file in the list +// of drivers by hash +//------------------------------------------------- -static void match_roms(emu_options &options, const hash_collection &hashes, int length, int *found) +int media_identifier::find_by_hash(const hash_collection &hashes, int length) { - /* iterate over drivers */ - for (int drvindex = 0; drivers[drvindex] != NULL; drvindex++) - { - machine_config config(*drivers[drvindex], options); + int found = 0; - /* iterate over sources, regions and files within the region */ - for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region)) - for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) + // iterate over drivers + m_drivlist.reset(); + while (m_drivlist.next()) + { + // iterate over sources, regions and files within the region */ + for (const rom_source *source = rom_first_source(m_drivlist.config()); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) { hash_collection romhashes(ROM_GETHASHDATA(rom)); if (!romhashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes) { bool baddump = romhashes.flag(hash_collection::FLAG_BAD_DUMP); - /* output information about the match */ - if (*found != 0) + // output information about the match + if (!found) mame_printf_info(" "); - mame_printf_info("= %s%-20s %-10s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), drivers[drvindex]->name, drivers[drvindex]->description); - (*found)++; + mame_printf_info("= %s%-20s %-10s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), m_drivlist.driver().name, m_drivlist.driver().description); + found++; } } - // also check any softlists - softlist_match_roms( config, hashes, length, found ); + // next iterate over softlists + for (const device_config *dev = m_drivlist.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) + { + software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); + + for (int listnum = 0; listnum < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; listnum++) + if (swlist->list_name[listnum] != NULL) + { + software_list *list = software_list_open(m_drivlist.options(), swlist->list_name[listnum], FALSE, NULL); + + for (software_info *swinfo = software_list_find(list, "*", NULL); swinfo != NULL; swinfo = software_list_find(list, "*", swinfo)) + for (software_part *part = software_find_part(swinfo, NULL, NULL); part != NULL; part = software_part_next(part)) + for (const rom_entry *region = part->romdata; region != NULL; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) + { + hash_collection romhashes(ROM_GETHASHDATA(rom)); + if (hashes == romhashes) + { + bool baddump = romhashes.flag(hash_collection::FLAG_BAD_DUMP); + + // output information about the match + if (!found) + mame_printf_info(" "); + mame_printf_info("= %s%-20s %s:%s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), swlist->list_name[listnum], swinfo->shortname, swinfo->longname); + found++; + } + } + + software_list_close(list); + } + } } + + return found; } diff --git a/src/emu/clifront.h b/src/emu/clifront.h index d240fdf160f..2870309c7a4 100644 --- a/src/emu/clifront.h +++ b/src/emu/clifront.h @@ -80,6 +80,7 @@ // TYPE DEFINITIONS //************************************************************************** +// cli_options wraps the general emu options with CLI-specific additions class cli_options : public emu_options { public: @@ -91,22 +92,75 @@ private: }; +// cli_frontend handles command-line processing and emulator execution +class cli_frontend +{ +public: + // construction/destruction + cli_frontend(cli_options &options, osd_interface &osd); + ~cli_frontend(); + + // execute based on the incoming argc/argv + int execute(int argc, char **argv); + + // direct access to the command operations + void listxml(const char *gamename = "*"); + void listfull(const char *gamename = "*"); + void listsource(const char *gamename = "*"); + void listclones(const char *gamename = "*"); + void listbrothers(const char *gamename = "*"); + void listcrc(const char *gamename = "*"); + void listroms(const char *gamename = "*"); + void listsamples(const char *gamename = "*"); + void listdevices(const char *gamename = "*"); + void listmedia(const char *gamename = "*"); + void verifyroms(const char *gamename = "*"); + void verifysamples(const char *gamename = "*"); + void romident(const char *filename); + +private: + // internal helpers + void execute_commands(const char *exename); + void display_help(); + void display_suggestions(const char *gamename); + + // internal state + cli_options & m_options; + osd_interface & m_osd; + int m_result; +}; + + +// media_identifier class identifies media by hash via a search in +// the driver database +class media_identifier +{ +public: + // construction/destruction + media_identifier(cli_options &options); + + // getters + const char *result() const { return m_result; } + int total() const { return m_total; } + int matches() const { return m_matches; } + int nonroms() const { return m_nonroms; } + + // operations + void reset() { m_total = m_matches = m_nonroms = 0; m_result.reset(); } + void identify(const char *name); + void identify_file(const char *name); + void identify_data(const char *name, const UINT8 *data, int length); + int find_by_hash(const hash_collection &hashes, int length); + +private: + // internal state + driver_enumerator m_drivlist; + astring m_result; + int m_total; + int m_matches; + int m_nonroms; +}; -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ -int cli_execute(cli_options &options, osd_interface &osd, int argc, char **argv); - -/* informational functions */ -void cli_info_listxml(emu_options &options, const char *gamename); -void cli_info_listfull(emu_options &options, const char *gamename); -void cli_info_listsource(emu_options &options, const char *gamename); -void cli_info_listclones(emu_options &options, const char *gamename); -void cli_info_listbrothers(emu_options &options, const char *gamename); -void cli_info_listcrc(emu_options &options, const char *gamename); -void cli_info_listroms(emu_options &options, const char *gamename); -void cli_info_listsamples(emu_options &options, const char *gamename); -void cli_info_listdevices(emu_options &options, const char *gamename); #endif /* __CLIFRONT_H__ */ diff --git a/src/emu/config.c b/src/emu/config.c index 3f1b7e18d93..070f3cd4cc7 100644 --- a/src/emu/config.c +++ b/src/emu/config.c @@ -235,13 +235,13 @@ static int config_load_xml(running_machine &machine, emu_file &file, int which_t case CONFIG_TYPE_CONTROLLER: { - const game_driver *clone_of; + int clone_of; /* match on: default, game name, source file name, parent name, grandparent name */ if (strcmp(name, "default") != 0 && strcmp(name, machine.system().name) != 0 && strcmp(name, srcfile) != 0 && - ((clone_of = driver_get_clone(&machine.system())) == NULL || strcmp(name, clone_of->name) != 0) && - (clone_of == NULL || ((clone_of = driver_get_clone(clone_of)) == NULL) || strcmp(name, clone_of->name) != 0)) + ((clone_of = driver_list::clone(machine.system())) == -1 || strcmp(name, driver_list::driver(clone_of).name) != 0) && + (clone_of == -1 || ((clone_of = driver_list::clone(clone_of)) == -1) || strcmp(name, driver_list::driver(clone_of).name) != 0)) continue; break; } diff --git a/src/emu/cpu/mips/dismips.c b/src/emu/cpu/mips/dismips.c index c549cc1b6a5..339ff26ff3b 100644 --- a/src/emu/cpu/mips/dismips.c +++ b/src/emu/cpu/mips/dismips.c @@ -336,6 +336,12 @@ void *malloc_file_line(size_t size, const char *file, int line) return osd_malloc(size); } +void *malloc_array_file_line(size_t size, const char *file, int line) +{ + // allocate the memory and fail if we can't + return osd_malloc_array(size); +} + void free_file_line( void *memory, const char *file, int line ) { osd_free( memory ); diff --git a/src/emu/debug/textbuf.c b/src/emu/debug/textbuf.c index 828887f6b66..08b8fb2214e 100644 --- a/src/emu/debug/textbuf.c +++ b/src/emu/debug/textbuf.c @@ -93,7 +93,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines) return NULL; /* allocate memory for the buffer itself */ - text->buffer = (char *)osd_malloc(bytes); + text->buffer = (char *)osd_malloc_array(bytes); if (!text->buffer) { osd_free(text); @@ -101,7 +101,7 @@ text_buffer *text_buffer_alloc(UINT32 bytes, UINT32 lines) } /* allocate memory for the lines array */ - text->lineoffs = (INT32 *)osd_malloc(lines * sizeof(text->lineoffs[0])); + text->lineoffs = (INT32 *)osd_malloc_array(lines * sizeof(text->lineoffs[0])); if (!text->lineoffs) { osd_free(text->buffer); diff --git a/src/emu/devcpu.c b/src/emu/devcpu.c index 4793308c966..cddecf11f7a 100644 --- a/src/emu/devcpu.c +++ b/src/emu/devcpu.c @@ -88,6 +88,7 @@ legacy_cpu_device_config::legacy_cpu_device_config(const machine_config &mconfig // set the real name m_name = get_legacy_config_string(DEVINFO_STR_NAME); m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME); + m_searchpath = m_shortname; } diff --git a/src/emu/devintrf.c b/src/emu/devintrf.c index fa221c86d46..6e424c3f9f8 100644 --- a/src/emu/devintrf.c +++ b/src/emu/devintrf.c @@ -307,6 +307,30 @@ device_config::device_config(const machine_config &mconfig, device_type type, co } +device_config::device_config(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, const device_config *owner, UINT32 clock, UINT32 param) + : m_next(NULL), + m_owner(const_cast<device_config *>(owner)), + m_interface_list(NULL), + m_type(type), + m_clock(clock), + m_machine_config(mconfig), + m_static_config(NULL), + m_input_defaults(NULL), + m_name(name), + m_shortname(shortname), + m_searchpath(shortname), + m_tag(tag), + m_config_complete(false) +{ + // derive the clock from our owner if requested + if ((m_clock & 0xff000000) == 0xff000000) + { + assert(m_owner != NULL); + m_clock = m_owner->m_clock * ((m_clock >> 12) & 0xfff) / ((m_clock >> 0) & 0xfff); + } +} + + //------------------------------------------------- // ~device_config - destructor //------------------------------------------------- diff --git a/src/emu/devintrf.h b/src/emu/devintrf.h index f0996ea47fe..3e05c742089 100644 --- a/src/emu/devintrf.h +++ b/src/emu/devintrf.h @@ -262,6 +262,7 @@ class device_config protected: // construction/destruction device_config(const machine_config &mconfig, device_type type, const char *name, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0); + device_config(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, const device_config *owner, UINT32 clock, UINT32 param = 0); virtual ~device_config(); public: @@ -289,6 +290,7 @@ public: UINT32 clock() const { return m_clock; } const char *name() const { return m_name; } const char *shortname() const { return m_shortname; } + const char *searchpath() const { return m_searchpath; } const char *tag() const { return m_tag; } const void *static_config() const { return m_static_config; } const machine_config &mconfig() const { return m_machine_config; } @@ -336,7 +338,9 @@ protected: const input_device_default *m_input_defaults; // devices input ports default overrides astring m_name; // name of the device - astring m_shortname; // short name of the device, used for potential romload + astring m_shortname; // short name of the device + astring m_searchpath; // search path, used for media loading + private: astring m_tag; // tag for this instance bool m_config_complete; // have we completed our configuration? diff --git a/src/emu/devlegcy.c b/src/emu/devlegcy.c index 638153683e6..0b72a5aeb72 100644 --- a/src/emu/devlegcy.c +++ b/src/emu/devlegcy.c @@ -62,6 +62,7 @@ legacy_device_config_base::legacy_device_config_base(const machine_config &mconf // set the proper name m_name = get_legacy_config_string(DEVINFO_STR_NAME); m_shortname = get_legacy_config_string(DEVINFO_STR_SHORTNAME); + m_searchpath = m_shortname; } diff --git a/src/emu/devlegcy.h b/src/emu/devlegcy.h index f956614bf0c..fc7e2ddd0fb 100644 --- a/src/emu/devlegcy.h +++ b/src/emu/devlegcy.h @@ -126,7 +126,7 @@ enum DEVINFO_STR_FIRST = 0x30000, DEVINFO_STR_NAME = DEVINFO_STR_FIRST, // R/O: name of the device - DEVINFO_STR_SHORTNAME, // R/O: short name of device, used in case of romload + DEVINFO_STR_SHORTNAME, // R/O: search path of device, used for media loading DEVINFO_STR_FAMILY, // R/O: family of the device DEVINFO_STR_VERSION, // R/O: version of the device DEVINFO_STR_SOURCE_FILE, // R/O: file containing the device implementation diff --git a/src/emu/diimage.c b/src/emu/diimage.c index d6200729608..d3c31bb503f 100644 --- a/src/emu/diimage.c +++ b/src/emu/diimage.c @@ -383,7 +383,6 @@ bool device_image_interface::try_change_working_directory(const char *subdir) void device_image_interface::setup_working_directory() { - const game_driver *gamedrv; char *dst = NULL; osd_get_full_path(&dst,"."); @@ -394,10 +393,10 @@ void device_image_interface::setup_working_directory() if (try_change_working_directory("software")) { /* now down to a directory for this computer */ - gamedrv = &device().machine().system(); - while(gamedrv && !try_change_working_directory(gamedrv->name)) + int gamedrv = driver_list::find(device().machine().system()); + while(gamedrv != -1 && !try_change_working_directory(driver_list::driver(gamedrv).name)) { - gamedrv = driver_get_compatible(gamedrv); + gamedrv = driver_list::compatible_with(gamedrv); } } osd_free(dst); 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); } diff --git a/src/emu/driver.h b/src/emu/driver.h index 47e64ef6564..c920c0ca5e6 100644 --- a/src/emu/driver.h +++ b/src/emu/driver.h @@ -2,10 +2,38 @@ driver.h - Definitions relating to game drivers. - - 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. ***************************************************************************/ @@ -81,6 +109,108 @@ struct game_driver }; +// driver_list is a purely static class that wraps the global driver list +class driver_list +{ + DISABLE_COPYING(driver_list); + +protected: + // construction/destruction + driver_list(); + +public: + // getters + static int total() { return s_driver_count; } + + // any item by index + static const game_driver &driver(int index) { assert(index >= 0 && index < s_driver_count); return *s_drivers_sorted[index]; } + static int clone(int index) { return find(driver(index).parent); } + static int non_bios_clone(int index) { int result = find(driver(index).parent); return (result != -1 && (driver(result).flags & GAME_IS_BIOS_ROOT) == 0) ? result : -1; } + static int compatible_with(int index) { int result = clone(index); return (result != -1) ? result : find(driver(index).compatible_with); } + + // any item by driver + static int clone(const game_driver &driver) { int index = find(driver); assert(index != -1); return clone(index); } + static int non_bios_clone(const game_driver &driver) { int index = find(driver); assert(index != -1); return non_bios_clone(index); } + static int compatible_with(const game_driver &driver) { int index = find(driver); assert(index != -1); return compatible_with(index); } + + // general helpers + static int find(const char *name); + static int find(const game_driver &driver) { return find(driver.name); } + + // static helpers + static bool matches(const char *wildstring, const char *string) { return (wildstring == NULL || mame_strwildcmp(wildstring, string) == 0); } + +protected: + // internal helpers + static int driver_sort_callback(const void *elem1, const void *elem2); + static int penalty_compare(const char *source, const char *target); + + // internal state + static int s_driver_count; + static const game_driver * const s_drivers_sorted[]; +}; + + +// driver_enumerator enables efficient iteration through the driver list +class driver_enumerator : public driver_list +{ + DISABLE_COPYING(driver_enumerator); + +public: + // construction/destruction + driver_enumerator(emu_options &options); + driver_enumerator(emu_options &options, const char *filter); + driver_enumerator(emu_options &options, const game_driver &filter); + ~driver_enumerator(); + + // getters + int count() const { return m_filtered_count; } + int current() const { return m_current; } + emu_options &options() const { return m_options; } + + // current item + const game_driver &driver() const { return driver_list::driver(m_current); } + machine_config &config() const { return config(m_current); } + int clone() { return driver_list::clone(m_current); } + int non_bios_clone() { return driver_list::non_bios_clone(m_current); } + int compatible_with() { return driver_list::compatible_with(m_current); } + void include() { include(m_current); } + void exclude() { exclude(m_current); } + + // any item by index + bool included(int index) const { assert(index >= 0 && index < s_driver_count); return m_included[index]; } + bool excluded(int index) const { assert(index >= 0 && index < s_driver_count); return !m_included[index]; } + machine_config &config(int index) const; + void include(int index) { assert(index >= 0 && index < s_driver_count); if (!m_included[index]) { m_included[index] = true; m_filtered_count++; } } + void exclude(int index) { assert(index >= 0 && index < s_driver_count); if (m_included[index]) { m_included[index] = false; m_filtered_count--; } } + using driver_list::driver; + using driver_list::clone; + using driver_list::non_bios_clone; + using driver_list::compatible_with; + + // filtering/iterating + int filter(const char *string = NULL); + int filter(const game_driver &driver); + void include_all() { memset(m_included, 1, sizeof(m_included[0]) * s_driver_count); m_filtered_count = s_driver_count; } + void exclude_all() { memset(m_included, 0, sizeof(m_included[0]) * s_driver_count); m_filtered_count = 0; } + void reset() { m_current = -1; } + bool next(); + bool next_excluded(); + + // general helpers + void set_current(int index) { assert(index >= -1 && index <= s_driver_count); m_current = index; } + void find_approximate_matches(const char *string, int count, int *results); + +private: + // internal state + int m_current; + int m_filtered_count; + emu_options & m_options; + UINT8 * m_included; + machine_config ** m_config; +}; + + /*************************************************************************** MACROS FOR BUILDING GAME DRIVERS @@ -176,24 +306,8 @@ extern const game_driver GAME_NAME(NAME) = \ GLOBAL VARIABLES ***************************************************************************/ -extern const game_driver * const drivers[]; - -GAME_EXTERN(empty); - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -const game_driver *driver_get_name(const char *name); -const game_driver *driver_get_clone(const game_driver *driver); -const game_driver *driver_get_compatible(const game_driver *drv); - -const char *driver_get_searchpath(const game_driver &driver, astring &string); +GAME_EXTERN(___empty); -void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list); -int driver_list_get_count(const game_driver * const driverlist[]); #endif diff --git a/src/emu/drivers/empty.c b/src/emu/drivers/empty.c index bea3c2231ab..d4ce7079f31 100644 --- a/src/emu/drivers/empty.c +++ b/src/emu/drivers/empty.c @@ -20,7 +20,7 @@ * *************************************/ -static MACHINE_START( empty ) +static MACHINE_START( ___empty ) { /* force the UI to show the game select screen */ ui_menu_force_game_select(machine, &machine.render().ui_container()); @@ -34,9 +34,9 @@ static MACHINE_START( empty ) * *************************************/ -static MACHINE_CONFIG_START( empty, driver_device ) +static MACHINE_CONFIG_START( ___empty, driver_device ) - MCFG_MACHINE_START(empty) + MCFG_MACHINE_START(___empty) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) @@ -54,8 +54,8 @@ MACHINE_CONFIG_END * *************************************/ -ROM_START( empty ) - ROM_REGION( 0x10, "user1", 0 ) +ROM_START( ___empty ) + ROM_REGION( 0x10, "user1", ROMREGION_ERASEFF ) ROM_END @@ -66,4 +66,4 @@ ROM_END * *************************************/ -GAME( 2007, empty, 0, empty, 0, 0, ROT0, "MAME", "No Driver Loaded", 0 ) +GAME( 2007, ___empty, 0, ___empty, 0, 0, ROT0, "MAME", "No Driver Loaded", GAME_NO_SOUND ) diff --git a/src/emu/emu.mak b/src/emu/emu.mak index d336f113876..73663d48c86 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -338,5 +338,6 @@ $(EMUOBJ)/rendlay.o: $(EMULAYOUT)/dualhovu.lh \ $(EMULAYOUT)/voffff20.lh \ $(EMULAYOUT)/lcd.lh \ $(EMULAYOUT)/lcd_rot.lh \ + $(EMULAYOUT)/pinball.lh \ $(EMUOBJ)/video.o: $(EMULAYOUT)/snap.lh diff --git a/src/emu/emualloc.c b/src/emu/emualloc.c index 75b972e0eeb..a3164e8e913 100644 --- a/src/emu/emualloc.c +++ b/src/emu/emualloc.c @@ -92,6 +92,7 @@ public: static UINT64 s_curid; // current ID static osd_lock * s_lock; // lock for managing the list static bool s_lock_alloc; // set to true temporarily during lock allocation + static bool s_tracking; // set to true when tracking is live static memory_entry *s_hash[k_hash_prime];// hash table based on pointer static memory_entry *s_freehead; // pointer to the head of the free list @@ -118,9 +119,10 @@ resource_pool global_resource_pool; const zeromem_t zeromem = { }; // globals for memory_entry -UINT64 memory_entry::s_curid = 0; +UINT64 memory_entry::s_curid = 1; osd_lock *memory_entry::s_lock = NULL; bool memory_entry::s_lock_alloc = false; +bool memory_entry::s_tracking = false; memory_entry *memory_entry::s_hash[memory_entry::k_hash_prime] = { NULL }; memory_entry *memory_entry::s_freehead = NULL; @@ -155,6 +157,31 @@ void *malloc_file_line(size_t size, const char *file, int line) //------------------------------------------------- +// malloc_array_file_line - allocate memory with +// file and line number information, and a hint +// that this object is an array +//------------------------------------------------- + +void *malloc_array_file_line(size_t size, const char *file, int line) +{ + // allocate the memory and fail if we can't + void *result = osd_malloc_array(size); + if (result == NULL) + return NULL; + + // add a new entry + memory_entry::allocate(size, result, file, line); + +#ifdef MAME_DEBUG + // randomize the memory + rand_memory(result, size); +#endif + + return result; +} + + +//------------------------------------------------- // free_file_line - free memory with file // and line number information //------------------------------------------------- @@ -189,7 +216,19 @@ void free_file_line(void *memory, const char *file, int line) // memory //------------------------------------------------- -void dump_unfreed_mem(void) +void track_memory(bool track) +{ + memory_entry::s_tracking = track; +} + + +//------------------------------------------------- +// dump_unfreed_mem - called from the exit path +// of any code that wants to check for unfreed +// memory +//------------------------------------------------- + +void dump_unfreed_mem() { #ifdef MAME_DEBUG memory_entry::report_unfreed(); @@ -446,7 +485,7 @@ memory_entry *memory_entry::allocate(size_t size, void *base, const char *file, if (s_freehead == NULL) { // create a new chunk, and fail if we can't - memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc(memory_block_alloc_chunk * sizeof(memory_entry))); + memory_entry *entry = reinterpret_cast<memory_entry *>(osd_malloc_array(memory_block_alloc_chunk * sizeof(memory_entry))); if (entry == NULL) { release_lock(); @@ -468,8 +507,8 @@ memory_entry *memory_entry::allocate(size_t size, void *base, const char *file, // populate it entry->m_size = size; entry->m_base = base; - entry->m_file = file; - entry->m_line = line; + entry->m_file = s_tracking ? file : NULL; + entry->m_line = s_tracking ? line : 0; entry->m_id = s_curid++; if (LOG_ALLOCS) fprintf(stderr, "#%06d, alloc %d bytes (%s:%d)\n", (UINT32)entry->m_id, static_cast<UINT32>(entry->m_size), entry->m_file, (int)entry->m_line); @@ -561,5 +600,5 @@ void memory_entry::report_unfreed() release_lock(); if (total > 0) - fprintf(stderr, "a total of %d bytes were not free()'d\n", total); + fprintf(stderr, "a total of %d bytes were not freed\n", total); } diff --git a/src/emu/emualloc.h b/src/emu/emualloc.h index 0a26fcad3ec..e4da24c52a5 100644 --- a/src/emu/emualloc.h +++ b/src/emu/emualloc.h @@ -47,9 +47,25 @@ //************************************************************************** +// DEBUGGING +//************************************************************************** + +// set to 1 to track memory allocated by emualloc.h itself as well +#define TRACK_SELF_MEMORY (0) + + + +//************************************************************************** // MACROS //************************************************************************** +// self-allocation helpers +#if TRACK_SELF_MEMORY +#define EMUALLOC_SELF_NEW new(__FILE__, __LINE__) +#else +#define EMUALLOC_SELF_NEW new +#endif + // pool allocation helpers #define pool_alloc(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__) _type) #define pool_alloc_clear(_pool, _type) (_pool).add_object(new(__FILE__, __LINE__, zeromem) _type) @@ -72,11 +88,13 @@ // allocate memory with file and line number information void *malloc_file_line(size_t size, const char *file, int line); +void *malloc_array_file_line(size_t size, const char *file, int line); // free memory with file and line number information void free_file_line(void *memory, const char *file, int line); // called from the exit path of any code that wants to check for unfreed memory +void track_memory(bool track); void dump_unfreed_mem(); @@ -100,7 +118,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size) throw (std::bad_al ATTR_FORCE_INLINE inline void *operator new[](std::size_t size) throw (std::bad_alloc) { - void *result = malloc_file_line(size, NULL, 0); + void *result = malloc_array_file_line(size, NULL, 0); if (result == NULL) throw std::bad_alloc(); return result; @@ -130,7 +148,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file, ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line) throw (std::bad_alloc) { - void *result = malloc_file_line(size, file, line); + void *result = malloc_array_file_line(size, file, line); if (result == NULL) throw std::bad_alloc(); return result; @@ -161,7 +179,7 @@ ATTR_FORCE_INLINE inline void *operator new(std::size_t size, const char *file, ATTR_FORCE_INLINE inline void *operator new[](std::size_t size, const char *file, int line, const zeromem_t &) throw (std::bad_alloc) { - void *result = malloc_file_line(size, file, line); + void *result = malloc_array_file_line(size, file, line); if (result == NULL) throw std::bad_alloc(); memset(result, 0, size); @@ -270,8 +288,8 @@ public: bool contains(void *ptrstart, void *ptrend); void clear(); - template<class T> T *add_object(T* object) { add(*new(__FILE__, __LINE__) resource_pool_object<T>(object)); return object; } - template<class T> T *add_array(T* array, int count) { add(*new(__FILE__, __LINE__) resource_pool_array<T>(array, count)); return array; } + template<class T> T *add_object(T* object) { add(*EMUALLOC_SELF_NEW resource_pool_object<T>(object)); return object; } + template<class T> T *add_array(T* array, int count) { add(*EMUALLOC_SELF_NEW resource_pool_array<T>(array, count)); return array; } private: static const int k_hash_prime = 193; @@ -306,7 +324,7 @@ extern const zeromem_t zeromem; #undef realloc #undef free -#define malloc(x) malloc_file_line(x, __FILE__, __LINE__) +#define malloc(x) malloc_array_file_line(x, __FILE__, __LINE__) #define calloc(x,y) __error_use_auto_alloc_clear_or_global_alloc_clear_instead__ #define realloc(x,y) __error_realloc_is_dangerous__ #define free(x) free_file_line(x, __FILE__, __LINE__) diff --git a/src/emu/emuopts.c b/src/emu/emuopts.c index 69cca4f8b87..7753b8e83ac 100644 --- a/src/emu/emuopts.c +++ b/src/emu/emuopts.c @@ -349,12 +349,12 @@ void emu_options::parse_standard_inis(astring &error_string) } // then parse the grandparent, parent, and system-specific INIs - const game_driver *parent = driver_get_clone(cursystem); - const game_driver *gparent = (parent != NULL) ? driver_get_clone(parent) : NULL; - if (gparent != NULL) - parse_one_ini(gparent->name, OPTION_PRIORITY_GPARENT_INI, &error_string); - if (parent != NULL) - parse_one_ini(parent->name, OPTION_PRIORITY_PARENT_INI, &error_string); + int parent = driver_list::clone(*cursystem); + int gparent = (parent != -1) ? driver_list::clone(parent) : -1; + if (gparent != -1) + parse_one_ini(driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_string); + if (parent != -1) + parse_one_ini(driver_list::driver(parent).name, OPTION_PRIORITY_PARENT_INI, &error_string); parse_one_ini(cursystem->name, OPTION_PRIORITY_DRIVER_INI, &error_string); } @@ -367,7 +367,8 @@ void emu_options::parse_standard_inis(astring &error_string) const game_driver *emu_options::system() const { astring tempstr; - return driver_get_name(*core_filename_extract_base(&tempstr, system_name(), TRUE)); + int index = driver_list::find(*core_filename_extract_base(&tempstr, system_name(), TRUE)); + return (index != -1) ? &driver_list::driver(index) : NULL; } diff --git a/src/emu/emutempl.h b/src/emu/emutempl.h index 74fe8501f6c..c4fd064c155 100644 --- a/src/emu/emutempl.h +++ b/src/emu/emutempl.h @@ -245,6 +245,37 @@ private: }; +// ======================> simple_list_wrapper + +// a simple_list_wrapper wraps an existing object with a next pointer so it +// can live in a simple_list without requiring the object to have a next +// pointer +template<class T> +class simple_list_wrapper +{ +public: + // construction/destruction + simple_list_wrapper(T *object) + : m_next(NULL), + m_object(object) { } + + // operators + operator T *() { return m_object; } + operator T *() const { return m_object; } + T *operator *() { return m_object; } + T *operator *() const { return m_object; } + + // getters + simple_list_wrapper *next() const { return m_next; } + T *object() const { return m_object; } + +private: + // internal state + simple_list_wrapper * m_next; + T * m_object; +}; + + // ======================> fixed_allocator // a fixed_allocator is a simple class that maintains a free pool of objects diff --git a/src/emu/hash.c b/src/emu/hash.c index 5d55f26d642..12f94dd1f5f 100644 --- a/src/emu/hash.c +++ b/src/emu/hash.c @@ -593,7 +593,7 @@ bool hash_collection::remove(char type) // crc - return the CRC hash if present //------------------------------------------------- -bool hash_collection::crc(UINT32 &result) +bool hash_collection::crc(UINT32 &result) const { // attempt to find the CRC hash; if we fail, return false hash_base *crchash = hash(HASH_CRC); @@ -601,7 +601,7 @@ bool hash_collection::crc(UINT32 &result) return false; // downcast to a hash_crc and convert to a UINT32 - result = *downcast<hash_crc *>(crchash); + result = *downcast<const hash_crc *>(crchash); return true; } diff --git a/src/emu/hash.h b/src/emu/hash.h index a89c7cee4b2..3f5995edb51 100644 --- a/src/emu/hash.h +++ b/src/emu/hash.h @@ -161,7 +161,7 @@ public: bool remove(char type); // CRC-specific helpers - bool crc(UINT32 &result); + bool crc(UINT32 &result) const; hash_base *add_crc(UINT32 crc); // string conversion diff --git a/src/emu/info.c b/src/emu/info.c index d0e39604249..7ee5c261500 100644 --- a/src/emu/info.c +++ b/src/emu/info.c @@ -4,8 +4,36 @@ Dumps the MAME internal data as an XML file. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + 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. ***************************************************************************/ @@ -19,7 +47,8 @@ #include <ctype.h> -/* MESS/MAME configuration */ + +// MAME vs MESS configuration #ifdef MESS #define XML_ROOT "mess" #define XML_TOP "machine" @@ -30,522 +59,375 @@ -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -class parent_info +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// DTD string describing the data +const char info_xml_creator::s_dtd_string[] = +"<!DOCTYPE " XML_ROOT " [\n" +"<!ELEMENT " XML_ROOT " (" XML_TOP "+)>\n" +"\t<!ATTLIST " XML_ROOT " build CDATA #IMPLIED>\n" +"\t<!ATTLIST " XML_ROOT " debug (yes|no) \"no\">\n" +"\t<!ATTLIST " XML_ROOT " mameconfig CDATA #REQUIRED>\n" +"\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, category*, adjuster*, driver?, device*, softwarelist*, ramoption*)>\n" +"\t\t<!ATTLIST " XML_TOP " name CDATA #REQUIRED>\n" +"\t\t<!ATTLIST " XML_TOP " sourcefile CDATA #IMPLIED>\n" +"\t\t<!ATTLIST " XML_TOP " isbios (yes|no) \"no\">\n" +"\t\t<!ATTLIST " XML_TOP " ismechanical (yes|no) \"no\">\n" +"\t\t<!ATTLIST " XML_TOP " runnable (yes|no) \"yes\">\n" +"\t\t<!ATTLIST " XML_TOP " cloneof CDATA #IMPLIED>\n" +"\t\t<!ATTLIST " XML_TOP " romof CDATA #IMPLIED>\n" +"\t\t<!ATTLIST " XML_TOP " sampleof CDATA #IMPLIED>\n" +"\t\t<!ELEMENT description (#PCDATA)>\n" +"\t\t<!ELEMENT year (#PCDATA)>\n" +"\t\t<!ELEMENT manufacturer (#PCDATA)>\n" +"\t\t<!ELEMENT biosset EMPTY>\n" +"\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n" +"\t\t<!ELEMENT rom EMPTY>\n" +"\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom md5 CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n" +"\t\t\t<!ATTLIST rom optional (yes|no) \"no\">\n" +"\t\t<!ELEMENT disk EMPTY>\n" +"\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST disk md5 CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n" +"\t\t\t<!ATTLIST disk optional (yes|no) \"no\">\n" +"\t\t<!ELEMENT sample EMPTY>\n" +"\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n" +"\t\t<!ELEMENT chip EMPTY>\n" +"\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n" +"\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n" +"\t\t<!ELEMENT display EMPTY>\n" +"\t\t\t<!ATTLIST display type (raster|vector|lcd|unknown) #REQUIRED>\n" +"\t\t\t<!ATTLIST display rotate (0|90|180|270) #REQUIRED>\n" +"\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n" +"\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n" +"\t\t<!ELEMENT sound EMPTY>\n" +"\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n" +"\t\t<!ELEMENT input (control*)>\n" +"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n" +"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n" +"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n" +"\t\t\t<!ELEMENT control EMPTY>\n" +"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n" +"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n" +"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n" +"\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n" +"\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n" +"\t\t<!ELEMENT dipswitch (dipvalue*)>\n" +"\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n" +"\t\t\t<!ELEMENT dipvalue EMPTY>\n" +"\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n" +"\t\t<!ELEMENT configuration (confsetting*)>\n" +"\t\t\t<!ATTLIST configuration name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST configuration tag CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST configuration mask CDATA #REQUIRED>\n" +"\t\t\t<!ELEMENT confsetting EMPTY>\n" +"\t\t\t\t<!ATTLIST confsetting name CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST confsetting value CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST confsetting default (yes|no) \"no\">\n" +"\t\t<!ELEMENT category (item*)>\n" +"\t\t\t<!ATTLIST category name CDATA #REQUIRED>\n" +"\t\t\t<!ELEMENT item EMPTY>\n" +"\t\t\t\t<!ATTLIST item name CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST item default (yes|no) \"no\">\n" +"\t\t<!ELEMENT adjuster EMPTY>\n" +"\t\t\t<!ATTLIST adjuster name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST adjuster default CDATA #REQUIRED>\n" +"\t\t<!ELEMENT driver EMPTY>\n" +"\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver color (good|imperfect|preliminary) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver sound (good|imperfect|preliminary) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver graphic (good|imperfect|preliminary) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n" +"\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n" +"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n" +"\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n" +"\t\t<!ELEMENT device (instance*, extension*)>\n" +"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n" +"\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n" +"\t\t\t<!ELEMENT instance EMPTY>\n" +"\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n" +"\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n" +"\t\t\t<!ELEMENT extension EMPTY>\n" +"\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n" +"\t\t<!ELEMENT softwarelist EMPTY>\n" +"\t\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n" +"\t\t\t<!ATTLIST softwarelist status (original|compatible) #REQUIRED>\n" +"\t\t<!ELEMENT ramoption (#PCDATA)>\n" +"\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n" +"]>"; + + + +//************************************************************************** +// INFO XML CREATOR +//************************************************************************** + +//------------------------------------------------- +// info_xml_creator - constructor +//------------------------------------------------- + +info_xml_creator::info_xml_creator(driver_enumerator &drivlist) + : m_output(NULL), + m_drivlist(drivlist) { -public: - const game_driver *drv; - machine_config mconfig; - - parent_info(const game_driver *drv, emu_options &options) : mconfig(*drv, options) - { - this->drv = drv; - } -}; - +} -/*************************************************************************** - CORE IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - print_game_switches - print the DIP switch - settings for a game --------------------------------------------------*/ +//------------------------------------------------- +// output_mame_xml - print the XML information +// for all known games +//------------------------------------------------- -static void print_game_switches(FILE *out, const game_driver *game, const ioport_list &portlist) +void info_xml_creator::output(FILE *out) { - const input_port_config *port; - const input_field_config *field; - - /* iterate looking for DIP switches */ - for (port = portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) - if (field->type == IPT_DIPSWITCH) - { - const input_setting_config *setting; - - /* output the switch name information */ - fprintf(out, "\t\t<dipswitch name=\"%s\"", xml_normalize_string(input_field_name(field))); - fprintf(out, " tag=\"%s\"", xml_normalize_string(field->port->tag)); - fprintf(out, " mask=\"%u\"", field->mask); - fprintf(out, ">\n"); + m_output = out; + + // output the DTD + fprintf(m_output, "<?xml version=\"1.0\"?>\n"); + fprintf(m_output, "%s\n\n", s_dtd_string); + + // top-level tag + fprintf(m_output, "<" XML_ROOT " build=\"%s\" debug=\"" +#ifdef MAME_DEBUG + "yes" +#else + "no" +#endif + "\" mameconfig=\"%d\">\n", + xml_normalize_string(build_version), + CONFIG_VERSION + ); - /* loop over settings */ - for (setting = field->settinglist; setting != NULL; setting = setting->next) - { - fprintf(out, "\t\t\t<dipvalue name=\"%s\"", xml_normalize_string(setting->name)); - fprintf(out, " value=\"%u\"", setting->value); - if (setting->value == field->defvalue) - fprintf(out, " default=\"yes\""); - fprintf(out, "/>\n"); - } + // iterate through the drivers, outputting one at a time + while (m_drivlist.next()) + output_one(); - /* terminate the switch entry */ - fprintf(out, "\t\t</dipswitch>\n"); - } + // close the top level tag + fprintf(m_output, "</" XML_ROOT ">\n"); } -/*------------------------------------------------- - print_game_configs - print the Configuration - settings for a game --------------------------------------------------*/ -static void print_game_configs(FILE *out, const game_driver *game, const ioport_list &portlist) -{ - const input_port_config *port; - const input_field_config *field; +//------------------------------------------------- +// output_one - print the XML information +// for one particular game driver +//------------------------------------------------- - /* iterate looking for configurations */ - for (port = portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) - if (field->type == IPT_CONFIG) - { - const input_setting_config *setting; +void info_xml_creator::output_one() +{ + // no action if not a game + const game_driver &driver = m_drivlist.driver(); + if (driver.flags & GAME_NO_STANDALONE) + return; - /* output the configuration name information */ - fprintf(out, "\t\t<configuration name=\"%s\"", xml_normalize_string(input_field_name(field))); - fprintf(out, " tag=\"%s\"", xml_normalize_string(field->port->tag)); - fprintf(out, " mask=\"%u\"", field->mask); - fprintf(out, ">\n"); + // allocate input ports + machine_config &config = m_drivlist.config(); + ioport_list portlist; + input_port_list_init(portlist, driver.ipt, NULL, 0, FALSE, NULL); + for (device_config *cfg = config.m_devicelist.first(); cfg != NULL; cfg = cfg->next()) + if (cfg->input_ports() != NULL) + input_port_list_init(portlist, cfg->input_ports(), NULL, 0, FALSE, cfg); - /* loop over settings */ - for (setting = field->settinglist; setting != NULL; setting = setting->next) - { - fprintf(out, "\t\t\t<confsetting name=\"%s\"", xml_normalize_string(setting->name)); - fprintf(out, " value=\"%u\"", setting->value); - if (setting->value == field->defvalue) - fprintf(out, " default=\"yes\""); - fprintf(out, "/>\n"); - } + // print the header and the game name + fprintf(m_output, "\t<" XML_TOP); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(driver.name)); - /* terminate the configuration entry */ - fprintf(out, "\t\t</configuration>\n"); - } + // strip away any path information from the source_file and output it + const char *start = strrchr(driver.source_file, '/'); + if (start == NULL) + start = strrchr(driver.source_file, '\\'); + if (start == NULL) + start = driver.source_file - 1; + fprintf(m_output, " sourcefile=\"%s\"", xml_normalize_string(start + 1)); + + // append bios and runnable flags + if (driver.flags & GAME_IS_BIOS_ROOT) + fprintf(m_output, " isbios=\"yes\""); + if (driver.flags & GAME_NO_STANDALONE) + fprintf(m_output, " runnable=\"no\""); + if (driver.flags & GAME_MECHANICAL) + fprintf(m_output, " ismechanical=\"yes\""); + + // display clone information + int clone_of = m_drivlist.find(driver.parent); + if (clone_of != -1 && !(m_drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT)) + fprintf(m_output, " cloneof=\"%s\"", xml_normalize_string(m_drivlist.driver(clone_of).name)); + if (clone_of != -1) + fprintf(m_output, " romof=\"%s\"", xml_normalize_string(m_drivlist.driver(clone_of).name)); + + // display sample information and close the game tag + output_sampleof(); + fprintf(m_output, ">\n"); + + // output game description + if (driver.description != NULL) + fprintf(m_output, "\t\t<description>%s</description>\n", xml_normalize_string(driver.description)); + + // print the year only if is a number or another allowed character (? or +) + if (driver.year != NULL && strspn(driver.year, "0123456789?+") == strlen(driver.year)) + fprintf(m_output, "\t\t<year>%s</year>\n", xml_normalize_string(driver.year)); + + // print the manufacturer information + if (driver.manufacturer != NULL) + fprintf(m_output, "\t\t<manufacturer>%s</manufacturer>\n", xml_normalize_string(driver.manufacturer)); + + // now print various additional information + output_bios(); + output_rom(); + output_sample(); + output_chips(); + output_display(); + output_sound(); + output_input(portlist); + output_switches(portlist, IPT_DIPSWITCH, "dipswitch", "dipvalue"); + output_switches(portlist, IPT_CONFIG, "configuration", "confsetting"); + output_categories(portlist); + output_adjusters(portlist); + output_driver(); + output_images(); + output_software_list(); + output_ramoptions(); + + // close the topmost tag + fprintf(m_output, "\t</" XML_TOP ">\n"); } -/*------------------------------------------------- - print_game_adjusters - print the Analog - Adjusters for a game --------------------------------------------------*/ - -static void print_game_adjusters(FILE *out, const game_driver *game, const ioport_list &portlist) -{ - const input_port_config *port; - const input_field_config *field; - /* iterate looking for Adjusters */ - for (port = portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) - if (field->type == IPT_ADJUSTER) - { - /* output the adjuster information */ - fprintf(out, "\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", xml_normalize_string(input_field_name(field)), field->defvalue); - } -} +//------------------------------------------------ +// output_sampleof - print the 'sampleof' +// attribute, if appropriate +//------------------------------------------------- -/*------------------------------------------------- - print_game_input - print a summary of a game's - input --------------------------------------------------*/ - -static void print_game_input(FILE *out, const game_driver *game, const ioport_list &portlist) +void info_xml_creator::output_sampleof() { - /* fix me -- this needs to be cleaned up to match the core style */ - -enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ckeypad, ckeyboard, ENDCONTROLTYPES}; - int nplayer = 0; - int nbutton = 0; - int ncoin = 0; - //int controlsyes = 0; - int analogcontrol = 0; - int i; - const char* service = 0; - const char* tilt = 0; - const char* const control_types[] = {"joy", "doublejoy", "stick", "dial", "trackball", "paddle", "lightgun", "pedal", "keypad", "keyboard"}; - static struct _input_info - { - const char * type; /* general type of input */ - const char * Xway; /* 2, 4, or 8 way */ - int analog; - int keyb; - int min; /* analog minimum value */ - int max; /* analog maximum value */ - int sensitivity; /* default analog sensitivity */ - int keydelta; /* default analog keydelta */ - int reverse; /* default analog reverse setting */ - } control[ENDCONTROLTYPES]; - const input_port_config *port; - const input_field_config *field; - - for (i = 0; i < ENDCONTROLTYPES; i++) + // iterate over sample devices + for (const device_config *devconfig = m_drivlist.config().m_devicelist.first(SAMPLES); devconfig != NULL; devconfig = devconfig->typenext()) { - control[i].type = control_types[i]; - control[i].Xway = NULL; - control[i].analog = 0; - control[i].keyb = 0; - control[i].min = 0; - control[i].max = 0; - control[i].sensitivity = 0; - control[i].keydelta = 0; - control[i].reverse = 0; - } - - for (port = portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) - { + const char *const *samplenames = ((const samples_interface *)devconfig->static_config())->samplenames; + if (samplenames != NULL) - if (nplayer < field->player + 1) - nplayer = field->player + 1; - - switch (field->type) + // iterate over sample names + for (int sampnum = 0; samplenames[sampnum] != NULL; sampnum++) { - case IPT_JOYSTICK_LEFT: - case IPT_JOYSTICK_RIGHT: - - /* if control not defined, start it off as horizontal 2-way */ - if (control[cjoy].Xway == NULL) - control[cjoy].Xway = "joy2way"; - else if (strcmp(control[cjoy].Xway,"joy2way") == 0) - ; - /* if already defined as vertical, make it 4 or 8 way */ - else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0) - { - if (field->way == 4) - control[cjoy].Xway = "joy4way"; - else - control[cjoy].Xway = "joy8way"; - } - //controlsyes = 1; - break; - - case IPT_JOYSTICK_UP: - case IPT_JOYSTICK_DOWN: + // only output sampleof if different from the game name + const char *cursampname = samplenames[sampnum]; + if (cursampname[0] == '*' && strcmp(cursampname + 1, m_drivlist.driver().name) != 0) + fprintf(m_output, " sampleof=\"%s\"", xml_normalize_string(cursampname + 1)); - /* if control not defined, start it off as vertical 2-way */ - if (control[cjoy].Xway == NULL) - control[cjoy].Xway = "vjoy2way"; - else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0) - ; - /* if already defined as horiz, make it 4 or 8way */ - else if (strcmp(control[cjoy].Xway,"joy2way") == 0) - { - if (field->way == 4) - control[cjoy].Xway = "joy4way"; - else - control[cjoy].Xway = "joy8way"; - } - //controlsyes = 1; - break; - - case IPT_JOYSTICKRIGHT_UP: - case IPT_JOYSTICKRIGHT_DOWN: - case IPT_JOYSTICKLEFT_UP: - case IPT_JOYSTICKLEFT_DOWN: - - /* if control not defined, start it off as vertical 2way */ - if (control[cdoublejoy].Xway == NULL) - control[cdoublejoy].Xway = "vdoublejoy2way"; - else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0) - ; - /* if already defined as horiz, make it 4 or 8 way */ - else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0) - { - if (field->way == 4) - control[cdoublejoy].Xway = "doublejoy4way"; - else - control[cdoublejoy].Xway = "doublejoy8way"; - } - //controlsyes = 1; - break; - - case IPT_JOYSTICKRIGHT_LEFT: - case IPT_JOYSTICKRIGHT_RIGHT: - case IPT_JOYSTICKLEFT_LEFT: - case IPT_JOYSTICKLEFT_RIGHT: - - /* if control not defined, start it off as horiz 2-way */ - if (control[cdoublejoy].Xway == NULL) - control[cdoublejoy].Xway = "doublejoy2way"; - else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0) - ; - /* if already defined as vertical, make it 4 or 8 way */ - else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0) - { - if (field->way == 4) - control[cdoublejoy].Xway = "doublejoy4way"; - else - control[cdoublejoy].Xway = "doublejoy8way"; - } - //controlsyes = 1; - break; - - /* mark as an analog input, and get analog stats after switch */ - case IPT_PADDLE: - analogcontrol = cpaddle; - break; - case IPT_DIAL: - analogcontrol = cdial; - break; - case IPT_TRACKBALL_X: - case IPT_TRACKBALL_Y: - analogcontrol = ctrackball; - break; - case IPT_AD_STICK_X: - case IPT_AD_STICK_Y: - analogcontrol = cAD_stick; - break; - case IPT_LIGHTGUN_X: - case IPT_LIGHTGUN_Y: - analogcontrol = clightgun; - break; - case IPT_PEDAL: - case IPT_PEDAL2: - case IPT_PEDAL3: - analogcontrol = cpedal; - break; - - case IPT_BUTTON1: - case IPT_BUTTON2: - case IPT_BUTTON3: - case IPT_BUTTON4: - case IPT_BUTTON5: - case IPT_BUTTON6: - case IPT_BUTTON7: - case IPT_BUTTON8: - case IPT_BUTTON9: - case IPT_BUTTON10: - case IPT_BUTTON11: - case IPT_BUTTON12: - case IPT_BUTTON13: - case IPT_BUTTON14: - case IPT_BUTTON15: - case IPT_BUTTON16: - nbutton = MAX(nbutton, field->type - IPT_BUTTON1 + 1); - break; - - case IPT_COIN1: - case IPT_COIN2: - case IPT_COIN3: - case IPT_COIN4: - case IPT_COIN5: - case IPT_COIN6: - case IPT_COIN7: - case IPT_COIN8: - ncoin = MAX(ncoin, field->type - IPT_COIN1 + 1); - - case IPT_SERVICE : - service = "yes"; - break; - - case IPT_TILT : - tilt = "yes"; - break; - - case IPT_KEYPAD: - control[ckeypad].keyb = 1; - break; - - case IPT_KEYBOARD: - control[ckeyboard].keyb = 1; - break; - } - - /* get the analog stats */ - if (analogcontrol) - { - //controlsyes = 1; - control[analogcontrol].analog = 1; - - if (field->min) - control[analogcontrol].min = field->min; - if (field->max) - control[analogcontrol].max = field->max; - if (field->sensitivity) - control[analogcontrol].sensitivity = field->sensitivity; - if (field->delta) - control[analogcontrol].keydelta = field->delta; - if (field->flags & ANALOG_FLAG_REVERSE) - control[analogcontrol].reverse = 1; - - analogcontrol = 0; - } - } - - fprintf(out, "\t\t<input"); - fprintf(out, " players=\"%d\"", nplayer); - if (nbutton != 0) - fprintf(out, " buttons=\"%d\"", nbutton); - if (ncoin != 0) - fprintf(out, " coins=\"%d\"", ncoin); - if (service != NULL) - fprintf(out, " service=\"%s\"", xml_normalize_string(service)); - if (tilt != NULL) - fprintf(out, " tilt=\"%s\"", xml_normalize_string(tilt)); - fprintf(out, ">\n"); - - for (i = 0; i < ENDCONTROLTYPES; i++) - { - if (control[i].Xway != NULL) - fprintf(out, "\t\t\t<control type=\"%s\"/>\n", xml_normalize_string(control[i].Xway)); - if (control[i].analog) - { - fprintf(out, "\t\t\t<control type=\"%s\"", xml_normalize_string(control_types[i])); - if (control[i].min || control[i].max) - { - fprintf(out, " minimum=\"%d\"", control[i].min); - fprintf(out, " maximum=\"%d\"", control[i].max); + // must stop here, as there can only be one attribute of the same name + return; } - if (control[i].sensitivity) - fprintf(out, " sensitivity=\"%d\"", control[i].sensitivity); - if (control[i].keydelta) - fprintf(out, " keydelta=\"%d\"", control[i].keydelta); - if (control[i].reverse) - fprintf(out, " reverse=\"yes\""); - - fprintf(out, "/>\n"); - } - if (control[i].keyb) - { - fprintf(out, "\t\t\t<control type=\"%s\"/>\n", xml_normalize_string(control_types[i])); - } } - fprintf(out, "\t\t</input>\n"); } -/*------------------------------------------------- - print_game_bios - print the BIOS set for a - game --------------------------------------------------*/ +//------------------------------------------------- +// output_bios - print the BIOS set for a +// game +//------------------------------------------------- -static void print_game_bios(FILE *out, const game_driver *game) +void info_xml_creator::output_bios() { - const rom_entry *rom; - - /* skip if no ROMs */ - if (game->rom == NULL) + // skip if no ROMs + if (m_drivlist.driver().rom == NULL) return; - /* iterate over ROM entries and look for BIOSes */ - for (rom = game->rom; !ROMENTRY_ISEND(rom); rom++) + // iterate over ROM entries and look for BIOSes + for (const rom_entry *rom = m_drivlist.driver().rom; !ROMENTRY_ISEND(rom); rom++) if (ROMENTRY_ISSYSTEM_BIOS(rom)) { - const char *name = ROM_GETNAME(rom); - const char *description = ROM_GETHASHDATA(rom); - - /* output extracted name and descriptions */ - fprintf(out, "\t\t<biosset"); - fprintf(out, " name=\"%s\"", xml_normalize_string(name)); - fprintf(out, " description=\"%s\"", xml_normalize_string(description)); + // output extracted name and descriptions + fprintf(m_output, "\t\t<biosset"); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom))); + fprintf(m_output, " description=\"%s\"", xml_normalize_string(ROM_GETHASHDATA(rom))); if (ROM_GETBIOSFLAGS(rom) == 1) - fprintf(out, " default=\"yes\""); - fprintf(out, "/>\n"); + fprintf(m_output, " default=\"yes\""); + fprintf(m_output, "/>\n"); } } -/*------------------------------------------------- - get_merge_name - get the rom name from a - parent set --------------------------------------------------*/ - -static const char *get_merge_name(const hash_collection &romhashes, int parents, const parent_info **pinfoarray) -{ - int parent; - const char *merge_name = NULL; - - for (parent = 0; parent < parents; ++parent) - { - const machine_config *pconfig = &pinfoarray[parent]->mconfig; - const rom_source *psource; - const rom_entry *pregion, *prom; - - /* scan the clone_of ROM for a matching ROM entry */ - for (psource = rom_first_source(*pconfig); psource != NULL; psource = rom_next_source(*psource)) - for (pregion = rom_first_region(*psource); pregion != NULL; pregion = rom_next_region(pregion)) - for (prom = rom_first_file(pregion); prom != NULL; prom = rom_next_file(prom)) - { - hash_collection phashes(ROM_GETHASHDATA(prom)); - if (!phashes.flag(hash_collection::FLAG_NO_DUMP) && romhashes == phashes) - { - merge_name = ROM_GETNAME(prom); - break; - } - } - } - - return merge_name; -} +//------------------------------------------------- +// output_rom - print the roms section of +// the XML output +//------------------------------------------------- - -/*------------------------------------------------- - print_game_rom - print the roms section of - the XML output --------------------------------------------------*/ - -static void print_game_rom(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_rom() { - const game_driver *clone_of = driver_get_clone(game); - int rom_type; - int parents = 0; - const parent_info *pinfoarray[4]; - - for (; clone_of != NULL; clone_of = driver_get_clone(clone_of)) - { - assert_always(parents < ARRAY_LENGTH(pinfoarray), "too many parents"); - pinfoarray[parents++] = global_alloc(parent_info(clone_of, config.options())); - } - - /* iterate over 3 different ROM "types": BIOS, ROMs, DISKs */ - for (rom_type = 0; rom_type < 3; rom_type++) + // iterate over 3 different ROM "types": BIOS, ROMs, DISKs + for (int rom_type = 0; rom_type < 3; rom_type++) { - const rom_source *source; - const rom_entry *region; - - /* iterate over ROM sources: first the game, then any devices */ - for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) - for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + // iterate over ROM sources: first the game, then any devices + for (const rom_source *source = rom_first_source(m_drivlist.config()); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) { - int is_disk = ROMREGION_ISDISKDATA(region); - const rom_entry *rom; + bool is_disk = ROMREGION_ISDISKDATA(region); - /* disk regions only work for disks */ + // disk regions only work for disks if ((is_disk && rom_type != 2) || (!is_disk && rom_type == 2)) continue; - /* iterate through ROM entries */ - for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) + // iterate through ROM entries + for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) { - int is_bios = ROM_GETBIOSFLAGS(rom); + bool is_bios = ROM_GETBIOSFLAGS(rom); const char *name = ROM_GETNAME(rom); int offset = ROM_GETOFFSET(rom); const char *merge_name = NULL; char bios_name[100]; - /* BIOS ROMs only apply to bioses */ + // BIOS ROMs only apply to bioses if ((is_bios && rom_type != 0) || (!is_bios && rom_type == 0)) continue; - /* if we have a valid ROM and we are a clone, see if we can find the parent ROM */ + // if we have a valid ROM and we are a clone, see if we can find the parent ROM hash_collection hashes(ROM_GETHASHDATA(rom)); - if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && parents > 0) - { - merge_name = get_merge_name(hashes, parents, pinfoarray); - } + if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) + merge_name = get_merge_name(hashes); - /* scan for a BIOS name */ + // scan for a BIOS name bios_name[0] = 0; if (!is_disk && is_bios) { - const rom_entry *brom; - - /* scan backwards through the ROM entries */ - for (brom = rom - 1; brom != game->rom; brom--) + // scan backwards through the ROM entries + for (const rom_entry *brom = rom - 1; brom != m_drivlist.driver().rom; brom--) if (ROMENTRY_ISSYSTEM_BIOS(brom)) { strcpy(bios_name, ROM_GETNAME(brom)); @@ -553,281 +435,521 @@ static void print_game_rom(FILE *out, const game_driver *game, const machine_con } } - /* opening tag */ + // opening tag if (!is_disk) - fprintf(out, "\t\t<rom"); + fprintf(m_output, "\t\t<rom"); else - fprintf(out, "\t\t<disk"); + fprintf(m_output, "\t\t<disk"); - /* add name, merge, bios, and size tags */ + // add name, merge, bios, and size tags */ if (name != NULL && name[0] != 0) - fprintf(out, " name=\"%s\"", xml_normalize_string(name)); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(name)); if (merge_name != NULL) - fprintf(out, " merge=\"%s\"", xml_normalize_string(merge_name)); + fprintf(m_output, " merge=\"%s\"", xml_normalize_string(merge_name)); if (bios_name[0] != 0) - fprintf(out, " bios=\"%s\"", xml_normalize_string(bios_name)); + fprintf(m_output, " bios=\"%s\"", xml_normalize_string(bios_name)); if (!is_disk) - fprintf(out, " size=\"%d\"", rom_file_size(rom)); + fprintf(m_output, " size=\"%d\"", rom_file_size(rom)); - /* dump checksum information only if there is a known dump */ + // dump checksum information only if there is a known dump if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) { - /* iterate over hash function types and print out their values */ + // iterate over hash function types and print m_output their values astring tempstr; for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next()) - fprintf(out, " %s=\"%s\"", hash->name(), hash->string(tempstr)); + fprintf(m_output, " %s=\"%s\"", hash->name(), hash->string(tempstr)); } - /* append a region name */ - fprintf(out, " region=\"%s\"", ROMREGION_GETTAG(region)); + // append a region name + fprintf(m_output, " region=\"%s\"", ROMREGION_GETTAG(region)); - /* add nodump/baddump flags */ + // add nodump/baddump flags if (hashes.flag(hash_collection::FLAG_NO_DUMP)) - fprintf(out, " status=\"nodump\""); + fprintf(m_output, " status=\"nodump\""); if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) - fprintf(out, " status=\"baddump\""); + fprintf(m_output, " status=\"baddump\""); - /* for non-disk entries, print offset */ + // for non-disk entries, print offset if (!is_disk) - fprintf(out, " offset=\"%x\"", offset); - /* for disk entries, add the disk index */ + fprintf(m_output, " offset=\"%x\"", offset); + + // for disk entries, add the disk index else - fprintf(out, " index=\"%x\"", DISK_GETINDEX(rom)); + fprintf(m_output, " index=\"%x\"", DISK_GETINDEX(rom)); - /* add optional flag */ + // add optional flag if ((!is_disk && ROM_ISOPTIONAL(rom)) || (is_disk && DISK_ISOPTIONAL(rom))) - fprintf(out, " optional=\"yes\""); + fprintf(m_output, " optional=\"yes\""); - fprintf(out, "/>\n"); + fprintf(m_output, "/>\n"); } } } - - for (; parents > 0; parents--) - global_free(pinfoarray[parents - 1]); -} - - -/*------------------------------------------------- - print_game_sampleof - print the 'sampleof' - attribute, if appropriate --------------------------------------------------*/ - -static void print_game_sampleof(FILE *out, const game_driver *game, const machine_config &config) -{ - const device_config_sound_interface *sound = NULL; - - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) - { - const char *const *samplenames = ((const samples_interface *)sound->devconfig().static_config())->samplenames; - if (samplenames != NULL) - { - int sampnum; - - /* iterate over sample names */ - for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++) - { - const char *cursampname = samplenames[sampnum]; - - /* only output sampleof if different from the game name */ - if (cursampname[0] == '*' && strcmp(cursampname + 1, game->name) != 0) - fprintf(out, " sampleof=\"%s\"", xml_normalize_string(cursampname + 1)); - - /* must stop here, as there can only be one attribute of the same name */ - return; - } - } - } } -/*------------------------------------------------- - print_game_sample - print a list of all - samples referenced by a game_driver --------------------------------------------------*/ +//------------------------------------------------- +// output_sample - print a list of all +// samples referenced by a game_driver +//------------------------------------------------- -static void print_game_sample(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_sample() { - const device_config_sound_interface *sound = NULL; + // iterate over sample devices + for (const device_config *devconfig = m_drivlist.config().m_devicelist.first(SAMPLES); devconfig != NULL; devconfig = devconfig->typenext()) + { + const char *const *samplenames = ((const samples_interface *)devconfig->static_config())->samplenames; + if (samplenames != NULL) - /* iterate over sound chips looking for samples */ - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) - { - const char *const *samplenames = ((const samples_interface *)sound->devconfig().static_config())->samplenames; - if (samplenames != NULL) + // iterate over sample names + for (int sampnum = 0; samplenames[sampnum] != NULL; sampnum++) { - int sampnum; - - /* iterate over sample names */ - for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++) - { - const char *cursampname = samplenames[sampnum]; - int dupnum; - - /* ignore the special '*' samplename */ - if (sampnum == 0 && cursampname[0] == '*') - continue; + // ignore the special '*' samplename + const char *cursampname = samplenames[sampnum]; + if (sampnum == 0 && cursampname[0] == '*') + continue; - /* filter out duplicates */ - for (dupnum = 0; dupnum < sampnum; dupnum++) - if (strcmp(samplenames[dupnum], cursampname) == 0) - break; - if (dupnum < sampnum) - continue; + // filter m_output duplicates + int dupnum; + for (dupnum = 0; dupnum < sampnum; dupnum++) + if (strcmp(samplenames[dupnum], cursampname) == 0) + break; + if (dupnum < sampnum) + continue; - /* output the sample name */ - fprintf(out, "\t\t<sample name=\"%s\"/>\n", xml_normalize_string(cursampname)); - } + // output the sample name + fprintf(m_output, "\t\t<sample name=\"%s\"/>\n", xml_normalize_string(cursampname)); } - } + } } /*------------------------------------------------- - print_game_chips - print a list of CPU and + output_chips - print a list of CPU and sound chips used by a game -------------------------------------------------*/ -static void print_game_chips(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_chips() { - /* iterate over CPUs */ + // iterate over executable devices const device_config_execute_interface *exec = NULL; - for (bool gotone = config.m_devicelist.first(exec); gotone; gotone = exec->next(exec)) + for (bool gotone = m_drivlist.config().m_devicelist.first(exec); gotone; gotone = exec->next(exec)) { - fprintf(out, "\t\t<chip"); - fprintf(out, " type=\"cpu\""); - fprintf(out, " tag=\"%s\"", xml_normalize_string(exec->devconfig().tag())); - fprintf(out, " name=\"%s\"", xml_normalize_string(exec->devconfig().name())); - fprintf(out, " clock=\"%d\"", exec->devconfig().clock()); - fprintf(out, "/>\n"); + fprintf(m_output, "\t\t<chip"); + fprintf(m_output, " type=\"cpu\""); + fprintf(m_output, " tag=\"%s\"", xml_normalize_string(exec->devconfig().tag())); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(exec->devconfig().name())); + fprintf(m_output, " clock=\"%d\"", exec->devconfig().clock()); + fprintf(m_output, "/>\n"); } - /* iterate over sound chips */ + // iterate over sound devices const device_config_sound_interface *sound = NULL; - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) + for (bool gotone = m_drivlist.config().m_devicelist.first(sound); gotone; gotone = sound->next(sound)) { - fprintf(out, "\t\t<chip"); - fprintf(out, " type=\"audio\""); - fprintf(out, " tag=\"%s\"", xml_normalize_string(sound->devconfig().tag())); - fprintf(out, " name=\"%s\"", xml_normalize_string(sound->devconfig().name())); + fprintf(m_output, "\t\t<chip"); + fprintf(m_output, " type=\"audio\""); + fprintf(m_output, " tag=\"%s\"", xml_normalize_string(sound->devconfig().tag())); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(sound->devconfig().name())); if (sound->devconfig().clock() != 0) - fprintf(out, " clock=\"%d\"", sound->devconfig().clock()); - fprintf(out, "/>\n"); + fprintf(m_output, " clock=\"%d\"", sound->devconfig().clock()); + fprintf(m_output, "/>\n"); } } -/*------------------------------------------------- - print_game_display - print a list of all the - displays --------------------------------------------------*/ +//------------------------------------------------- +// output_display - print a list of all the +// displays +//------------------------------------------------- -static void print_game_display(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_display() { - const screen_device_config *devconfig; - - /* iterate over screens */ - for (devconfig = config.first_screen(); devconfig != NULL; devconfig = devconfig->next_screen()) + // iterate over screens + for (const screen_device_config *devconfig = m_drivlist.config().first_screen(); devconfig != NULL; devconfig = devconfig->next_screen()) { - fprintf(out, "\t\t<display"); + fprintf(m_output, "\t\t<display"); switch (devconfig->screen_type()) { - case SCREEN_TYPE_RASTER: fprintf(out, " type=\"raster\""); break; - case SCREEN_TYPE_VECTOR: fprintf(out, " type=\"vector\""); break; - case SCREEN_TYPE_LCD: fprintf(out, " type=\"lcd\""); break; - default: fprintf(out, " type=\"unknown\""); break; + case SCREEN_TYPE_RASTER: fprintf(m_output, " type=\"raster\""); break; + case SCREEN_TYPE_VECTOR: fprintf(m_output, " type=\"vector\""); break; + case SCREEN_TYPE_LCD: fprintf(m_output, " type=\"lcd\""); break; + default: fprintf(m_output, " type=\"unknown\""); break; } - /* output the orientation as a string */ - switch (game->flags & ORIENTATION_MASK) + // output the orientation as a string + switch (m_drivlist.driver().flags & ORIENTATION_MASK) { case ORIENTATION_FLIP_X: - fprintf(out, " rotate=\"0\" flipx=\"yes\""); + fprintf(m_output, " rotate=\"0\" flipx=\"yes\""); break; case ORIENTATION_FLIP_Y: - fprintf(out, " rotate=\"180\" flipx=\"yes\""); + fprintf(m_output, " rotate=\"180\" flipx=\"yes\""); break; case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - fprintf(out, " rotate=\"180\""); + fprintf(m_output, " rotate=\"180\""); break; case ORIENTATION_SWAP_XY: - fprintf(out, " rotate=\"90\" flipx=\"yes\""); + fprintf(m_output, " rotate=\"90\" flipx=\"yes\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: - fprintf(out, " rotate=\"90\""); + fprintf(m_output, " rotate=\"90\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: - fprintf(out, " rotate=\"270\""); + fprintf(m_output, " rotate=\"270\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - fprintf(out, " rotate=\"270\" flipx=\"yes\""); + fprintf(m_output, " rotate=\"270\" flipx=\"yes\""); break; default: - fprintf(out, " rotate=\"0\""); + fprintf(m_output, " rotate=\"0\""); break; } - /* output width and height only for games that are not vector */ + // output width and height only for games that are not vector if (devconfig->screen_type() != SCREEN_TYPE_VECTOR) { const rectangle &visarea = devconfig->visible_area(); - int dx = visarea.max_x - visarea.min_x + 1; - int dy = visarea.max_y - visarea.min_y + 1; - - fprintf(out, " width=\"%d\"", dx); - fprintf(out, " height=\"%d\"", dy); + fprintf(m_output, " width=\"%d\"", visarea.max_x - visarea.min_x + 1); + fprintf(m_output, " height=\"%d\"", visarea.max_y - visarea.min_y + 1); } - /* output refresh rate */ - fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(devconfig->refresh())); + // output refresh rate + fprintf(m_output, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(devconfig->refresh())); - /* output raw video parameters only for games that are not vector */ - /* and had raw parameters specified */ + // output raw video parameters only for games that are not vector + // and had raw parameters specified if (devconfig->screen_type() != SCREEN_TYPE_VECTOR && !devconfig->oldstyle_vblank_supplied()) { int pixclock = devconfig->width() * devconfig->height() * ATTOSECONDS_TO_HZ(devconfig->refresh()); - fprintf(out, " pixclock=\"%d\"", pixclock); - fprintf(out, " htotal=\"%d\"", devconfig->width()); - fprintf(out, " hbend=\"%d\"", devconfig->visible_area().min_x); - fprintf(out, " hbstart=\"%d\"", devconfig->visible_area().max_x+1); - fprintf(out, " vtotal=\"%d\"", devconfig->height()); - fprintf(out, " vbend=\"%d\"", devconfig->visible_area().min_y); - fprintf(out, " vbstart=\"%d\"", devconfig->visible_area().max_y+1); + fprintf(m_output, " pixclock=\"%d\"", pixclock); + fprintf(m_output, " htotal=\"%d\"", devconfig->width()); + fprintf(m_output, " hbend=\"%d\"", devconfig->visible_area().min_x); + fprintf(m_output, " hbstart=\"%d\"", devconfig->visible_area().max_x+1); + fprintf(m_output, " vtotal=\"%d\"", devconfig->height()); + fprintf(m_output, " vbend=\"%d\"", devconfig->visible_area().min_y); + fprintf(m_output, " vbstart=\"%d\"", devconfig->visible_area().max_y+1); } - fprintf(out, " />\n"); + fprintf(m_output, " />\n"); } } -/*------------------------------------------------- - print_game_sound - print a list of all the - displays --------------------------------------------------*/ +//------------------------------------------------- +// output_sound - print a list of all the +// displays +//------------------------------------------------ -static void print_game_sound(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_sound() { - int speakers = config.m_devicelist.count(SPEAKER); + int speakers = m_drivlist.config().m_devicelist.count(SPEAKER); - /* if we have no sound, zero out the speaker count */ + // if we have no sound, zero m_output the speaker count const device_config_sound_interface *sound = NULL; - if (!config.m_devicelist.first(sound)) + if (!m_drivlist.config().m_devicelist.first(sound)) speakers = 0; - fprintf(out, "\t\t<sound channels=\"%d\"/>\n", speakers); + fprintf(m_output, "\t\t<sound channels=\"%d\"/>\n", speakers); } -/*------------------------------------------------- - print_game_driver - print driver status --------------------------------------------------*/ +//------------------------------------------------- +// output_input - print a summary of a game's +// input +//------------------------------------------------- -static void print_game_driver(FILE *out, const game_driver *game, const machine_config &config) +void info_xml_creator::output_input(const ioport_list &portlist) { - fprintf(out, "\t\t<driver"); + // enumerated list of control types + enum + { + ANALOG_TYPE_JOYSTICK, + ANALOG_TYPE_DIAL, + ANALOG_TYPE_TRACKBALL, + ANALOG_TYPE_PADDLE, + ANALOG_TYPE_LIGHTGUN, + ANALOG_TYPE_PEDAL, + ANALOG_TYPE_COUNT + }; + + // directions + const UINT8 DIR_LEFTRIGHT = 0x01; + const UINT8 DIR_UPDOWN = 0x02; + const UINT8 DIR_4WAY = 0x04; + const UINT8 DIR_DUAL = 0x08; + + // initialize the list of control types + struct + { + const char * type; /* general type of input */ + bool analog; + bool keyb; + INT32 min; /* analog minimum value */ + INT32 max; /* analog maximum value */ + INT32 sensitivity; /* default analog sensitivity */ + INT32 keydelta; /* default analog keydelta */ + bool reverse; /* default analog reverse setting */ + } control_info[ANALOG_TYPE_COUNT]; + + memset(&control_info, 0, sizeof(control_info)); + + // tracking info as we iterate + int nplayer = 0; + int nbutton = 0; + int ncoin = 0; + UINT8 joytype = 0; + bool service = false; + bool tilt = false; + bool keypad = false; + bool keyboard = false; + + // iterate over the ports + for (const input_port_config *port = portlist.first(); port != NULL; port = port->next()) + for (const input_field_config *field = port->fieldlist; field != NULL; field = field->next) + { + int analogtype = -1; + + // track the highest player number + if (nplayer < field->player + 1) + nplayer = field->player + 1; + + // switch off of the type + switch (field->type) + { + // map which joystick directions are present + case IPT_JOYSTICKRIGHT_LEFT: + case IPT_JOYSTICKRIGHT_RIGHT: + case IPT_JOYSTICKLEFT_LEFT: + case IPT_JOYSTICKLEFT_RIGHT: + joytype |= DIR_DUAL; + // fall through... + + case IPT_JOYSTICK_LEFT: + case IPT_JOYSTICK_RIGHT: + joytype |= DIR_LEFTRIGHT | ((field->way == 4) ? DIR_4WAY : 0); + break; + + case IPT_JOYSTICKRIGHT_UP: + case IPT_JOYSTICKRIGHT_DOWN: + case IPT_JOYSTICKLEFT_UP: + case IPT_JOYSTICKLEFT_DOWN: + joytype |= DIR_DUAL; + // fall through... + + case IPT_JOYSTICK_UP: + case IPT_JOYSTICK_DOWN: + joytype |= DIR_UPDOWN | ((field->way == 4) ? DIR_4WAY : 0); + break; + + // mark as an analog input, and get analog stats after switch + case IPT_PADDLE: + control_info[analogtype = ANALOG_TYPE_PADDLE].type = "paddle"; + break; + + case IPT_DIAL: + control_info[analogtype = ANALOG_TYPE_DIAL].type = "dial"; + analogtype = ANALOG_TYPE_DIAL; + break; + + case IPT_TRACKBALL_X: + case IPT_TRACKBALL_Y: + control_info[analogtype = ANALOG_TYPE_TRACKBALL].type = "trackball"; + analogtype = ANALOG_TYPE_TRACKBALL; + break; + + case IPT_AD_STICK_X: + case IPT_AD_STICK_Y: + control_info[analogtype = ANALOG_TYPE_JOYSTICK].type = "stick"; + break; + + case IPT_LIGHTGUN_X: + case IPT_LIGHTGUN_Y: + control_info[analogtype = ANALOG_TYPE_LIGHTGUN].type = "lightgun"; + break; + + case IPT_PEDAL: + case IPT_PEDAL2: + case IPT_PEDAL3: + control_info[analogtype = ANALOG_TYPE_PEDAL].type = "pedal"; + break; + + // track maximum button index + case IPT_BUTTON1: + case IPT_BUTTON2: + case IPT_BUTTON3: + case IPT_BUTTON4: + case IPT_BUTTON5: + case IPT_BUTTON6: + case IPT_BUTTON7: + case IPT_BUTTON8: + case IPT_BUTTON9: + case IPT_BUTTON10: + case IPT_BUTTON11: + case IPT_BUTTON12: + case IPT_BUTTON13: + case IPT_BUTTON14: + case IPT_BUTTON15: + case IPT_BUTTON16: + nbutton = MAX(nbutton, field->type - IPT_BUTTON1 + 1); + break; + + // track maximum coin index + case IPT_COIN1: + case IPT_COIN2: + case IPT_COIN3: + case IPT_COIN4: + case IPT_COIN5: + case IPT_COIN6: + case IPT_COIN7: + case IPT_COIN8: + ncoin = MAX(ncoin, field->type - IPT_COIN1 + 1); + break; + + // track presence of these guys + case IPT_KEYPAD: + keypad = true; + break; + + case IPT_KEYBOARD: + keyboard = true; + break; + + // additional types + case IPT_SERVICE: + service = true; + break; + + case IPT_TILT: + tilt = true; + break; + } + + // get the analog stats + if (analogtype != -1) + { + if (field->min != 0) + control_info[analogtype].min = field->min; + if (field->max != 0) + control_info[analogtype].max = field->max; + if (field->sensitivity != 0) + control_info[analogtype].sensitivity = field->sensitivity; + if (field->delta != 0) + control_info[analogtype].keydelta = field->delta; + if ((field->flags & ANALOG_FLAG_REVERSE) != 0) + control_info[analogtype].reverse = true; + } + } + + // output the basic info + fprintf(m_output, "\t\t<input"); + fprintf(m_output, " players=\"%d\"", nplayer); + if (nbutton != 0) + fprintf(m_output, " buttons=\"%d\"", nbutton); + if (ncoin != 0) + fprintf(m_output, " coins=\"%d\"", ncoin); + if (service) + fprintf(m_output, " service=\"yes\""); + if (tilt) + fprintf(m_output, " tilt=\"yes\""); + fprintf(m_output, ">\n"); + + // output the joystick types + if (joytype != 0) + { + const char *vertical = ((joytype & DIR_LEFTRIGHT) == 0) ? "v" : ""; + const char *doubletype = ((joytype & DIR_DUAL) != 0) ? "doublejoy" : "joy"; + const char *way = ((joytype & DIR_LEFTRIGHT) == 0 || (joytype & DIR_UPDOWN) == 0) ? "2way" : ((joytype & DIR_4WAY) != 0) ? "4way" : "8way"; + fprintf(m_output, "\t\t\t<control type=\"%s%s%s\"/>\n", vertical, doubletype, way); + } + + // output analog types + for (int type = 0; type < ANALOG_TYPE_COUNT; type++) + if (control_info[type].type != NULL) + { + fprintf(m_output, "\t\t\t<control type=\"%s\"", xml_normalize_string(control_info[type].type)); + if (control_info[type].min != 0 || control_info[type].max != 0) + { + fprintf(m_output, " minimum=\"%d\"", control_info[type].min); + fprintf(m_output, " maximum=\"%d\"", control_info[type].max); + } + if (control_info[type].sensitivity != 0) + fprintf(m_output, " sensitivity=\"%d\"", control_info[type].sensitivity); + if (control_info[type].keydelta != 0) + fprintf(m_output, " keydelta=\"%d\"", control_info[type].keydelta); + if (control_info[type].reverse) + fprintf(m_output, " reverse=\"yes\""); + + fprintf(m_output, "/>\n"); + } + + // output keypad and keyboard + if (keypad) + fprintf(m_output, "\t\t\t<control type=\"keypad\"/>\n"); + if (keyboard) + fprintf(m_output, "\t\t\t<control type=\"keyboard\"/>\n"); + + fprintf(m_output, "\t\t</input>\n"); +} + + +//------------------------------------------------- +// output_switches - print the configurations or +// DIP switch settings +//------------------------------------------------- + +void info_xml_creator::output_switches(const ioport_list &portlist, int type, const char *outertag, const char *innertag) +{ + // iterate looking for DIP switches + for (const input_port_config *port = portlist.first(); port != NULL; port = port->next()) + for (const input_field_config *field = port->fieldlist; field != NULL; field = field->next) + if (field->type == type) + { + // output the switch name information + fprintf(m_output, "\t\t<%s name=\"%s\"", outertag, xml_normalize_string(input_field_name(field))); + fprintf(m_output, " tag=\"%s\"", xml_normalize_string(field->port->tag)); + fprintf(m_output, " mask=\"%u\"", field->mask); + fprintf(m_output, ">\n"); + + // loop over settings + for (const input_setting_config *setting = field->settinglist; setting != NULL; setting = setting->next) + { + fprintf(m_output, "\t\t\t<%s name=\"%s\"", innertag, xml_normalize_string(setting->name)); + fprintf(m_output, " value=\"%u\"", setting->value); + if (setting->value == field->defvalue) + fprintf(m_output, " default=\"yes\""); + fprintf(m_output, "/>\n"); + } + + // terminate the switch entry + fprintf(m_output, "\t\t</%s>\n", outertag); + } +} + + +//------------------------------------------------- +// output_adjusters - print the Analog +// Adjusters for a game +//------------------------------------------------- + +void info_xml_creator::output_adjusters(const ioport_list &portlist) +{ + // iterate looking for Adjusters + for (const input_port_config *port = portlist.first(); port != NULL; port = port->next()) + for (const input_field_config *field = port->fieldlist; field != NULL; field = field->next) + if (field->type == IPT_ADJUSTER) + fprintf(m_output, "\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", xml_normalize_string(input_field_name(field)), field->defvalue); +} + + +//------------------------------------------------- +// output_driver - print driver status +//------------------------------------------------- + +void info_xml_creator::output_driver() +{ + fprintf(m_output, "\t\t<driver"); /* The status entry is an hint for frontend authors */ /* to select working and not working games without */ @@ -837,444 +959,210 @@ static void print_game_driver(FILE *out, const game_driver *game, const machine_ /* some minor issues, games marked as status=preliminary */ /* don't work or have major emulation problems. */ - if (game->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS)) - fprintf(out, " status=\"preliminary\""); - else if (game->flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS)) - fprintf(out, " status=\"imperfect\""); + if (m_drivlist.driver().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS)) + fprintf(m_output, " status=\"preliminary\""); + else if (m_drivlist.driver().flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS)) + fprintf(m_output, " status=\"imperfect\""); else - fprintf(out, " status=\"good\""); + fprintf(m_output, " status=\"good\""); - if (game->flags & GAME_NOT_WORKING) - fprintf(out, " emulation=\"preliminary\""); + if (m_drivlist.driver().flags & GAME_NOT_WORKING) + fprintf(m_output, " emulation=\"preliminary\""); else - fprintf(out, " emulation=\"good\""); + fprintf(m_output, " emulation=\"good\""); - if (game->flags & GAME_WRONG_COLORS) - fprintf(out, " color=\"preliminary\""); - else if (game->flags & GAME_IMPERFECT_COLORS) - fprintf(out, " color=\"imperfect\""); + if (m_drivlist.driver().flags & GAME_WRONG_COLORS) + fprintf(m_output, " color=\"preliminary\""); + else if (m_drivlist.driver().flags & GAME_IMPERFECT_COLORS) + fprintf(m_output, " color=\"imperfect\""); else - fprintf(out, " color=\"good\""); + fprintf(m_output, " color=\"good\""); - if (game->flags & GAME_NO_SOUND) - fprintf(out, " sound=\"preliminary\""); - else if (game->flags & GAME_IMPERFECT_SOUND) - fprintf(out, " sound=\"imperfect\""); + if (m_drivlist.driver().flags & GAME_NO_SOUND) + fprintf(m_output, " sound=\"preliminary\""); + else if (m_drivlist.driver().flags & GAME_IMPERFECT_SOUND) + fprintf(m_output, " sound=\"imperfect\""); else - fprintf(out, " sound=\"good\""); + fprintf(m_output, " sound=\"good\""); - if (game->flags & GAME_IMPERFECT_GRAPHICS) - fprintf(out, " graphic=\"imperfect\""); + if (m_drivlist.driver().flags & GAME_IMPERFECT_GRAPHICS) + fprintf(m_output, " graphic=\"imperfect\""); else - fprintf(out, " graphic=\"good\""); + fprintf(m_output, " graphic=\"good\""); - if (game->flags & GAME_NO_COCKTAIL) - fprintf(out, " cocktail=\"preliminary\""); + if (m_drivlist.driver().flags & GAME_NO_COCKTAIL) + fprintf(m_output, " cocktail=\"preliminary\""); - if (game->flags & GAME_UNEMULATED_PROTECTION) - fprintf(out, " protection=\"preliminary\""); + if (m_drivlist.driver().flags & GAME_UNEMULATED_PROTECTION) + fprintf(m_output, " protection=\"preliminary\""); - if (game->flags & GAME_SUPPORTS_SAVE) - fprintf(out, " savestate=\"supported\""); + if (m_drivlist.driver().flags & GAME_SUPPORTS_SAVE) + fprintf(m_output, " savestate=\"supported\""); else - fprintf(out, " savestate=\"unsupported\""); + fprintf(m_output, " savestate=\"unsupported\""); - fprintf(out, " palettesize=\"%d\"", config.m_total_colors); + fprintf(m_output, " palettesize=\"%d\"", m_drivlist.config().m_total_colors); - fprintf(out, "/>\n"); + fprintf(m_output, "/>\n"); } -/*------------------------------------------------- - print_game_categories - print the Categories - settings for a system --------------------------------------------------*/ -static void print_game_categories(FILE *out, const game_driver *game, const ioport_list &portlist) -{ - const input_port_config *port; - const input_field_config *field; +//------------------------------------------------- +// output_categories - print the Categories +// settings for a system +//------------------------------------------------- - /* iterate looking for Categories */ - for (port = portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) +void info_xml_creator::output_categories(const ioport_list &portlist) +{ + // iterate looking for Categories + for (const input_port_config *port = portlist.first(); port != NULL; port = port->next()) + for (const input_field_config *field = port->fieldlist; field != NULL; field = field->next) if (field->type == IPT_CATEGORY) { - const input_setting_config *setting; - - /* output the category name information */ - fprintf(out, "\t\t<category name=\"%s\">\n", xml_normalize_string(input_field_name(field))); + // output the category name information + fprintf(m_output, "\t\t<category name=\"%s\">\n", xml_normalize_string(input_field_name(field))); - /* loop over item settings */ - for (setting = field->settinglist; setting != NULL; setting = setting->next) + // loop over item settings + for (const input_setting_config *setting = field->settinglist; setting != NULL; setting = setting->next) { - fprintf(out, "\t\t\t<item name=\"%s\"", xml_normalize_string(setting->name)); + fprintf(m_output, "\t\t\t<item name=\"%s\"", xml_normalize_string(setting->name)); if (setting->value == field->defvalue) - fprintf(out, " default=\"yes\""); - fprintf(out, "/>\n"); + fprintf(m_output, " default=\"yes\""); + fprintf(m_output, "/>\n"); } - /* terminate the category entry */ - fprintf(out, "\t\t</category>\n"); + // terminate the category entry + fprintf(m_output, "\t\t</category>\n"); } } -/*------------------------------------------------- - print_game_images - prints out all info on - image devices --------------------------------------------------*/ -static void print_game_images(FILE *out, const game_driver *game, const machine_config &config) +//------------------------------------------------- +// output_images - prints m_output all info on +// image devices +//------------------------------------------------- + +void info_xml_creator::output_images() { const device_config_image_interface *dev = NULL; - const char *name; - const char *shortname; - - for (bool gotone = config.m_devicelist.first(dev); gotone; gotone = dev->next(dev)) + for (bool gotone = m_drivlist.config().m_devicelist.first(dev); gotone; gotone = dev->next(dev)) { - /* print out device type */ - fprintf(out, "\t\t<device type=\"%s\"", xml_normalize_string(dev->image_type_name())); + // print m_output device type + fprintf(m_output, "\t\t<device type=\"%s\"", xml_normalize_string(dev->image_type_name())); - /* does this device have a tag? */ + // does this device have a tag? if (dev->devconfig().tag()) - fprintf(out, " tag=\"%s\"", xml_normalize_string(dev->devconfig().tag())); + fprintf(m_output, " tag=\"%s\"", xml_normalize_string(dev->devconfig().tag())); - /* is this device mandatory? */ + // is this device mandatory? if (dev->must_be_loaded()) - fprintf(out, " mandatory=\"1\""); + fprintf(m_output, " mandatory=\"1\""); - if (dev->image_interface()[0] ) - fprintf(out, " interface=\"%s\"", xml_normalize_string(dev->image_interface())); + if (dev->image_interface()[0]) + fprintf(m_output, " interface=\"%s\"", xml_normalize_string(dev->image_interface())); - /* close the XML tag */ - fprintf(out, ">\n"); + // close the XML tag + fprintf(m_output, ">\n"); - name = dev->instance_name(); - shortname = dev->brief_instance_name(); + const char *name = dev->instance_name(); + const char *shortname = dev->brief_instance_name(); - fprintf(out, "\t\t\t<instance"); - fprintf(out, " name=\"%s\"", xml_normalize_string(name)); - fprintf(out, " briefname=\"%s\"", xml_normalize_string(shortname)); - fprintf(out, "/>\n"); + fprintf(m_output, "\t\t\t<instance"); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(name)); + fprintf(m_output, " briefname=\"%s\"", xml_normalize_string(shortname)); + fprintf(m_output, "/>\n"); astring extensions(dev->file_extensions()); - char *ext = strtok((char*)extensions.cstr(),","); + char *ext = strtok((char *)extensions.cstr(), ","); while (ext != NULL) { - fprintf(out, "\t\t\t<extension"); - fprintf(out, " name=\"%s\"", xml_normalize_string(ext)); - fprintf(out, "/>\n"); - ext = strtok (NULL, ","); + fprintf(m_output, "\t\t\t<extension"); + fprintf(m_output, " name=\"%s\"", xml_normalize_string(ext)); + fprintf(m_output, "/>\n"); + ext = strtok(NULL, ","); } - fprintf(out, "\t\t</device>\n"); + fprintf(m_output, "\t\t</device>\n"); } } -/*------------------------------------------------- - print_game_software_list - print the information - for all known software lists for this system --------------------------------------------------*/ -static void print_game_software_list(FILE *out, const game_driver *game, const machine_config &config) +//------------------------------------------------- +// output_software_list - print the information +// for all known software lists for this system +//------------------------------------------------- + +void info_xml_creator::output_software_list() { - for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) + for (const device_config *dev = m_drivlist.config().m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext()) { software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config(); - for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ ) - { - if ( swlist->list_name[i] ) + for (int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++) + if (swlist->list_name[i]) { - fprintf(out, "\t\t<softwarelist name=\"%s\" ", swlist->list_name[i] ); - fprintf(out, "status=\"%s\" />\n", (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM) ? "original" : "compatible" ); + fprintf(m_output, "\t\t<softwarelist name=\"%s\" ", swlist->list_name[i]); + fprintf(m_output, "status=\"%s\" />\n", (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM) ? "original" : "compatible"); } - } } } -/* device iteration helpers */ -#define ram_first(config) (config).m_devicelist.first(RAM) -#define ram_next(previous) ((previous)->typenext()) -/*------------------------------------------------- - print_game_ramoptions - prints out all RAM - options for this system --------------------------------------------------*/ -static void print_game_ramoptions(FILE *out, const game_driver *game, const machine_config &config) -{ - const device_config *device; - for (device = ram_first(config); device != NULL; device = ram_next(device)) +//------------------------------------------------- +// output_ramoptions - prints m_output all RAM +// options for this system +//------------------------------------------------- + +void info_xml_creator::output_ramoptions() +{ + for (const device_config *device = m_drivlist.config().m_devicelist.first(RAM); device != NULL; device = device->typenext()) { ram_config *ram = (ram_config *)downcast<const legacy_device_config_base *>(device)->inline_config(); - fprintf(out, "\t\t<ramoption default=\"1\">%u</ramoption>\n", ram_parse_string(ram->default_size)); + fprintf(m_output, "\t\t<ramoption default=\"1\">%u</ramoption>\n", ram_parse_string(ram->default_size)); + if (ram->extra_options != NULL) { - int j; - int size = strlen(ram->extra_options); - char * const s = mame_strdup(ram->extra_options); - char * const e = s + size; - char *p = s; - for (j=0;j<size;j++) { - if (p[j]==',') p[j]=0; - } - /* try to parse each option */ - while(p <= e) + astring options(ram->extra_options); + for (int start, end = options.chr(0, ','); ; start = end + 1, end = options.chr(start, ',')) { - fprintf(out, "\t\t<ramoption>%u</ramoption>\n", ram_parse_string(p)); - p += strlen(p); - if (p == e) + astring option; + option.cpysubstr(options, start, (end == -1) ? -1 : end - start); + fprintf(m_output, "\t\t<ramoption>%u</ramoption>\n", ram_parse_string(option)); + if (end == -1) break; - p += 1; } - - osd_free(s); } } } -/*------------------------------------------------- - print_game_info - print the XML information - for one particular game driver --------------------------------------------------*/ - -static void print_game_info(FILE *out, const game_driver *game, emu_options &options) -{ - const game_driver *clone_of; - machine_config config(*game, options); - ioport_list portlist; - const char *start; - - /* no action if not a game */ - if (game->flags & GAME_NO_STANDALONE) - return; - /* start tracking resources and allocate the machine and input configs */ - input_port_list_init(portlist, game->ipt, NULL, 0, FALSE, NULL); - for (device_config *cfg = config.m_devicelist.first(); cfg != NULL; cfg = cfg->next()) - { - if (cfg->input_ports() != NULL) - input_port_list_init(portlist, cfg->input_ports(), NULL, 0, FALSE, cfg); - } - - /* print the header and the game name */ - fprintf(out, "\t<" XML_TOP); - fprintf(out, " name=\"%s\"", xml_normalize_string(game->name) ); +//------------------------------------------------- +// get_merge_name - get the rom name from a +// parent set +//------------------------------------------------- - /* strip away any path information from the source_file and output it */ - start = strrchr(game->source_file, '/'); - if (start == NULL) - start = strrchr(game->source_file, '\\'); - if (start == NULL) - start = game->source_file - 1; - fprintf(out, " sourcefile=\"%s\"", xml_normalize_string(start + 1)); - - /* append bios and runnable flags */ - if (game->flags & GAME_IS_BIOS_ROOT) - fprintf(out, " isbios=\"yes\""); - if (game->flags & GAME_NO_STANDALONE) - fprintf(out, " runnable=\"no\""); - if (game->flags & GAME_MECHANICAL) - fprintf(out, " ismechanical=\"yes\""); - - /* display clone information */ - clone_of = driver_get_clone(game); - if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT)) - fprintf(out, " cloneof=\"%s\"", xml_normalize_string(clone_of->name)); - if (clone_of != NULL) - fprintf(out, " romof=\"%s\"", xml_normalize_string(clone_of->name)); - - /* display sample information and close the game tag */ - print_game_sampleof(out, game, config); - fprintf(out, ">\n"); - - /* output game description */ - if (game->description != NULL) - fprintf(out, "\t\t<description>%s</description>\n", xml_normalize_string(game->description)); - - /* print the year only if is a number or another allowed character (? or +) */ - if (game->year != NULL && strspn(game->year, "0123456789?+") == strlen(game->year)) - fprintf(out, "\t\t<year>%s</year>\n", xml_normalize_string(game->year)); - - /* print the manufacturer information */ - if (game->manufacturer != NULL) - fprintf(out, "\t\t<manufacturer>%s</manufacturer>\n", xml_normalize_string(game->manufacturer)); - - /* now print various additional information */ - print_game_bios(out, game); - print_game_rom(out, game, config); - print_game_sample(out, game, config); - print_game_chips(out, game, config); - print_game_display(out, game, config); - print_game_sound(out, game, config); - print_game_input(out, game, portlist); - print_game_switches(out, game, portlist); - print_game_configs(out, game, portlist); - print_game_categories(out, game, portlist); - print_game_adjusters(out, game, portlist); - print_game_driver(out, game, config); - print_game_images( out, game, config ); - print_game_software_list( out, game, config ); - print_game_ramoptions( out, game, config ); - /* close the topmost tag */ - fprintf(out, "\t</" XML_TOP ">\n"); -} - - -/*------------------------------------------------- - print_mame_xml - print the XML information - for all known games --------------------------------------------------*/ - -void print_mame_xml(FILE *out, const game_driver *const games[], const char *gamename, emu_options &options) +const char *info_xml_creator::get_merge_name(const hash_collection &romhashes) { - int drvnum; - - fprintf(out, - "<?xml version=\"1.0\"?>\n" - "<!DOCTYPE " XML_ROOT " [\n" - "<!ELEMENT " XML_ROOT " (" XML_TOP "+)>\n" - "\t<!ATTLIST " XML_ROOT " build CDATA #IMPLIED>\n" - "\t<!ATTLIST " XML_ROOT " debug (yes|no) \"no\">\n" - "\t<!ATTLIST " XML_ROOT " mameconfig CDATA #REQUIRED>\n" - "\t<!ELEMENT " XML_TOP " (description, year?, manufacturer, biosset*, rom*, disk*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, category*, adjuster*, driver?, device*, softwarelist*, ramoption*)>\n" - "\t\t<!ATTLIST " XML_TOP " name CDATA #REQUIRED>\n" - "\t\t<!ATTLIST " XML_TOP " sourcefile CDATA #IMPLIED>\n" - "\t\t<!ATTLIST " XML_TOP " isbios (yes|no) \"no\">\n" - "\t\t<!ATTLIST " XML_TOP " ismechanical (yes|no) \"no\">\n" - "\t\t<!ATTLIST " XML_TOP " runnable (yes|no) \"yes\">\n" - "\t\t<!ATTLIST " XML_TOP " cloneof CDATA #IMPLIED>\n" - "\t\t<!ATTLIST " XML_TOP " romof CDATA #IMPLIED>\n" - "\t\t<!ATTLIST " XML_TOP " sampleof CDATA #IMPLIED>\n" - "\t\t<!ELEMENT description (#PCDATA)>\n" - "\t\t<!ELEMENT year (#PCDATA)>\n" - "\t\t<!ELEMENT manufacturer (#PCDATA)>\n" - "\t\t<!ELEMENT biosset EMPTY>\n" - "\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n" - "\t\t<!ELEMENT rom EMPTY>\n" - "\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom md5 CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n" - "\t\t\t<!ATTLIST rom optional (yes|no) \"no\">\n" - "\t\t<!ELEMENT disk EMPTY>\n" - "\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST disk md5 CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n" - "\t\t\t<!ATTLIST disk optional (yes|no) \"no\">\n" - "\t\t<!ELEMENT sample EMPTY>\n" - "\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n" - "\t\t<!ELEMENT chip EMPTY>\n" - "\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n" - "\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n" - "\t\t<!ELEMENT display EMPTY>\n" - "\t\t\t<!ATTLIST display type (raster|vector|lcd|unknown) #REQUIRED>\n" - "\t\t\t<!ATTLIST display rotate (0|90|180|270) #REQUIRED>\n" - "\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n" - "\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n" - "\t\t<!ELEMENT sound EMPTY>\n" - "\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n" - "\t\t<!ELEMENT input (control*)>\n" - "\t\t\t<!ATTLIST input service (yes|no) \"no\">\n" - "\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n" - "\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n" - "\t\t\t<!ELEMENT control EMPTY>\n" - "\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n" - "\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n" - "\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n" - "\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n" - "\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n" - "\t\t<!ELEMENT dipswitch (dipvalue*)>\n" - "\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n" - "\t\t\t<!ELEMENT dipvalue EMPTY>\n" - "\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n" - "\t\t<!ELEMENT configuration (confsetting*)>\n" - "\t\t\t<!ATTLIST configuration name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST configuration tag CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST configuration mask CDATA #REQUIRED>\n" - "\t\t\t<!ELEMENT confsetting EMPTY>\n" - "\t\t\t\t<!ATTLIST confsetting name CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST confsetting value CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST confsetting default (yes|no) \"no\">\n" - "\t\t<!ELEMENT category (item*)>\n" - "\t\t\t<!ATTLIST category name CDATA #REQUIRED>\n" - "\t\t\t<!ELEMENT item EMPTY>\n" - "\t\t\t\t<!ATTLIST item name CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST item default (yes|no) \"no\">\n" - "\t\t<!ELEMENT adjuster EMPTY>\n" - "\t\t\t<!ATTLIST adjuster name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST adjuster default CDATA #REQUIRED>\n" - "\t\t<!ELEMENT driver EMPTY>\n" - "\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver color (good|imperfect|preliminary) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver sound (good|imperfect|preliminary) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver graphic (good|imperfect|preliminary) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n" - "\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n" - "\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n" - "\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n" - "\t\t<!ELEMENT device (instance*, extension*)>\n" - "\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n" - "\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n" - "\t\t\t<!ELEMENT instance EMPTY>\n" - "\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n" - "\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n" - "\t\t\t<!ELEMENT extension EMPTY>\n" - "\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n" - "\t\t<!ELEMENT softwarelist EMPTY>\n" - "\t\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n" - "\t\t\t<!ATTLIST softwarelist status (original|compatible) #REQUIRED>\n" - "\t\t<!ELEMENT ramoption (#PCDATA)>\n" - "\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n" - "]>\n\n" - "<" XML_ROOT " build=\"%s\" debug=\"" -#ifdef MAME_DEBUG - "yes" -#else - "no" -#endif - "\" mameconfig=\"%d\">\n", - xml_normalize_string(build_version), - CONFIG_VERSION - ); - - for (drvnum = 0; games[drvnum] != NULL; drvnum++) - if (mame_strwildcmp(gamename, games[drvnum]->name) == 0) - print_game_info(out, games[drvnum], options); + const char *merge_name = NULL; + + // walk the parent chain + for (int clone_of = m_drivlist.find(m_drivlist.driver().parent); clone_of != -1; clone_of = m_drivlist.find(m_drivlist.driver(clone_of).parent)) + + // look in the parent's ROMs + for (const rom_source *psource = rom_first_source(m_drivlist.config(clone_of)); psource != NULL; psource = rom_next_source(*psource)) + for (const rom_entry *pregion = rom_first_region(*psource); pregion != NULL; pregion = rom_next_region(pregion)) + for (const rom_entry *prom = rom_first_file(pregion); prom != NULL; prom = rom_next_file(prom)) + { + hash_collection phashes(ROM_GETHASHDATA(prom)); + if (!phashes.flag(hash_collection::FLAG_NO_DUMP) && romhashes == phashes) + { + // stop when we find a match + merge_name = ROM_GETNAME(prom); + break; + } + } - fprintf(out, "</" XML_ROOT ">\n"); + return merge_name; } diff --git a/src/emu/info.h b/src/emu/info.h index 327354e2d6f..5fd260d05bf 100644 --- a/src/emu/info.h +++ b/src/emu/info.h @@ -4,8 +4,36 @@ Dumps the MAME internal data as an XML file. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + 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. ***************************************************************************/ @@ -15,12 +43,47 @@ #define __INFO_H__ -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// FUNCTION PROTOTYPES +//************************************************************************** + +// helper class to putput +class info_xml_creator +{ +public: + // construction/destruction + info_xml_creator(driver_enumerator &drivlist); + + // output + void output(FILE *out); + +private: + // internal helper + void output_one(); + void output_sampleof(); + void output_bios(); + void output_rom(); + void output_sample(); + void output_chips(); + void output_display(); + void output_sound(); + void output_input(const ioport_list &portlist); + void output_switches(const ioport_list &portlist, int type, const char *outertag, const char *innertag); + void output_adjusters(const ioport_list &portlist); + void output_categories(const ioport_list &portlist); + void output_driver(); + void output_images(); + void output_software_list(); + void output_ramoptions(); + + const char *get_merge_name(const hash_collection &romhashes); + + // internal state + FILE * m_output; + driver_enumerator & m_drivlist; -/* print the MAME database in XML format */ -void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename, emu_options &options); + static const char s_dtd_string[]; +}; #endif /* __INFO_H__ */ diff --git a/src/emu/layout/pinball.lay b/src/emu/layout/pinball.lay new file mode 100644 index 00000000000..0372a828ac0 --- /dev/null +++ b/src/emu/layout/pinball.lay @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<mamelayout version="2"> + <element name="digit" defstate="0"> + <led7seg> + <color red="0.75" green="0" blue="0.0" /> + </led7seg> + </element> + <element name="dummy_str" defstate="0"> + <text string="Pinball"> + <color red="1.0" green="1.0" blue="1.0" /> + <bounds x="0" y="0" width="25" height="5" /> + </text> + </element> + <view name="Standard"> + <bezel name="dummy_txt" element="dummy_str"> + <bounds x="0" y="0" width="25" height="5" /> + </bezel> + </view> +</mamelayout> diff --git a/src/emu/machine.c b/src/emu/machine.c index a0ed6794f14..7707468d556 100644 --- a/src/emu/machine.c +++ b/src/emu/machine.c @@ -943,8 +943,17 @@ driver_device_config_base::driver_device_config_base(const machine_config &mconf void driver_device_config_base::static_set_game(device_config *device, const game_driver *game) { - downcast<driver_device_config_base *>(device)->m_system = game; - downcast<driver_device_config_base *>(device)->m_shortname = game->name; + driver_device_config_base *base = downcast<driver_device_config_base *>(device); + + base->m_system = game; + + // set the short name to the game's name + base->m_shortname = game->name; + + // and set the search path to include all parents + base->m_searchpath = game->name; + for (int parent = driver_list::clone(*game); parent != -1; parent = driver_list::clone(parent)) + base->m_searchpath.cat(";").cat(driver_list::driver(parent).name); } diff --git a/src/emu/mame.c b/src/emu/mame.c index 65d671b32ef..ea9452ac2de 100644 --- a/src/emu/mame.c +++ b/src/emu/mame.c @@ -157,7 +157,7 @@ int mame_execute(emu_options &options, osd_interface &osd) const game_driver *system = options.system(); if (system == NULL) { - system = &GAME_NAME(empty); + system = &GAME_NAME(___empty); if (firstgame) started_empty = true; } diff --git a/src/emu/render.c b/src/emu/render.c index 654534d3a52..5ca15bd77da 100644 --- a/src/emu/render.c +++ b/src/emu/render.c @@ -1642,10 +1642,10 @@ void render_target::load_layout_files(const char *layoutfile, bool singlefile) load_layout_file(NULL, m_manager.machine().config().m_default_layout); // try to load another file based on the parent driver name - const game_driver *cloneof = driver_get_clone(&system); - if (cloneof != NULL) - if (!load_layout_file(cloneof->name, cloneof->name)) - load_layout_file(cloneof->name, "default"); + int cloneof = driver_list::clone(system); + if (cloneof != -1) + if (!load_layout_file(driver_list::driver(cloneof).name, driver_list::driver(cloneof).name)) + load_layout_file(driver_list::driver(cloneof).name, "default"); // now do the built-in layouts for single-screen games if (m_manager.machine().m_devicelist.count(SCREEN) == 1) diff --git a/src/emu/rendlay.c b/src/emu/rendlay.c index c6e03f1c1d6..c3df4c94c9c 100644 --- a/src/emu/rendlay.c +++ b/src/emu/rendlay.c @@ -117,6 +117,10 @@ #include "lcd.lh" #include "lcd_rot.lh" +// generic dummy pinball layout +#include "pinball.lh" + + //************************************************************************** // CONSTANTS diff --git a/src/emu/romload.c b/src/emu/romload.c index 760cfc46ac0..46cf9c09d81 100644 --- a/src/emu/romload.c +++ b/src/emu/romload.c @@ -614,7 +614,6 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro { file_error filerr = FILERR_NOT_FOUND; UINT32 romsize = rom_file_size(romp); - const game_driver *drv; /* update status display */ display_loading_rom_message(romdata, ROM_GETNAME(romp)); @@ -626,9 +625,8 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro /* attempt reading up the chain through the parents. It automatically also attempts any kind of load by checksum supported by the archives. */ romdata->file = NULL; - for (drv = &romdata->machine().system(); romdata->file == NULL && drv != NULL; drv = driver_get_clone(drv)) - if (drv->name != NULL && *drv->name != 0) - filerr = common_process_file(romdata->machine().options(), drv->name, has_crc, crc, romp, &romdata->file); + for (int drv = driver_list::find(romdata->machine().system()); romdata->file == NULL && drv != -1; drv = driver_list::clone(drv)) + filerr = common_process_file(romdata->machine().options(), driver_list::driver(drv).name, has_crc, crc, romp, &romdata->file); /* if the region is load by name, load the ROM from there */ if (romdata->file == NULL && regiontag != NULL) @@ -1007,7 +1005,6 @@ static void process_rom_entries(rom_load_data *romdata, const char *regiontag, c chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd, const char *locationtag) { - const game_driver *drv, *searchdrv; const rom_entry *region, *rom; const rom_source *source; file_error filerr; @@ -1018,8 +1015,8 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons /* attempt to open the properly named file, scanning up through parent directories */ filerr = FILERR_NOT_FOUND; - for (searchdrv = gamedrv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv)) - filerr = common_process_file(options, searchdrv->name, ".chd", romp, image_file); + for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file); if (filerr != FILERR_NONE) filerr = common_process_file(options, NULL, ".chd", romp, image_file); @@ -1114,9 +1111,9 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons /* otherwise, look at our parents for a CHD with an identical checksum */ /* and try to open that */ hash_collection romphashes(ROM_GETHASHDATA(romp)); - for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv)) + for (int drv = driver_list::find(*gamedrv); drv != -1; drv = driver_list::clone(drv)) { - machine_config config(*drv, options); + machine_config config(driver_list::driver(drv), options); for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) if (ROMREGION_ISDISKDATA(region)) @@ -1128,8 +1125,8 @@ chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, cons { /* attempt to open the properly named file, scanning up through parent directories */ filerr = FILERR_NOT_FOUND; - for (searchdrv = drv; searchdrv != NULL && filerr != FILERR_NONE; searchdrv = driver_get_clone(searchdrv)) - filerr = common_process_file(options, searchdrv->name, ".chd", rom, image_file); + for (int searchdrv = drv; searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", rom, image_file); if (filerr != FILERR_NONE) filerr = common_process_file(options, NULL, ".chd", rom, image_file); diff --git a/src/emu/sound/bsmt2000.c b/src/emu/sound/bsmt2000.c index 6293b8b38bd..7e172fc6a98 100644 --- a/src/emu/sound/bsmt2000.c +++ b/src/emu/sound/bsmt2000.c @@ -107,13 +107,12 @@ ROM_END //------------------------------------------------- bsmt2000_device_config::bsmt2000_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) - : device_config(mconfig, static_alloc_device_config, "BSMT2000", tag, owner, clock), + : device_config(mconfig, static_alloc_device_config, "BSMT2000", "bsmt2000", tag, owner, clock), device_config_sound_interface(mconfig, *this), device_config_memory_interface(mconfig, *this), m_space_config("samples", ENDIANNESS_LITTLE, 8, 32, 0, NULL, *ADDRESS_MAP_NAME(bsmt2000)), m_ready_callback(NULL) { - m_shortname = "bsmt2000"; } diff --git a/src/emu/sound/wavwrite.c b/src/emu/sound/wavwrite.c index 1d318a08b9e..5cd884d7417 100644 --- a/src/emu/sound/wavwrite.c +++ b/src/emu/sound/wavwrite.c @@ -126,7 +126,7 @@ void wav_add_data_32(wav_file *wav, INT32 *data, int samples, int shift) if (!wav) return; /* allocate temp memory */ - temp = (INT16 *)osd_malloc(samples * sizeof(temp[0])); + temp = (INT16 *)osd_malloc_array(samples * sizeof(temp[0])); if (!temp) return; @@ -154,7 +154,7 @@ void wav_add_data_16lr(wav_file *wav, INT16 *left, INT16 *right, int samples) if (!wav) return; /* allocate temp memory */ - temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0])); + temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0])); if (!temp) return; @@ -179,7 +179,7 @@ void wav_add_data_32lr(wav_file *wav, INT32 *left, INT32 *right, int samples, in if (!wav) return; /* allocate temp memory */ - temp = (INT16 *)osd_malloc(samples * 2 * sizeof(temp[0])); + temp = (INT16 *)osd_malloc_array(samples * 2 * sizeof(temp[0])); if (!temp) return; diff --git a/src/emu/ui.c b/src/emu/ui.c index 61110734aca..b29ebddc89d 100644 --- a/src/emu/ui.c +++ b/src/emu/ui.c @@ -280,7 +280,7 @@ int ui_display_startup_screens(running_machine &machine, int first_time, int sho /* disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver, or if we are debugging */ - if (!first_time || (str > 0 && str < 60*5) || &machine.system() == &GAME_NAME(empty) || (machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) + if (!first_time || (str > 0 && str < 60*5) || &machine.system() == &GAME_NAME(___empty) || (machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) show_gameinfo = show_warnings = show_disclaimer = FALSE; /* initialize the on-screen display system */ @@ -907,8 +907,6 @@ static astring &warnings_string(running_machine &machine, astring &string) GAME_IMPERFECT_GRAPHICS | \ GAME_NO_COCKTAIL) - int i; - string.reset(); /* if no warnings, nothing to return */ @@ -955,10 +953,6 @@ static astring &warnings_string(running_machine &machine, astring &string) /* if there's a NOT WORKING, UNEMULATED PROTECTION or GAME MECHANICAL warning, make it stronger */ if (machine.system().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) { - const game_driver *maindrv; - const game_driver *clone_of; - int foundworking; - /* add the strings for these warnings */ if (machine.system().flags & GAME_UNEMULATED_PROTECTION) string.cat("The game has protection which isn't fully emulated.\n"); @@ -970,25 +964,25 @@ static astring &warnings_string(running_machine &machine, astring &string) "It is not possible to fully play this " GAMENOUN ".\n"); /* find the parent of this driver */ - clone_of = driver_get_clone(&machine.system()); - if (clone_of != NULL && !(clone_of->flags & GAME_IS_BIOS_ROOT)) + driver_enumerator drivlist(machine.options()); + int maindrv = drivlist.find(machine.system()); + int clone_of = drivlist.non_bios_clone(maindrv); + if (clone_of != -1) maindrv = clone_of; - else - maindrv = &machine.system(); /* scan the driver list for any working clones and add them */ - foundworking = FALSE; - for (i = 0; drivers[i] != NULL; i++) - if (drivers[i] == maindrv || driver_get_clone(drivers[i]) == maindrv) - if ((drivers[i]->flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0) + bool foundworking = false; + while (drivlist.next()) + if (drivlist.current() == maindrv || drivlist.clone() == maindrv) + if ((drivlist.driver().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_MECHANICAL)) == 0) { /* this one works, add a header and display the name of the clone */ if (!foundworking) string.cat("\n\nThere are working clones of this game: "); else string.cat(", "); - string.cat(drivers[i]->name); - foundworking = TRUE; + string.cat(drivlist.driver().name); + foundworking = true; } if (foundworking) diff --git a/src/emu/uimenu.c b/src/emu/uimenu.c index efd14614b1b..91addf9ba55 100644 --- a/src/emu/uimenu.c +++ b/src/emu/uimenu.c @@ -208,7 +208,7 @@ struct _select_game_state UINT8 error; UINT8 rerandomize; char search[40]; - const game_driver * matchlist[VISIBLE_GAMES_IN_LIST]; + int matchlist[VISIBLE_GAMES_IN_LIST]; const game_driver * driverlist[1]; }; @@ -245,6 +245,9 @@ static const char priortext[] = "Return to Prior Menu"; static const char backtext[] = "Return to " CAPSTARTGAMENOUN; static const char exittext[] = "Exit"; +// temporary hack until this is C++-ified +static driver_enumerator *drivlist; + /*************************************************************************** @@ -299,7 +302,6 @@ static void menu_crosshair_populate(running_machine &machine, ui_menu *menu); static void menu_quit_game(running_machine &machine, ui_menu *menu, void *parameter, void *state); static void menu_select_game(running_machine &machine, ui_menu *menu, void *parameter, void *state); static void menu_select_game_populate(running_machine &machine, ui_menu *menu, select_game_state *menustate); -static int CLIB_DECL menu_select_game_driver_compare(const void *elem1, const void *elem2); static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate); static void menu_select_game_custom_render(running_machine &machine, ui_menu *menu, void *state, void *selectedref, float top, float bottom, float x, float y, float x2, float y2); @@ -3426,9 +3428,10 @@ static void menu_select_game(running_machine &machine, ui_menu *menu, void *para /* if no state, allocate some */ if (state == NULL) { - state = ui_menu_alloc_state(menu, sizeof(*menustate) + sizeof(menustate->driverlist) * driver_list_get_count(drivers), NULL); + state = ui_menu_alloc_state(menu, sizeof(*menustate) + sizeof(menustate->driverlist) * driver_list::total(), NULL); if (parameter != NULL) strcpy(((select_game_state *)state)->search, (const char *)parameter); + ((select_game_state *)state)->matchlist[0] = -1; } menustate = (select_game_state *)state; @@ -3459,24 +3462,20 @@ static void menu_select_game(running_machine &machine, ui_menu *menu, void *para /* anything else is a driver */ else { - audit_record *audit; - int audit_records; - int audit_result; - - /* audit the game first to see if we're going to work */ - audit_records = audit_images(menu->machine().options(), driver, AUDIT_VALIDATE_FAST, &audit); - audit_result = audit_summary(driver, audit_records, audit, FALSE); - if (audit_records > 0) - global_free(audit); - - /* if everything looks good, schedule the new driver */ - if (audit_result == CORRECT || audit_result == BEST_AVAILABLE) + // audit the game first to see if we're going to work + driver_enumerator enumerator(machine.options(), *driver); + enumerator.next(); + media_auditor auditor(enumerator); + media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST); + + // if everything looks good, schedule the new driver + if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE) { machine.schedule_new_driver(*driver); ui_menu_stack_reset(machine); } - /* otherwise, display an error */ + // otherwise, display an error else { ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_REF); @@ -3551,18 +3550,19 @@ static void menu_select_game_populate(running_machine &machine, ui_menu *menu, s } /* otherwise, rebuild the match list */ - if (menustate->search[0] != 0 || menustate->matchlist[0] == NULL || menustate->rerandomize) - driver_list_get_approx_matches(menustate->driverlist, menustate->search, matchcount, menustate->matchlist); + assert(drivlist != NULL); + if (menustate->search[0] != 0 || menustate->matchlist[0] == -1 || menustate->rerandomize) + drivlist->find_approximate_matches(menustate->search, matchcount, menustate->matchlist); menustate->rerandomize = FALSE; /* iterate over entries */ for (curitem = 0; curitem < matchcount; curitem++) { - const game_driver *driver = menustate->matchlist[curitem]; - if (driver != NULL) + int curmatch = menustate->matchlist[curitem]; + if (curmatch != -1) { - const game_driver *cloneof = driver_get_clone(driver); - ui_menu_item_append(menu, driver->name, driver->description, (cloneof == NULL || (cloneof->flags & GAME_IS_BIOS_ROOT)) ? 0 : MENU_FLAG_INVERT, (void *)driver); + int cloneof = drivlist->non_bios_clone(curmatch); + ui_menu_item_append(menu, drivlist->driver(curmatch).name, drivlist->driver(curmatch).description, (cloneof == -1) ? 0 : MENU_FLAG_INVERT, (void *)&drivlist->driver(curmatch)); } } @@ -3579,41 +3579,17 @@ static void menu_select_game_populate(running_machine &machine, ui_menu *menu, s /*------------------------------------------------- - menu_select_game_driver_compare - compare the - names of two drivers --------------------------------------------------*/ - -static int CLIB_DECL menu_select_game_driver_compare(const void *elem1, const void *elem2) -{ - const game_driver **driver1_ptr = (const game_driver **)elem1; - const game_driver **driver2_ptr = (const game_driver **)elem2; - const char *driver1 = (*driver1_ptr)->name; - const char *driver2 = (*driver2_ptr)->name; - - while (*driver1 == *driver2 && *driver1 != 0) - driver1++, driver2++; - return *driver1 - *driver2; -} - - -/*------------------------------------------------- menu_select_game_build_driver_list - build a list of available drivers -------------------------------------------------*/ static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *menustate) { - int driver_count = driver_list_get_count(drivers); - int drivnum, listnum; - UINT8 *found; - - /* create a sorted copy of the main driver list */ - memcpy((void *)menustate->driverlist, drivers, driver_count * sizeof(menustate->driverlist[0])); - qsort((void *)menustate->driverlist, driver_count, sizeof(menustate->driverlist[0]), menu_select_game_driver_compare); - - /* allocate a temporary array to track which ones we found */ - found = (UINT8 *)ui_menu_pool_alloc(menu, (driver_count + 7) / 8); - memset(found, 0, (driver_count + 7) / 8); + // start with an empty list + // hack alert: use new directly here to avoid reporting this one-time static memory as unfreed + if (drivlist == NULL) + drivlist = new driver_enumerator(menu->machine().options()); + drivlist->exclude_all(); /* open a path to the ROMs and find them in the array */ file_enumerator path(menu->machine().options().media_path()); @@ -3622,9 +3598,6 @@ static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state /* iterate while we get new objects */ while ((dir = path.next()) != NULL) { - game_driver tempdriver; - game_driver *tempdriver_ptr; - const game_driver **found_driver; char drivername[50]; char *dst = drivername; const char *src; @@ -3634,23 +3607,16 @@ static void menu_select_game_build_driver_list(ui_menu *menu, select_game_state *dst++ = tolower((UINT8)*src); *dst = 0; - /* find it in the array */ - tempdriver.name = drivername; - tempdriver_ptr = &tempdriver; - found_driver = (const game_driver **)bsearch(&tempdriver_ptr, menustate->driverlist, driver_count, sizeof(*menustate->driverlist), menu_select_game_driver_compare); - - /* if found, mark the corresponding entry in the array */ - if (found_driver != NULL) - { - int index = found_driver - menustate->driverlist; - found[index / 8] |= 1 << (index % 8); - } + int drivnum = drivlist->find(drivername); + if (drivnum != -1) + drivlist->include(drivnum); } /* now build the final list */ - for (drivnum = listnum = 0; drivnum < driver_count; drivnum++) - if (found[drivnum / 8] & (1 << (drivnum % 8))) - menustate->driverlist[listnum++] = menustate->driverlist[drivnum]; + drivlist->reset(); + int listnum = 0; + while (drivlist->next()) + menustate->driverlist[listnum++] = &drivlist->driver(); /* NULL-terminate */ menustate->driverlist[listnum] = NULL; diff --git a/src/emu/validity.c b/src/emu/validity.c index e15082da3c4..2e0fbbb84d1 100644 --- a/src/emu/validity.c +++ b/src/emu/validity.c @@ -314,12 +314,11 @@ static bool validate_inlines(void) information -------------------------------------------------*/ -static bool validate_driver(const machine_config &config, game_driver_map &names, game_driver_map &descriptions) +static bool validate_driver(driver_enumerator &drivlist, game_driver_map &names, game_driver_map &descriptions) { - const game_driver &driver = config.gamedrv(); - const game_driver *clone_of; + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); const char *compatible_with; - const game_driver *other_drv; bool error = FALSE, is_clone; const char *s; @@ -343,27 +342,27 @@ static bool validate_driver(const machine_config &config, game_driver_map &names /* determine the clone */ is_clone = (strcmp(driver.parent, "0") != 0); - clone_of = driver_get_clone(&driver); - if (clone_of && (clone_of->flags & GAME_IS_BIOS_ROOT)) + int clone_of = drivlist.clone(driver); + if (clone_of != -1 && (drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT)) is_clone = false; /* if we have at least 100 drivers, validate the clone */ /* (100 is arbitrary, but tries to avoid tiny.mak dependencies) */ - if (driver_list_get_count(drivers) > 100 && !clone_of && is_clone) + if (driver_list::total() > 100 && clone_of == -1 && is_clone) { mame_printf_error("%s: %s is a non-existant clone\n", driver.source_file, driver.parent); error = true; } /* look for recursive cloning */ - if (clone_of == &driver) + if (clone_of != -1 && &drivlist.driver(clone_of) == &driver) { mame_printf_error("%s: %s is set as a clone of itself\n", driver.source_file, driver.name); error = true; } /* look for clones that are too deep */ - if (clone_of != NULL && (clone_of = driver_get_clone(clone_of)) != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0) + if (clone_of != -1 && (clone_of = drivlist.non_bios_clone(clone_of)) != -1) { mame_printf_error("%s: %s is a clone of a clone\n", driver.source_file, driver.name); error = true; @@ -392,23 +391,23 @@ static bool validate_driver(const machine_config &config, game_driver_map &names compatible_with = NULL; /* check for this driver being compatible with a non-existant driver */ - if ((compatible_with != NULL) && (driver_get_name(driver.compatible_with) == NULL)) + if ((compatible_with != NULL) && (drivlist.find(driver.compatible_with) == -1)) { mame_printf_error("%s: is compatible with %s, which is not in drivers[]\n", driver.name, driver.compatible_with); error = true; } /* check for clone_of and compatible_with being specified at the same time */ - if ((driver_get_clone(&driver) != NULL) && (compatible_with != NULL)) + if ((drivlist.clone(driver) != -1) && (compatible_with != NULL)) { mame_printf_error("%s: both compatible_with and clone_of are specified\n", driver.name); error = true; } /* find any recursive dependencies on the current driver */ - for (other_drv = driver_get_compatible(&driver); other_drv != NULL; other_drv = driver_get_compatible(other_drv)) + for (int other_drv = drivlist.compatible_with(driver); other_drv != -1; other_drv = drivlist.compatible_with(other_drv)) { - if (&driver == other_drv) + if (&driver == &drivlist.driver(other_drv)) { mame_printf_error("%s: recursive compatibility\n", driver.name); error = true; @@ -432,9 +431,10 @@ static bool validate_driver(const machine_config &config, game_driver_map &names validate_roms - validate ROM definitions -------------------------------------------------*/ -static bool validate_roms(const machine_config &config, region_array *rgninfo, game_driver_map &roms) +static bool validate_roms(driver_enumerator &drivlist, region_array *rgninfo, game_driver_map &roms) { - const game_driver &driver = config.gamedrv(); + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); int bios_flags = 0, last_bios = 0; const char *last_rgnname = "???"; const char *last_name = "???"; @@ -579,9 +579,10 @@ static bool validate_roms(const machine_config &config, region_array *rgninfo, g configurations -------------------------------------------------*/ -static bool validate_display(const machine_config &config) +static bool validate_display(driver_enumerator &drivlist) { - const game_driver &driver = config.gamedrv(); + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); bool palette_modes = false; bool error = false; @@ -605,9 +606,10 @@ static bool validate_display(const machine_config &config) configuration -------------------------------------------------*/ -static bool validate_gfx(const machine_config &config, region_array *rgninfo) +static bool validate_gfx(driver_enumerator &drivlist, region_array *rgninfo) { - const game_driver &driver = config.gamedrv(); + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); bool error = false; int gfxnum; @@ -939,12 +941,13 @@ static void validate_dip_settings(const input_field_config *field, const game_dr validate_inputs - validate input configuration -------------------------------------------------*/ -static bool validate_inputs(const machine_config &config, int_map &defstr_map, ioport_list &portlist) +static bool validate_inputs(driver_enumerator &drivlist, int_map &defstr_map, ioport_list &portlist) { const input_port_config *scanport; const input_port_config *port; const input_field_config *field; - const game_driver &driver = config.gamedrv(); + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); int empty_string_found = FALSE; char errorbuf[1024]; bool error = false; @@ -1088,10 +1091,11 @@ static bool validate_inputs(const machine_config &config, int_map &defstr_map, i checks -------------------------------------------------*/ -static bool validate_devices(const machine_config &config, const ioport_list &portlist, region_array *rgninfo) +static bool validate_devices(driver_enumerator &drivlist, const ioport_list &portlist, region_array *rgninfo) { bool error = false; - const game_driver &driver = config.gamedrv(); + const game_driver &driver = drivlist.driver(); + const machine_config &config = drivlist.config(); for (const device_config *devconfig = config.m_devicelist.first(); devconfig != NULL; devconfig = devconfig->next()) { @@ -1126,7 +1130,6 @@ static bool validate_devices(const machine_config &config, const ioport_list &po void validate_drivers(emu_options &options, const game_driver *curdriver) { osd_ticks_t prep = 0; - osd_ticks_t expansion = 0; osd_ticks_t driver_checks = 0; osd_ticks_t rom_checks = 0; osd_ticks_t gfx_checks = 0; @@ -1186,9 +1189,10 @@ void validate_drivers(emu_options &options, const game_driver *curdriver) prep += get_profile_ticks(); /* iterate over all drivers */ - for (int drivnum = 0; drivers[drivnum]; drivnum++) + driver_enumerator drivlist(options); + while (drivlist.next()) { - const game_driver &driver = *drivers[drivnum]; + const game_driver &driver = drivlist.driver(); ioport_list portlist; region_array rgninfo; @@ -1198,39 +1202,34 @@ void validate_drivers(emu_options &options, const game_driver *curdriver) try { - /* expand the machine driver */ - expansion -= get_profile_ticks(); - machine_config config(driver, options); - expansion += get_profile_ticks(); - /* validate the driver entry */ driver_checks -= get_profile_ticks(); - error = validate_driver(config, names, descriptions) || error; + error = validate_driver(drivlist, names, descriptions) || error; driver_checks += get_profile_ticks(); /* validate the ROM information */ rom_checks -= get_profile_ticks(); - error = validate_roms(config, &rgninfo, roms) || error; + error = validate_roms(drivlist, &rgninfo, roms) || error; rom_checks += get_profile_ticks(); /* validate input ports */ input_checks -= get_profile_ticks(); - error = validate_inputs(config, defstr, portlist) || error; + error = validate_inputs(drivlist, defstr, portlist) || error; input_checks += get_profile_ticks(); /* validate the display */ display_checks -= get_profile_ticks(); - error = validate_display(config) || error; + error = validate_display(drivlist) || error; display_checks += get_profile_ticks(); /* validate the graphics decoding */ gfx_checks -= get_profile_ticks(); - error = validate_gfx(config, &rgninfo) || error; + error = validate_gfx(drivlist, &rgninfo) || error; gfx_checks += get_profile_ticks(); /* validate devices */ device_checks -= get_profile_ticks(); - error = validate_devices(config, portlist, &rgninfo) || error; + error = validate_devices(drivlist, portlist, &rgninfo) || error; device_checks += get_profile_ticks(); } catch (emu_fatalerror &err) @@ -1241,7 +1240,6 @@ void validate_drivers(emu_options &options, const game_driver *curdriver) #if (REPORT_TIMES) mame_printf_info("Prep: %8dm\n", (int)(prep / 1000000)); - mame_printf_info("Expansion: %8dm\n", (int)(expansion / 1000000)); mame_printf_info("Driver: %8dm\n", (int)(driver_checks / 1000000)); mame_printf_info("ROM: %8dm\n", (int)(rom_checks / 1000000)); mame_printf_info("CPU: %8dm\n", (int)(cpu_checks / 1000000)); |