diff options
Diffstat (limited to 'src/frontend/mame/clifront.cpp')
-rw-r--r-- | src/frontend/mame/clifront.cpp | 481 |
1 files changed, 300 insertions, 181 deletions
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index 2adb4e3ecc1..d7d9a8fdf08 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -23,6 +23,7 @@ #include "pluginopts.h" #include "emuopts.h" +#include "fileio.h" #include "romload.h" #include "softlist_dev.h" #include "validity.h" @@ -30,6 +31,7 @@ #include "chd.h" #include "corestr.h" +#include "path.h" #include "unzip.h" #include "xmlfile.h" @@ -37,7 +39,10 @@ #include <algorithm> #include <new> +#include <set> +#include <tuple> #include <cctype> +#include <iostream> //************************************************************************** @@ -61,6 +66,7 @@ #define CLICOMMAND_LISTBROTHERS "listbrothers" #define CLICOMMAND_LISTCRC "listcrc" #define CLICOMMAND_LISTROMS "listroms" +#define CLICOMMAND_LISTBIOS "listbios" #define CLICOMMAND_LISTSAMPLES "listsamples" #define CLICOMMAND_VERIFYROMS "verifyroms" #define CLICOMMAND_VERIFYSAMPLES "verifysamples" @@ -79,6 +85,7 @@ namespace { + //************************************************************************** // COMMAND-LINE OPTIONS //************************************************************************** @@ -86,40 +93,41 @@ namespace { const options_entry cli_option_entries[] = { /* core commands */ - { nullptr, nullptr, OPTION_HEADER, "CORE COMMANDS" }, - { CLICOMMAND_HELP ";h;?", "0", OPTION_COMMAND, "show help message" }, - { CLICOMMAND_VALIDATE ";valid", "0", OPTION_COMMAND, "perform validation on system drivers and devices" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE COMMANDS" }, + { CLICOMMAND_HELP ";h;?", "0", core_options::option_type::COMMAND, "show help message" }, + { CLICOMMAND_VALIDATE ";valid", "0", core_options::option_type::COMMAND, "perform validation on system drivers and devices" }, /* configuration commands */ - { nullptr, nullptr, OPTION_HEADER, "CONFIGURATION COMMANDS" }, - { CLICOMMAND_CREATECONFIG ";cc", "0", OPTION_COMMAND, "create the default configuration file" }, - { CLICOMMAND_SHOWCONFIG ";sc", "0", OPTION_COMMAND, "display running parameters" }, - { CLICOMMAND_SHOWUSAGE ";su", "0", OPTION_COMMAND, "show this help" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CONFIGURATION COMMANDS" }, + { CLICOMMAND_CREATECONFIG ";cc", "0", core_options::option_type::COMMAND, "create the default configuration file" }, + { CLICOMMAND_SHOWCONFIG ";sc", "0", core_options::option_type::COMMAND, "display running parameters" }, + { CLICOMMAND_SHOWUSAGE ";su", "0", core_options::option_type::COMMAND, "show this help" }, /* frontend commands */ - { nullptr, nullptr, OPTION_HEADER, "FRONTEND COMMANDS" }, - { CLICOMMAND_LISTXML ";lx", "0", OPTION_COMMAND, "all available info on driver in XML format" }, - { CLICOMMAND_LISTFULL ";ll", "0", OPTION_COMMAND, "short name, full name" }, - { CLICOMMAND_LISTSOURCE ";ls", "0", OPTION_COMMAND, "driver sourcefile" }, - { CLICOMMAND_LISTCLONES ";lc", "0", OPTION_COMMAND, "show clones" }, - { CLICOMMAND_LISTBROTHERS ";lb", "0", OPTION_COMMAND, "show \"brothers\", or other drivers from same sourcefile" }, - { CLICOMMAND_LISTCRC, "0", OPTION_COMMAND, "CRC-32s" }, - { CLICOMMAND_LISTROMS ";lr", "0", OPTION_COMMAND, "list required ROMs for a driver" }, - { CLICOMMAND_LISTSAMPLES, "0", OPTION_COMMAND, "list optional samples for a driver" }, - { CLICOMMAND_VERIFYROMS, "0", OPTION_COMMAND, "report romsets that have problems" }, - { CLICOMMAND_VERIFYSAMPLES, "0", OPTION_COMMAND, "report samplesets that have problems" }, - { CLICOMMAND_ROMIDENT, "0", OPTION_COMMAND, "compare files with known MAME ROMs" }, - { CLICOMMAND_LISTDEVICES ";ld", "0", OPTION_COMMAND, "list available devices" }, - { CLICOMMAND_LISTSLOTS ";lslot", "0", OPTION_COMMAND, "list available slots and slot devices" }, - { CLICOMMAND_LISTMEDIA ";lm", "0", OPTION_COMMAND, "list available media for the system" }, - { CLICOMMAND_LISTSOFTWARE ";lsoft", "0", OPTION_COMMAND, "list known software for the system" }, - { CLICOMMAND_VERIFYSOFTWARE ";vsoft", "0", OPTION_COMMAND, "verify known software for the system" }, - { CLICOMMAND_GETSOFTLIST ";glist", "0", OPTION_COMMAND, "retrieve software list by name" }, - { CLICOMMAND_VERIFYSOFTLIST ";vlist", "0", OPTION_COMMAND, "verify software list by name" }, - { CLICOMMAND_VERSION, "0", OPTION_COMMAND, "get MAME version" }, - - { nullptr, nullptr, OPTION_HEADER, "FRONTEND COMMAND OPTIONS" }, - { CLIOPTION_DTD, "1", OPTION_BOOLEAN, "include DTD in XML output" }, + { nullptr, nullptr, core_options::option_type::HEADER, "FRONTEND COMMANDS" }, + { CLICOMMAND_LISTXML ";lx", "0", core_options::option_type::COMMAND, "all available info on driver in XML format" }, + { CLICOMMAND_LISTFULL ";ll", "0", core_options::option_type::COMMAND, "short name, full name" }, + { CLICOMMAND_LISTSOURCE ";ls", "0", core_options::option_type::COMMAND, "driver sourcefile" }, + { CLICOMMAND_LISTCLONES ";lc", "0", core_options::option_type::COMMAND, "show clones" }, + { CLICOMMAND_LISTBROTHERS ";lb", "0", core_options::option_type::COMMAND, "show \"brothers\", or other drivers from same sourcefile" }, + { CLICOMMAND_LISTCRC, "0", core_options::option_type::COMMAND, "CRC-32s" }, + { CLICOMMAND_LISTROMS ";lr", "0", core_options::option_type::COMMAND, "list required ROMs for a driver" }, + { CLICOMMAND_LISTSAMPLES, "0", core_options::option_type::COMMAND, "list optional samples for a driver" }, + { CLICOMMAND_VERIFYROMS, "0", core_options::option_type::COMMAND, "report romsets that have problems" }, + { CLICOMMAND_VERIFYSAMPLES, "0", core_options::option_type::COMMAND, "report samplesets that have problems" }, + { CLICOMMAND_ROMIDENT, "0", core_options::option_type::COMMAND, "compare files with known MAME ROMs" }, + { CLICOMMAND_LISTDEVICES ";ld", "0", core_options::option_type::COMMAND, "list devices in a system" }, + { CLICOMMAND_LISTSLOTS ";lslot", "0", core_options::option_type::COMMAND, "list available slots and slot devices" }, + { CLICOMMAND_LISTBIOS, "0", core_options::option_type::COMMAND, "list BIOS options for a system" }, + { CLICOMMAND_LISTMEDIA ";lm", "0", core_options::option_type::COMMAND, "list available media for the system" }, + { CLICOMMAND_LISTSOFTWARE ";lsoft", "0", core_options::option_type::COMMAND, "list known software for the system" }, + { CLICOMMAND_VERIFYSOFTWARE ";vsoft", "0", core_options::option_type::COMMAND, "verify known software for the system" }, + { CLICOMMAND_GETSOFTLIST ";glist", "0", core_options::option_type::COMMAND, "retrieve software list by name" }, + { CLICOMMAND_VERIFYSOFTLIST ";vlist", "0", core_options::option_type::COMMAND, "verify software list by name" }, + { CLICOMMAND_VERSION, "0", core_options::option_type::COMMAND, "get MAME version" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "FRONTEND COMMAND OPTIONS" }, + { CLIOPTION_DTD, "1", core_options::option_type::BOOLEAN, "include DTD in XML output" }, { nullptr } }; @@ -294,7 +302,7 @@ int cli_frontend::execute(std::vector<std::string> &args) // reason for failure, offer some suggestions if (m_result == EMU_ERR_NO_SUCH_SYSTEM && !m_options.attempted_system_name().empty() - && !core_iswildstr(m_options.attempted_system_name().c_str()) + && !core_iswildstr(m_options.attempted_system_name()) && mame_options::system(m_options) == nullptr) { // get the top 16 approximate matches @@ -395,7 +403,10 @@ void cli_frontend::listsource(const std::vector<std::string> &args) { auto const list_system_source = [] (device_type type) { - osd_printf_info("%-16s %s\n", type.shortname(), core_filename_extract_base(type.source())); + osd_printf_info( + "%-16s %s\n", + type.shortname(), + info_xml_creator::format_sourcefile(type.source())); }; apply_action( args, @@ -494,11 +505,12 @@ void cli_frontend::listbrothers(const std::vector<std::string> &args) drivlist.reset(); while (drivlist.next()) { - int clone_of = drivlist.clone(); + auto const src(info_xml_creator::format_sourcefile(drivlist.driver().type.source())); + int const clone_of(drivlist.clone()); if (clone_of != -1) - osd_printf_info("%-20s %-16s %s\n", core_filename_extract_base(drivlist.driver().type.source()), drivlist.driver().name, (clone_of == -1 ? "" : drivlist.driver(clone_of).name)); + osd_printf_info("%-20s %-16s %s\n", src, drivlist.driver().name, (clone_of == -1 ? "" : drivlist.driver(clone_of).name)); else - osd_printf_info("%-20s %s\n", core_filename_extract_base(drivlist.driver().type.source()), drivlist.driver().name); + osd_printf_info("%-20s %s\n", src, drivlist.driver().name); } } @@ -547,58 +559,150 @@ void cli_frontend::listroms(const std::vector<std::string> &args) osd_printf_info("\n"); // iterate through ROMs - bool hasroms = false; + std::list<std::tuple<std::string, int64_t, std::string>> entries; + std::set<std::string_view> devnames; for (device_t const &device : device_enumerator(root)) { + bool hasroms = false; for (const rom_entry *region = rom_first_region(device); region; region = rom_next_region(region)) { for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { - // print a header if (!hasroms) - osd_printf_info( - "ROMs required for %s \"%s\".\n" - "%-32s %10s %s\n", - type, root.shortname(), "Name", "Size", "Checksum"); - hasroms = true; + { + hasroms = true; + if (&device != &root) + devnames.insert(device.shortname()); + } // accumulate the total length of all chunks int64_t length = -1; if (ROMREGION_ISROMDATA(region)) length = rom_file_size(rom); - // start with the name - osd_printf_info("%-32s ", rom->name()); + entries.emplace_back(rom->name(), length, rom->hashdata()); + } + } + } - // output the length next - if (length >= 0) - osd_printf_info("%10u", unsigned(uint64_t(length))); + // print results + if (entries.empty()) + osd_printf_info("No ROMs required for %s \"%s\".\n", type, root.shortname()); + else + { + // print a header + osd_printf_info("ROMs required for %s \"%s\"", type, root.shortname()); + if (!devnames.empty()) + { + osd_printf_info(" (including device%s", devnames.size() > 1 ? "s" : ""); + bool first = true; + for (const std::string_view &devname : devnames) + { + if (first) + first = false; else - osd_printf_info("%10s", ""); + osd_printf_info(","); + osd_printf_info(" \"%s\"", devname); + } + osd_printf_info(")"); + } + osd_printf_info(".\n%-32s %10s %s\n", "Name", "Size", "Checksum"); - // output the hash data - util::hash_collection hashes(rom->hashdata()); - if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP)) - { - if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP)) - osd_printf_info(" BAD"); - osd_printf_info(" %s", hashes.macro_string()); - } - else - osd_printf_info(" NO GOOD DUMP KNOWN"); + for (auto &entry : entries) + { + // start with the name + osd_printf_info("%-32s ", std::get<0>(entry)); + + // output the length next + int64_t length = std::get<1>(entry); + if (length >= 0) + osd_printf_info("%10u", unsigned(uint64_t(length))); + else + osd_printf_info("%10s", ""); - // end with a CR - osd_printf_info("\n"); + // output the hash data + util::hash_collection hashes(std::get<2>(entry)); + if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP)) + { + if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP)) + osd_printf_info(" BAD"); + osd_printf_info(" %s", hashes.macro_string()); } + else + osd_printf_info(" NO GOOD DUMP KNOWN"); + + // end with a CR + osd_printf_info("\n"); } } - if (!hasroms) - osd_printf_info("No ROMs required for %s \"%s\".\n", type, root.shortname()); }); } //------------------------------------------------- +// listbios - output the BIOS options for a system +// by matching systems/devices +//------------------------------------------------- + +void cli_frontend::listbios(const std::vector<std::string> &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_SYSTEM, "No matching systems found for '%s'", gamename); + + // iterate over drivers + bool firstsystem = true; + std::vector<std::pair<std::string, std::string> > bioses; + while (drivlist.next()) + { + device_t &root = drivlist.config()->root_device(); + if (firstsystem) + firstsystem = false; + else + printf("\n"); + + // print system BIOS options if there are any + bool firstbios = true; + for (const romload::system_bios &bios : romload::system_bioses(root.rom_region())) + { + if (firstbios) + { + printf("BIOS options for system %s (%s):\n", root.name(), root.shortname()); + firstbios = false; + } + printf(" %-16s %s\n", bios.get_name(), bios.get_description()); + } + if (firstbios) + printf("No BIOS options for system %s (%s)\n", root.name(), root.shortname()); + + // iterate over slots + for (const device_slot_interface &slot : slot_interface_enumerator(root)) + { + // ignore fixed or empty slots + device_t *const card = slot.get_card_device(); + if (slot.fixed() || !card || !card->rom_region()) + continue; + + // print card BIOS options if there are any + bool firstcard = true; + for (const romload::system_bios &bios : romload::system_bioses(card->rom_region())) + { + if (firstcard) + { + printf("\n BIOS options for device %s (-%s %s):\n", card->name(), slot.device().tag() + 1, card->basetag()); + firstcard = false; + } + printf(" %-16s %s\n", bios.get_name(), bios.get_description()); + } + } + } +} + + +//------------------------------------------------- // listsamples - output the list of samples // referenced by a given game or set of games //------------------------------------------------- @@ -725,7 +829,7 @@ void cli_frontend::listdevices(const std::vector<std::string> &args) //------------------------------------------------- // listslots - output the list of slot devices -// referenced by a given game or set of games +// present in a system or set of systems //------------------------------------------------- void cli_frontend::listslots(const std::vector<std::string> &args) @@ -744,11 +848,12 @@ void cli_frontend::listslots(const std::vector<std::string> &args) // iterate over drivers while (drivlist.next()) { - // iterate + // iterate over slots bool first = true; for (const device_slot_interface &slot : slot_interface_enumerator(drivlist.config()->root_device())) { - if (slot.fixed()) continue; + if (slot.fixed()) + continue; // build a list of user-selectable options std::vector<device_slot_interface::slot_option const *> option_list; @@ -757,9 +862,13 @@ void cli_frontend::listslots(const std::vector<std::string> &args) option_list.push_back(option.second.get()); // sort them by name - std::sort(option_list.begin(), option_list.end(), [](device_slot_interface::slot_option const *opt1, device_slot_interface::slot_option const *opt2) { - return strcmp(opt1->name(), opt2->name()) < 0; - }); + std::sort( + option_list.begin(), + option_list.end(), + [] (device_slot_interface::slot_option const *opt1, device_slot_interface::slot_option const *opt2) + { + return strcmp(opt1->name(), opt2->name()) < 0; + }); // output the line, up to the list of extensions @@ -852,7 +961,7 @@ void cli_frontend::listmedia(const std::vector<std::string> &args) //------------------------------------------------- void cli_frontend::verifyroms(const std::vector<std::string> &args) { - bool const iswild((1U != args.size()) || core_iswildstr(args[0].c_str())); + bool const iswild((1U != args.size()) || core_iswildstr(args[0])); std::vector<bool> matched(args.size(), false); unsigned matchcount = 0; auto const included = [&args, &matched, &matchcount] (char const *name) -> bool @@ -867,7 +976,7 @@ void cli_frontend::verifyroms(const std::vector<std::string> &args) auto it = matched.begin(); for (std::string const &pat : args) { - if (!core_strwildcmp(pat.c_str(), name)) + if (!core_strwildcmp(pat, name)) { ++matchcount; result = true; @@ -1006,18 +1115,17 @@ void cli_frontend::verifysamples(const std::vector<std::string> &args) if (matched == 0) throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching systems found for '%s'", gamename); - // if we didn't get anything at all, display a generic end message if (matched > 0 && correct == 0 && incorrect == 0) { + // if we didn't get anything at all, display a generic end message if (notfound > 0) throw emu_fatalerror(EMU_ERR_MISSING_FILES, "sampleset \"%s\" not found!\n", gamename); else throw emu_fatalerror(EMU_ERR_MISSING_FILES, "sampleset \"%s\" not required!\n", gamename); } - - // otherwise, print a summary else { + // otherwise, print a summary if (incorrect > 0) throw emu_fatalerror(EMU_ERR_MISSING_FILES, "%u samplesets found, %u were OK.\n", correct + incorrect, correct); osd_printf_info("%u samplesets found, %u were OK.\n", correct, correct); @@ -1025,93 +1133,100 @@ void cli_frontend::verifysamples(const std::vector<std::string> &args) } const char cli_frontend::s_softlist_xml_dtd[] = - "<?xml version=\"1.0\"?>\n" \ - "<!DOCTYPE softwarelists [\n" \ - "<!ELEMENT softwarelists (softwarelist*)>\n" \ - "\t<!ELEMENT softwarelist (software+)>\n" \ - "\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n" \ - "\t\t<!ATTLIST softwarelist description CDATA #IMPLIED>\n" \ - "\t\t<!ELEMENT software (description, year, publisher, info*, sharedfeat*, part*)>\n" \ - "\t\t\t<!ATTLIST software name CDATA #REQUIRED>\n" \ - "\t\t\t<!ATTLIST software cloneof CDATA #IMPLIED>\n" \ - "\t\t\t<!ATTLIST software supported (yes|partial|no) \"yes\">\n" \ - "\t\t\t<!ELEMENT description (#PCDATA)>\n" \ - "\t\t\t<!ELEMENT year (#PCDATA)>\n" \ - "\t\t\t<!ELEMENT publisher (#PCDATA)>\n" \ - "\t\t\t<!ELEMENT info EMPTY>\n" \ - "\t\t\t\t<!ATTLIST info name CDATA #REQUIRED>\n" \ - "\t\t\t\t<!ATTLIST info value CDATA #IMPLIED>\n" \ - "\t\t\t<!ELEMENT sharedfeat EMPTY>\n" \ - "\t\t\t\t<!ATTLIST sharedfeat name CDATA #REQUIRED>\n" \ - "\t\t\t\t<!ATTLIST sharedfeat value CDATA #IMPLIED>\n" \ - "\t\t\t<!ELEMENT part (feature*, dataarea*, diskarea*, dipswitch*)>\n" \ - "\t\t\t\t<!ATTLIST part name CDATA #REQUIRED>\n" \ - "\t\t\t\t<!ATTLIST part interface CDATA #REQUIRED>\n" \ - "\t\t\t\t<!ELEMENT feature EMPTY>\n" \ - "\t\t\t\t\t<!ATTLIST feature name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ATTLIST feature value CDATA #IMPLIED>\n" \ - "\t\t\t\t<!ELEMENT dataarea (rom*)>\n" \ - "\t\t\t\t\t<!ATTLIST dataarea name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ATTLIST dataarea size CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ATTLIST dataarea databits (8|16|32|64) \"8\">\n" \ - "\t\t\t\t\t<!ATTLIST dataarea endian (big|little) \"little\">\n" \ - "\t\t\t\t\t<!ELEMENT rom EMPTY>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom name CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom size CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom length CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom value CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n" \ - "\t\t\t\t\t\t<!ATTLIST rom loadflag (load16_byte|load16_word|load16_word_swap|load32_byte|load32_word|load32_word_swap|load32_dword|load64_word|load64_word_swap|reload|fill|continue|reload_plain) #IMPLIED>\n" \ - "\t\t\t\t<!ELEMENT diskarea (disk*)>\n" \ - "\t\t\t\t\t<!ATTLIST diskarea name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ELEMENT disk EMPTY>\n" \ - "\t\t\t\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n" \ - "\t\t\t\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n" \ - "\t\t\t\t\t\t<!ATTLIST disk writeable (yes|no) \"no\">\n" \ - "\t\t\t\t<!ELEMENT dipswitch (dipvalue*)>\n" \ - "\t\t\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n" \ - "\t\t\t\t\t<!ELEMENT dipvalue EMPTY>\n" \ - "\t\t\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n" \ - "\t\t\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n" \ - "\t\t\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n" \ + "<?xml version=\"1.0\"?>\n" + "<!DOCTYPE softwarelists [\n" + "<!ELEMENT softwarelists (softwarelist*)>\n" + "\t<!ELEMENT softwarelist (notes?, software+)>\n" + "\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n" + "\t\t<!ATTLIST softwarelist description CDATA #IMPLIED>\n" + "\t\t<!ELEMENT notes (#PCDATA)>\n" + "\t\t<!ELEMENT software (description, year, publisher, notes?, info*, sharedfeat*, part*)>\n" + "\t\t\t<!ATTLIST software name CDATA #REQUIRED>\n" + "\t\t\t<!ATTLIST software cloneof CDATA #IMPLIED>\n" + "\t\t\t<!ATTLIST software supported (yes|partial|no) \"yes\">\n" + "\t\t\t<!ELEMENT description (#PCDATA)>\n" + "\t\t\t<!ELEMENT year (#PCDATA)>\n" + "\t\t\t<!ELEMENT publisher (#PCDATA)>\n" + "\t\t\t<!ELEMENT notes (#PCDATA)>\n" + "\t\t\t<!ELEMENT info EMPTY>\n" + "\t\t\t\t<!ATTLIST info name CDATA #REQUIRED>\n" + "\t\t\t\t<!ATTLIST info value CDATA #IMPLIED>\n" + "\t\t\t<!ELEMENT sharedfeat EMPTY>\n" + "\t\t\t\t<!ATTLIST sharedfeat name CDATA #REQUIRED>\n" + "\t\t\t\t<!ATTLIST sharedfeat value CDATA #IMPLIED>\n" + "\t\t\t<!ELEMENT part (feature*, dataarea*, diskarea*, dipswitch*)>\n" + "\t\t\t\t<!ATTLIST part name CDATA #REQUIRED>\n" + "\t\t\t\t<!ATTLIST part interface CDATA #REQUIRED>\n" + "\t\t\t\t<!ELEMENT feature EMPTY>\n" + "\t\t\t\t\t<!ATTLIST feature name CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ATTLIST feature value CDATA #IMPLIED>\n" + "\t\t\t\t<!ELEMENT dataarea (rom*)>\n" + "\t\t\t\t\t<!ATTLIST dataarea name CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ATTLIST dataarea size CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ATTLIST dataarea databits (8|16|32|64) \"8\">\n" + "\t\t\t\t\t<!ATTLIST dataarea endian (big|little) \"little\">\n" + "\t\t\t\t\t<!ELEMENT rom EMPTY>\n" + "\t\t\t\t\t\t<!ATTLIST rom name CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom size CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom length CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom value CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n" + "\t\t\t\t\t\t<!ATTLIST rom loadflag (load16_byte|load16_word|load16_word_swap|load32_byte|load32_word|load32_word_swap|load32_dword|load64_word|load64_word_swap|reload|fill|continue|reload_plain) #IMPLIED>\n" + "\t\t\t\t<!ELEMENT diskarea (disk*)>\n" + "\t\t\t\t\t<!ATTLIST diskarea name CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ELEMENT disk EMPTY>\n" + "\t\t\t\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n" + "\t\t\t\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n" + "\t\t\t\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n" + "\t\t\t\t\t\t<!ATTLIST disk writeable (yes|no) \"no\">\n" + "\t\t\t\t<!ELEMENT dipswitch (dipvalue*)>\n" + "\t\t\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n" + "\t\t\t\t\t<!ELEMENT dipvalue EMPTY>\n" + "\t\t\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n" + "\t\t\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n" + "\t\t\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n" "]>\n\n"; void cli_frontend::output_single_softlist(std::ostream &out, software_list_device &swlistdev) { - util::stream_format(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlistdev.list_name(), util::xml::normalize_string(swlistdev.description().c_str())); + using util::xml::normalize_string; + + util::stream_format(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlistdev.list_name(), normalize_string(swlistdev.description())); for (const software_info &swinfo : swlistdev.get_info()) { - util::stream_format(out, "\t\t<software name=\"%s\"", util::xml::normalize_string(swinfo.shortname().c_str())); + util::stream_format(out, "\t\t<software name=\"%s\"", normalize_string(swinfo.shortname())); if (!swinfo.parentname().empty()) - util::stream_format(out, " cloneof=\"%s\"", util::xml::normalize_string(swinfo.parentname().c_str())); - if (swinfo.supported() == SOFTWARE_SUPPORTED_PARTIAL) + util::stream_format(out, " cloneof=\"%s\"", normalize_string(swinfo.parentname())); + if (swinfo.supported() == software_support::PARTIALLY_SUPPORTED) out << " supported=\"partial\""; - if (swinfo.supported() == SOFTWARE_SUPPORTED_NO) + else if (swinfo.supported() == software_support::UNSUPPORTED) out << " supported=\"no\""; out << ">\n"; - util::stream_format(out, "\t\t\t<description>%s</description>\n", util::xml::normalize_string(swinfo.longname().c_str())); - util::stream_format(out, "\t\t\t<year>%s</year>\n", util::xml::normalize_string(swinfo.year().c_str())); - util::stream_format(out, "\t\t\t<publisher>%s</publisher>\n", util::xml::normalize_string(swinfo.publisher().c_str())); + util::stream_format(out, "\t\t\t<description>%s</description>\n", normalize_string(swinfo.longname())); + util::stream_format(out, "\t\t\t<year>%s</year>\n", normalize_string(swinfo.year())); + util::stream_format(out, "\t\t\t<publisher>%s</publisher>\n", normalize_string(swinfo.publisher())); + + for (const auto &flist : swinfo.info()) + util::stream_format(out, "\t\t\t<info name=\"%s\" value=\"%s\"/>\n", flist.name(), normalize_string(flist.value())); - for (const feature_list_item &flist : swinfo.other_info()) - util::stream_format(out, "\t\t\t<info name=\"%s\" value=\"%s\"/>\n", flist.name(), util::xml::normalize_string(flist.value().c_str())); + for (const auto &flist : swinfo.shared_features()) + util::stream_format(out, "\t\t\t<sharedfeat name=\"%s\" value=\"%s\"/>\n", flist.name(), normalize_string(flist.value())); for (const software_part &part : swinfo.parts()) { - util::stream_format(out, "\t\t\t<part name=\"%s\"", util::xml::normalize_string(part.name().c_str())); + util::stream_format(out, "\t\t\t<part name=\"%s\"", normalize_string(part.name())); if (!part.interface().empty()) - util::stream_format(out, " interface=\"%s\"", util::xml::normalize_string(part.interface().c_str())); + util::stream_format(out, " interface=\"%s\"", normalize_string(part.interface())); out << ">\n"; - for (const feature_list_item &flist : part.featurelist()) - util::stream_format(out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", flist.name(), util::xml::normalize_string(flist.value().c_str())); + for (const auto &flist : part.features()) + util::stream_format(out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", flist.name(), normalize_string(flist.value())); // TODO: display ROM region information for (const rom_entry *region = part.romdata().data(); region; region = rom_next_region(region)) @@ -1119,18 +1234,18 @@ void cli_frontend::output_single_softlist(std::ostream &out, software_list_devic int is_disk = ROMREGION_ISDISKDATA(region); if (!is_disk) - util::stream_format(out, "\t\t\t\t<dataarea name=\"%s\" size=\"%d\">\n", util::xml::normalize_string(region->name().c_str()), region->get_length()); + util::stream_format(out, "\t\t\t\t<dataarea name=\"%s\" size=\"%d\">\n", normalize_string(region->name()), region->get_length()); else - util::stream_format(out, "\t\t\t\t<diskarea name=\"%s\">\n", util::xml::normalize_string(region->name().c_str())); + util::stream_format(out, "\t\t\t\t<diskarea name=\"%s\">\n", normalize_string(region->name())); for (const rom_entry *rom = rom_first_file(region); rom && !ROMENTRY_ISREGIONEND(rom); rom++) { if (ROMENTRY_ISFILE(rom)) { if (!is_disk) - util::stream_format(out, "\t\t\t\t\t<rom name=\"%s\" size=\"%d\"", util::xml::normalize_string(ROM_GETNAME(rom)), rom_file_size(rom)); + util::stream_format(out, "\t\t\t\t\t<rom name=\"%s\" size=\"%d\"", normalize_string(ROM_GETNAME(rom)), rom_file_size(rom)); else - util::stream_format(out, "\t\t\t\t\t<disk name=\"%s\"", util::xml::normalize_string(ROM_GETNAME(rom))); + util::stream_format(out, "\t\t\t\t\t<disk name=\"%s\"", normalize_string(ROM_GETNAME(rom))); // dump checksum information only if there is a known dump util::hash_collection hashes(rom->hashdata()); @@ -1246,27 +1361,24 @@ void cli_frontend::listsoftware(const std::vector<std::string> &args) -------------------------------------------------*/ void cli_frontend::verifysoftware(const std::vector<std::string> &args) { - const char *gamename = args.empty() ? "*" : args[0].c_str(); + char const *const gamename = args.empty() ? "*" : args[0].c_str(); + + // determine which drivers to process; return an error if none found + driver_enumerator drivlist(m_options, gamename); + if (!drivlist.count()) + throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching systems found for '%s'", gamename); std::unordered_set<std::string> list_map; unsigned correct = 0; unsigned incorrect = 0; unsigned notfound = 0; - unsigned matched = 0; unsigned nrlists = 0; - // determine which drivers to process; return an error if none found - driver_enumerator drivlist(m_options, gamename); - if (drivlist.count() == 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching systems found for '%s'", gamename); - media_auditor auditor(drivlist); util::ovectorstream summary_string; while (drivlist.next()) { - matched++; - for (software_list_device &swlistdev : software_list_device_enumerator(drivlist.config()->root_device())) { if (swlistdev.is_original()) @@ -1296,18 +1408,19 @@ void cli_frontend::verifysoftware(const std::vector<std::string> &args) util::archive_file::cache_clear(); // return an error if none found - if (matched == 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching systems found for '%s'", gamename); - - // if we didn't get anything at all, display a generic end message - if (matched > 0 && correct == 0 && incorrect == 0) + if (!nrlists) { - throw emu_fatalerror(EMU_ERR_MISSING_FILES, "romset \"%s\" has no software entries defined!\n", gamename); + throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No software list items are defined for systems matching '%s'", gamename); + } + else if (!correct && !incorrect) + { + // if we didn't get anything at all, display a generic end message + throw emu_fatalerror(EMU_ERR_MISSING_FILES, "No software items found for systems matching '%s'", gamename); } - // otherwise, print a summary else { - if (incorrect > 0) + // otherwise, print a summary + if (incorrect) throw emu_fatalerror(EMU_ERR_MISSING_FILES, "%u romsets found in %u software lists, %u were OK.\n", correct + incorrect, nrlists, correct); osd_printf_info("%u romsets found in %u software lists, %u romsets were OK.\n", correct, nrlists, correct); } @@ -1331,7 +1444,7 @@ void cli_frontend::getsoftlist(const std::vector<std::string> &args) { for (software_list_device &swlistdev : software_list_device_enumerator(root)) { - if (core_strwildcmp(gamename, swlistdev.list_name().c_str()) == 0 && list_map.insert(swlistdev.list_name()).second) + if (core_strwildcmp(gamename, swlistdev.list_name()) == 0 && list_map.insert(swlistdev.list_name()).second) { if (!swlistdev.get_info().empty()) { @@ -1376,7 +1489,7 @@ void cli_frontend::verifysoftlist(const std::vector<std::string> &args) { for (software_list_device &swlistdev : software_list_device_enumerator(drivlist.config()->root_device())) { - if (core_strwildcmp(gamename, swlistdev.list_name().c_str()) == 0 && list_map.insert(swlistdev.list_name()).second) + if (core_strwildcmp(gamename, swlistdev.list_name()) == 0 && list_map.insert(swlistdev.list_name()).second) { if (!swlistdev.get_info().empty()) { @@ -1442,7 +1555,7 @@ void cli_frontend::romident(const std::vector<std::string> &args) // create our own copy of options for the purposes of ROM identification // so we are not "polluted" with driver-specific slot/image options emu_options options; - options.set_value(OPTION_MEDIAPATH, m_options.media_path(), OPTION_PRIORITY_DEFAULT); + options.set_value(OPTION_HASHPATH, m_options.hash_path(), OPTION_PRIORITY_DEFAULT); media_identifier ident(options); @@ -1472,7 +1585,7 @@ void cli_frontend::romident(const std::vector<std::string> &args) template <typename T, typename U> void cli_frontend::apply_action(const std::vector<std::string> &args, T &&drvact, U &&devact) { - bool const iswild((1U != args.size()) || core_iswildstr(args[0].c_str())); + bool const iswild((1U != args.size()) || core_iswildstr(args[0])); std::vector<bool> matched(args.size(), false); auto const included = [&args, &matched] (char const *name) -> bool { @@ -1483,7 +1596,7 @@ template <typename T, typename U> void cli_frontend::apply_action(const std::vec auto it = matched.begin(); for (std::string const &pat : args) { - if (!core_strwildcmp(pat.c_str(), name)) + if (!core_strwildcmp(pat, name)) { result = true; *it = true; @@ -1579,6 +1692,7 @@ const cli_frontend::info_command_struct *cli_frontend::find_command(const std::s { 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_LISTBIOS, 0, 1, &cli_frontend::listbios, "[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, "[pattern] ..." }, @@ -1648,36 +1762,41 @@ void cli_frontend::execute_commands(std::string_view exename) // createconfig? if (m_options.command() == CLICOMMAND_CREATECONFIG) { - // attempt to open the output file + // attempt to open the output file and generate the updated (mame).ini emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(std::string(emulator_info::get_configname()) + ".ini") != osd_file::error::NONE) + if (file.open(std::string(emulator_info::get_configname()) + ".ini")) throw emu_fatalerror("Unable to create file %s.ini\n",emulator_info::get_configname()); - // generate the updated INI file.puts(m_options.output_ini()); + // ui.ini ui_options ui_opts; emu_file file_ui(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file_ui.open("ui.ini") != osd_file::error::NONE) + if (file_ui.open("ui.ini")) throw emu_fatalerror("Unable to create file ui.ini\n"); - // generate the updated INI file_ui.puts(ui_opts.output_ini()); + // plugin.ini plugin_options plugin_opts; path_iterator iter(m_options.plugins_path()); std::string pluginpath; while (iter.next(pluginpath)) - { - osd_subst_env(pluginpath, pluginpath); plugin_opts.scan_directory(pluginpath, true); - } - emu_file file_plugin(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file_plugin.open("plugin.ini") != osd_file::error::NONE) - throw emu_fatalerror("Unable to create file plugin.ini\n"); - // generate the updated INI - file_plugin.puts(plugin_opts.output_ini()); + std::string plugins(plugin_opts.output_ini()); + + // only update the file when it found plugins + if (!plugins.empty()) + { + emu_file file_plugin(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (file_plugin.open("plugin.ini")) + throw emu_fatalerror("Unable to create file plugin.ini\n"); + + file_plugin.puts(plugins); + } + else + osd_printf_error("Skipped plugin.ini, could not find any plugins\n"); return; } |