From 026905fb302162049ef9acf32c5894d4e24a2fbc Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 19 May 2017 10:46:26 +1000 Subject: [PATCH] More usability improvements: * Allow multiple patterns/names for -listxml * Fix some spurious errors from -listroms and -verifyroms with multiple patterns --- src/frontend/mame/clifront.cpp | 33 ++--- src/frontend/mame/info.cpp | 227 +++++++++++++++++++++--------- src/frontend/mame/info.h | 31 ++-- src/frontend/mame/ui/miscmenu.cpp | 144 +++++++++---------- 4 files changed, 259 insertions(+), 176 deletions(-) diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index 37a8044ad9a..4df8dddb4ca 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -319,16 +319,9 @@ int cli_frontend::execute(std::vector &args) void cli_frontend::listxml(const std::vector &args) { - const char *gamename = args.empty() ? nullptr : args[0].c_str(); - - // determine which drivers to output; return an error if none found - driver_enumerator drivlist(m_options, gamename); - if (drivlist.count() == 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename ? gamename : ""); - // create the XML and print it to stdout - info_xml_creator creator(drivlist, gamename && *gamename); - creator.output(stdout); + info_xml_creator creator(m_options); + creator.output(stdout, args); } @@ -512,23 +505,20 @@ void cli_frontend::listroms(const std::vector &args) auto const included = [&args, &matched] (char const *name) -> bool { if (args.empty()) - { return true; - } + bool result = false; auto it = matched.begin(); for (std::string const &pat : args) { if (!core_strwildcmp(pat.c_str(), name)) { + result = true; *it = true; - return true; } - ++it; } - - return false; + return result; }; bool first = true; @@ -878,20 +868,19 @@ void cli_frontend::verifyroms(const std::vector &args) return true; } + bool result = false; auto it = matched.begin(); for (std::string const &pat : args) { if (!core_strwildcmp(pat.c_str(), name)) { ++matchcount; + result = true; *it = true; - return true; } - ++it; } - - return false; + return result; }; unsigned correct = 0; @@ -1549,7 +1538,7 @@ void cli_frontend::execute_commands(const char *exename) const char *usage; } info_commands[] = { - { CLICOMMAND_LISTXML, 0, 1, &cli_frontend::listxml, "[system name]" }, + { CLICOMMAND_LISTXML, 0, -1, &cli_frontend::listxml, "[pattern] ..." }, { CLICOMMAND_LISTFULL, 0, 1, &cli_frontend::listfull, "[system name]" }, { CLICOMMAND_LISTSOURCE, 0, 1, &cli_frontend::listsource, "[system name]" }, { CLICOMMAND_LISTCLONES, 0, 1, &cli_frontend::listclones, "[system name]" }, @@ -1557,9 +1546,9 @@ void cli_frontend::execute_commands(const char *exename) { CLICOMMAND_LISTCRC, 0, 1, &cli_frontend::listcrc, "[system name]" }, { CLICOMMAND_LISTDEVICES, 0, 1, &cli_frontend::listdevices, "[system name]" }, { CLICOMMAND_LISTSLOTS, 0, 1, &cli_frontend::listslots, "[system name]" }, - { CLICOMMAND_LISTROMS, 0, -1, &cli_frontend::listroms, "[system name]" }, + { CLICOMMAND_LISTROMS, 0, -1, &cli_frontend::listroms, "[pattern] ..." }, { CLICOMMAND_LISTSAMPLES, 0, 1, &cli_frontend::listsamples, "[system name]" }, - { CLICOMMAND_VERIFYROMS, 0, -1, &cli_frontend::verifyroms, "[system name]" }, + { CLICOMMAND_VERIFYROMS, 0, -1, &cli_frontend::verifyroms, "[pattern] ..." }, { CLICOMMAND_VERIFYSAMPLES, 0, 1, &cli_frontend::verifysamples, "[system name|*]" }, { CLICOMMAND_LISTMEDIA, 0, 1, &cli_frontend::listmedia, "[system name]" }, { CLICOMMAND_LISTSOFTWARE, 0, 1, &cli_frontend::listsoftware, "[system name]" }, diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp index ea9b39bc731..ae1323786e9 100644 --- a/src/frontend/mame/info.cpp +++ b/src/frontend/mame/info.cpp @@ -189,11 +189,9 @@ const char info_xml_creator::s_dtd_string[] = // info_xml_creator - constructor //------------------------------------------------- -info_xml_creator::info_xml_creator(driver_enumerator &drivlist, bool filter_devices) +info_xml_creator::info_xml_creator(emu_options const &options) : m_output(nullptr) - , m_drivlist(drivlist) - , m_filter_devices(filter_devices) - , m_lookup_options(m_drivlist.options()) + , m_lookup_options(options) { mame_options::remove_device_options(m_lookup_options); } @@ -204,10 +202,108 @@ info_xml_creator::info_xml_creator(driver_enumerator &drivlist, bool filter_devi // for all known games //------------------------------------------------- -void info_xml_creator::output(FILE *out, bool nodevices) +void info_xml_creator::output(FILE *out, std::vector const &patterns) { m_output = out; + std::unique_ptr devfilter(patterns.empty() ? nullptr : new device_type_set); + + // track which patterns match machines + driver_enumerator drivlist(m_lookup_options); + std::vector matched(patterns.size(), false); + auto const included = [&patterns, &drivlist, &matched] () -> bool + { + if (patterns.empty()) + return true; + + char const *const name = drivlist.driver().name; + bool result = false; + auto it = matched.begin(); + for (std::string const &pat : patterns) + { + if (!core_strwildcmp(pat.c_str(), name)) + { + result = true; + *it = true; + } + ++it; + } + return result; + }; + + // iterate through the drivers, outputting one at a time + bool first = true; + while (drivlist.next()) + { + if (included()) + { + if (first) + { + output_header(); + first = false; + } + output_one(drivlist, devfilter.get()); + } + } + + // output devices (both devices with roms and slot devices) + if (!devfilter || !devfilter->empty()) + { + if (first) + { + output_header(); + first = false; + } + output_devices(devfilter.get()); + } + + if (!first) + output_footer(); + + // throw an error if there were unmatched patterns + auto it = matched.begin(); + for (std::string const &pat : patterns) + { + if (!*it) + throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching machines found for '%s'", pat.c_str()); + + ++it; + } +} + + +//------------------------------------------------- +// output_mame_xml - print the XML information +// for a subset of games +//------------------------------------------------- + +void info_xml_creator::output(FILE *out, driver_enumerator &drivlist, bool nodevices) +{ + m_output = out; + + device_type_set devfilter; + + output_header(); + + // iterate through the drivers, outputting one at a time + while (drivlist.next()) + output_one(drivlist, &devfilter); + + // output devices (both devices with roms and slot devices) + if (!nodevices) + output_devices(&devfilter); + + output_footer(); +} + + +//------------------------------------------------- +// output_header - print the XML DTD and open +// the root element +//------------------------------------------------- + +void info_xml_creator::output_header() +{ // output the DTD fprintf(m_output, "\n"); std::string dtd(s_dtd_string); @@ -228,19 +324,17 @@ void info_xml_creator::output(FILE *out, bool nodevices) util::xml::normalize_string(emulator_info::get_build_version()), CONFIG_VERSION ); +} - std::unique_ptr devfilter((m_filter_devices && !nodevices) ? new device_type_set : nullptr); - // iterate through the drivers, outputting one at a time - while (m_drivlist.next()) - output_one(devfilter.get()); - - // output devices (both devices with roms and slot devices) - if (!nodevices) - output_devices(devfilter.get()); +//------------------------------------------------- +// output_header - close the root element +//------------------------------------------------- +void info_xml_creator::output_footer() +{ // close the top level tag - fprintf(m_output, "\n",XML_ROOT); + fprintf(m_output, "\n", XML_ROOT); } @@ -249,14 +343,14 @@ void info_xml_creator::output(FILE *out, bool nodevices) // for one particular game driver //------------------------------------------------- -void info_xml_creator::output_one(device_type_set *devtypes) +void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *devtypes) { // no action if not a game - const game_driver &driver = m_drivlist.driver(); + const game_driver &driver = drivlist.driver(); if (driver.flags & MACHINE_NO_STANDALONE) return; - std::shared_ptr const config(m_drivlist.config()); + std::shared_ptr const config(drivlist.config()); device_iterator iter(config->root_device()); // allocate input ports @@ -318,11 +412,11 @@ void info_xml_creator::output_one(device_type_set *devtypes) 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 & MACHINE_IS_BIOS_ROOT)) - fprintf(m_output, " cloneof=\"%s\"", util::xml::normalize_string(m_drivlist.driver(clone_of).name)); + int clone_of = drivlist.find(driver.parent); + if (clone_of != -1 && !(drivlist.driver(clone_of).flags & MACHINE_IS_BIOS_ROOT)) + fprintf(m_output, " cloneof=\"%s\"", util::xml::normalize_string(drivlist.driver(clone_of).name)); if (clone_of != -1) - fprintf(m_output, " romof=\"%s\"", util::xml::normalize_string(m_drivlist.driver(clone_of).name)); + fprintf(m_output, " romof=\"%s\"", util::xml::normalize_string(drivlist.driver(clone_of).name)); // display sample information and close the game tag output_sampleof(config->root_device()); @@ -341,23 +435,23 @@ void info_xml_creator::output_one(device_type_set *devtypes) fprintf(m_output, "\t\t%s\n", util::xml::normalize_string(driver.manufacturer)); // now print various additional information - output_bios(); - output_rom(config->root_device()); - output_device_roms(); + output_bios(driver); + output_rom(&drivlist, config->root_device()); + output_device_roms(config->root_device()); output_sample(config->root_device()); output_chips(config->root_device(), ""); - output_display(config->root_device(), &m_drivlist.driver().flags, ""); + output_display(config->root_device(), &drivlist.driver().flags, ""); output_sound(config->root_device()); output_input(portlist); output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "dipvalue"); output_switches(portlist, "", IPT_CONFIG, "configuration", "confsetting"); output_ports(portlist); output_adjusters(portlist); - output_driver(); + output_driver(driver); output_images(config->root_device(), ""); output_slots(*config, config->root_device(), "", devtypes); - output_software_list(); - output_ramoptions(); + output_software_list(config->root_device()); + output_ramoptions(config->root_device()); // close the topmost tag fprintf(m_output, "\t\n",XML_TOP); @@ -402,7 +496,7 @@ void info_xml_creator::output_one_device(machine_config &config, device_t &devic fprintf(m_output, ">\n"); fprintf(m_output, "\t\t%s\n", util::xml::normalize_string(device.name())); - output_rom(device); + output_rom(nullptr, device); if (device.type().type() != typeid(samples_device)) // ignore samples_device itself output_sample(device); @@ -471,10 +565,10 @@ void info_xml_creator::output_devices(device_type_set const *filter) // included in a device set, print a reference //------------------------------------------------- -void info_xml_creator::output_device_roms() +void info_xml_creator::output_device_roms(device_t &root) { - for (device_t &device : device_iterator(m_drivlist.config()->root_device())) - if (device.owner() != nullptr && device.shortname() != nullptr && device.shortname()[0] != '\0') + for (device_t &device : device_iterator(root)) + if (device.owner()) fprintf(m_output, "\t\t\n", util::xml::normalize_string(device.shortname())); } @@ -506,32 +600,32 @@ void info_xml_creator::output_sampleof(device_t &device) // game //------------------------------------------------- -void info_xml_creator::output_bios() +void info_xml_creator::output_bios(game_driver const &driver) { // skip if no ROMs - if (m_drivlist.driver().rom == nullptr) - return; + if (driver.rom) + { + auto rom_entries = rom_build_entries(driver.rom); - auto rom_entries = rom_build_entries(m_drivlist.driver().rom); + // first determine the default BIOS name + std::string defaultname; + for (const rom_entry &rom : rom_entries) + if (ROMENTRY_ISDEFAULT_BIOS(&rom)) + defaultname = ROM_GETNAME(&rom); - // first determine the default BIOS name - std::string defaultname; - for (const rom_entry &rom : rom_entries) - if (ROMENTRY_ISDEFAULT_BIOS(&rom)) - defaultname = ROM_GETNAME(&rom); - - // iterate over ROM entries and look for BIOSes - for (const rom_entry &rom : rom_entries) - if (ROMENTRY_ISSYSTEM_BIOS(&rom)) - { - // output extracted name and descriptions - fprintf(m_output, "\t\t\n"); - } + // iterate over ROM entries and look for BIOSes + for (const rom_entry &rom : rom_entries) + if (ROMENTRY_ISSYSTEM_BIOS(&rom)) + { + // output extracted name and descriptions + fprintf(m_output, "\t\t\n"); + } + } } @@ -540,9 +634,10 @@ void info_xml_creator::output_bios() // the XML output //------------------------------------------------- -void info_xml_creator::output_rom(device_t &device) +void info_xml_creator::output_rom(driver_enumerator *drivlist, device_t &device) { // iterate over 3 different ROM "types": BIOS, ROMs, DISKs + bool const do_merge_name = drivlist && dynamic_cast(&device); for (int rom_type = 0; rom_type < 3; rom_type++) for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region)) { @@ -567,8 +662,8 @@ void info_xml_creator::output_rom(device_t &device) // if we have a valid ROM and we are a clone, see if we can find the parent ROM util::hash_collection hashes(ROM_GETHASHDATA(rom)); - if (dynamic_cast(&device) &&!hashes.flag(util::hash_collection::FLAG_NO_DUMP)) - merge_name = get_merge_name(hashes); + if (do_merge_name && !hashes.flag(util::hash_collection::FLAG_NO_DUMP)) + merge_name = get_merge_name(*drivlist, hashes); // scan for a BIOS name bios_name[0] = 0; @@ -1385,7 +1480,7 @@ void info_xml_creator::output_adjusters(const ioport_list &portlist) // output_driver - print driver status //------------------------------------------------- -void info_xml_creator::output_driver() +void info_xml_creator::output_driver(game_driver const &driver) { fprintf(m_output, "\t\troot_device())) + for (const software_list_device &swlist : software_list_device_iterator(root)) { fprintf(m_output, "\t\troot_device())) + for (const ram_device &ram : ram_device_iterator(root)) { fprintf(m_output, "\t\t%u\n", ram.default_size()); @@ -1615,14 +1710,14 @@ void info_xml_creator::output_ramoptions() // parent set //------------------------------------------------- -const char *info_xml_creator::get_merge_name(const util::hash_collection &romhashes) +const char *info_xml_creator::get_merge_name(driver_enumerator &drivlist, util::hash_collection const &romhashes) { // walk the parent chain const char *merge_name = nullptr; - 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)) + for (int clone_of = drivlist.find(drivlist.driver().parent); clone_of != -1; clone_of = drivlist.find(drivlist.driver(clone_of).parent)) { // look in the parent's ROMs - device_t *device = &m_drivlist.config(clone_of, m_lookup_options)->root_device(); + device_t *device = &drivlist.config(clone_of, m_lookup_options)->root_device(); for (const rom_entry *pregion = rom_first_region(*device); pregion != nullptr; pregion = rom_next_region(pregion)) for (const rom_entry *prom = rom_first_file(pregion); prom != nullptr; prom = rom_next_file(prom)) { diff --git a/src/frontend/mame/info.h b/src/frontend/mame/info.h index c36daf3b6ee..23d01b8e1ae 100644 --- a/src/frontend/mame/info.h +++ b/src/frontend/mame/info.h @@ -17,6 +17,7 @@ #include #include +#include class driver_enumerator; @@ -31,20 +32,24 @@ class info_xml_creator { public: // construction/destruction - info_xml_creator(driver_enumerator &drivlist, bool filter_devices); + info_xml_creator(emu_options const &options); // output - void output(FILE *out, bool nodevices = false); + void output(FILE *out, std::vector const &patterns); + void output(FILE *out, driver_enumerator &drivlist, bool nodevices); private: typedef std::unordered_set > device_type_set; // internal helper - void output_one(device_type_set *devtypes); + void output_header(); + void output_footer(); + + void output_one(driver_enumerator &drivlist, device_type_set *devtypes); void output_sampleof(device_t &device); - void output_bios(); - void output_rom(device_t &device); - void output_device_roms(); + void output_bios(game_driver const &driver); + void output_rom(driver_enumerator *drivlist, device_t &device); + void output_device_roms(device_t &root); void output_sample(device_t &device); void output_chips(device_t &device, const char *root_tag); void output_display(device_t &device, u32 const *flags, const char *root_tag); @@ -53,22 +58,20 @@ private: void output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *innertag); void output_ports(const ioport_list &portlist); void output_adjusters(const ioport_list &portlist); - void output_driver(); + void output_driver(game_driver const &driver); void output_images(device_t &device, const char *root_tag); void output_slots(machine_config &config, device_t &device, const char *root_tag, device_type_set *devtypes); - void output_software_list(); - void output_ramoptions(); + void output_software_list(device_t &root); + void output_ramoptions(device_t &root); void output_one_device(machine_config &config, device_t &device, const char *devtag); void output_devices(device_type_set const *filter); - const char *get_merge_name(const util::hash_collection &romhashes); + const char *get_merge_name(driver_enumerator &drivlist, util::hash_collection const &romhashes); // internal state - FILE * m_output; - driver_enumerator & m_drivlist; - bool m_filter_devices; - emu_options m_lookup_options; + FILE * m_output; // FIXME: this is not reentrancy-safe + emu_options m_lookup_options; static const char s_dtd_string[]; }; diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 6f5d211d933..6d797bc8dda 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -566,91 +566,87 @@ void menu_export::handle() const event *menu_event = process(PROCESS_NOIMAGE); if (menu_event != nullptr && menu_event->itemref != nullptr) { - switch ((uintptr_t)menu_event->itemref) + switch (uintptr_t(menu_event->itemref)) { - case 1: - case 3: + case 1: + case 3: + if (menu_event->iptkey == IPT_UI_SELECT) { - if (menu_event->iptkey == IPT_UI_SELECT) - { - std::string filename("exported"); - emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ); - if (infile.open(filename.c_str(), ".xml") == osd_file::error::NONE) - for (int seq = 0; ; ++seq) - { - std::string seqtext = string_format("%s_%04d", filename, seq); - if (infile.open(seqtext.c_str(), ".xml") != osd_file::error::NONE) - { - filename = seqtext; - break; - } - } - - // attempt to open the output file - emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(filename.c_str(), ".xml") == osd_file::error::NONE) + std::string filename("exported"); + emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ); + if (infile.open(filename.c_str(), ".xml") == osd_file::error::NONE) + for (int seq = 0; ; ++seq) { - FILE *pfile; - std::string fullpath(file.fullpath()); - file.close(); - pfile = fopen(fullpath.c_str(), "w"); - - // create the XML and save to file - driver_enumerator drvlist(machine().options()); - drvlist.exclude_all(); - for (auto & elem : m_list) - drvlist.include(driver_list::find(*elem)); - - info_xml_creator creator(drvlist, true); - creator.output(pfile, ((uintptr_t)menu_event->itemref == 1) ? false : true); - fclose(pfile); - machine().popmessage(_("%s.xml saved under ui folder."), filename.c_str()); + std::string seqtext = string_format("%s_%04d", filename, seq); + if (infile.open(seqtext.c_str(), ".xml") != osd_file::error::NONE) + { + filename = seqtext; + break; + } } + + // attempt to open the output file + emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (file.open(filename.c_str(), ".xml") == osd_file::error::NONE) + { + FILE *pfile; + std::string fullpath(file.fullpath()); + file.close(); + pfile = fopen(fullpath.c_str(), "w"); + + // create the XML and save to file + driver_enumerator drvlist(machine().options()); + drvlist.exclude_all(); + for (auto & elem : m_list) + drvlist.include(driver_list::find(*elem)); + + info_xml_creator creator(machine().options()); + creator.output(pfile, drvlist, (uintptr_t(menu_event->itemref) == 1) ? false : true); + fclose(pfile); + machine().popmessage(_("%s.xml saved under ui folder."), filename.c_str()); } - break; } - case 2: + break; + case 2: + if (menu_event->iptkey == IPT_UI_SELECT) { - if (menu_event->iptkey == IPT_UI_SELECT) - { - std::string filename("exported"); - emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ); - if (infile.open(filename.c_str(), ".txt") == osd_file::error::NONE) - for (int seq = 0; ; ++seq) - { - std::string seqtext = string_format("%s_%04d", filename, seq); - if (infile.open(seqtext.c_str(), ".txt") != osd_file::error::NONE) - { - filename = seqtext; - break; - } - } - - // attempt to open the output file - emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(filename.c_str(), ".txt") == osd_file::error::NONE) + std::string filename("exported"); + emu_file infile(ui().options().ui_path(), OPEN_FLAG_READ); + if (infile.open(filename.c_str(), ".txt") == osd_file::error::NONE) + for (int seq = 0; ; ++seq) { - // print the header - std::ostringstream buffer; - buffer << _("Name: Description:\n"); - driver_enumerator drvlist(machine().options()); - drvlist.exclude_all(); - for (auto & elem : m_list) - drvlist.include(driver_list::find(*elem)); - - // iterate through drivers and output the info - while (drvlist.next()) - if ((drvlist.driver().flags & MACHINE_NO_STANDALONE) == 0) - util::stream_format(buffer, "%-18s\"%s\"\n", drvlist.driver().name, drvlist.driver().type.fullname()); - file.puts(buffer.str().c_str()); - file.close(); - machine().popmessage(_("%s.txt saved under ui folder."), filename.c_str()); + std::string seqtext = string_format("%s_%04d", filename, seq); + if (infile.open(seqtext.c_str(), ".txt") != osd_file::error::NONE) + { + filename = seqtext; + break; + } } + + // attempt to open the output file + emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (file.open(filename.c_str(), ".txt") == osd_file::error::NONE) + { + // print the header + std::ostringstream buffer; + buffer << _("Name: Description:\n"); + driver_enumerator drvlist(machine().options()); + drvlist.exclude_all(); + for (auto & elem : m_list) + drvlist.include(driver_list::find(*elem)); + + // iterate through drivers and output the info + while (drvlist.next()) + if ((drvlist.driver().flags & MACHINE_NO_STANDALONE) == 0) + util::stream_format(buffer, "%-18s\"%s\"\n", drvlist.driver().name, drvlist.driver().type.fullname()); + file.puts(buffer.str().c_str()); + file.close(); + machine().popmessage(_("%s.txt saved under ui folder."), filename.c_str()); } - break; } - default: - break; + break; + default: + break; } } }