diff options
author | Vas Crabb <vas@vastheman.com> | 2021-06-23 16:08:59 +1000 |
---|---|---|
committer | Vas Crabb <vas@vastheman.com> | 2021-06-23 16:08:59 +1000 |
commit | c9a62818e9135c5b757cfbaa940c83ca5371e275 (patch) | |
tree | 2308021b4c003b9f6abe29efbb00aabe67909e01 /src/emu | |
parent | 12959e6e97a229c91757dff52f5153ca49cc7ced (diff) |
-Miscellaneous improvements for software lists:
* Show list name in software selection menu (machines have multiple
lists).
* Actually report software list parsing errors during validation.
* Check that software list name attribute matches filename.
* Limit software list names to 24 characters - they're getting too long,
and they need to be practical in command lines.
* c128.cpp: Fix dangling reference to renamed software list.
-emu/ioport.cpp: Slightly better test for deselected slot cards.
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/diimage.cpp | 5 | ||||
-rw-r--r-- | src/emu/ioport.cpp | 24 | ||||
-rw-r--r-- | src/emu/romload.cpp | 5 | ||||
-rw-r--r-- | src/emu/softlist.cpp | 152 | ||||
-rw-r--r-- | src/emu/softlist.h | 112 | ||||
-rw-r--r-- | src/emu/softlist_dev.cpp | 114 | ||||
-rw-r--r-- | src/emu/softlist_dev.h | 4 |
7 files changed, 227 insertions, 189 deletions
diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 9f63ebd4b4b..55a9193f3f1 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -801,10 +801,9 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st if (!swinfo) return false; - const u32 supported = swinfo->supported(); - if (supported == SOFTWARE_SUPPORTED_PARTIAL) + if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); - if (supported == SOFTWARE_SUPPORTED_NO) + else if (swinfo->supported() == software_support::UNSUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()); u32 crc = 0; diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 3c88c319a8b..02713356bf7 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -2323,20 +2323,24 @@ void ioport_manager::load_game_config(util::xml::data_node const *portnode, int if (pos && (std::string_view::npos != pos)) { parent_tag = parent_tag.substr(0, pos); - for (pos = parent_tag.rfind(':'); pos && (std::string_view::npos != pos); pos = parent_tag.rfind(':')) + if (!machine().root_device().subdevice(parent_tag)) { - parent_tag = parent_tag.substr(0, pos); - device_t const *const parent_device(machine().root_device().subdevice(parent_tag)); - if (parent_device) + for (pos = parent_tag.rfind(':'); pos && (std::string_view::npos != pos); pos = parent_tag.rfind(':')) { - device_slot_interface const *slot; - if (parent_device->interface(slot)) + std::string_view const child_tag(parent_tag.substr(pos + 1)); + parent_tag = parent_tag.substr(0, pos); + device_t const *const parent_device(machine().root_device().subdevice(parent_tag)); + if (parent_device) { - if (!m_deselected_card_config) - m_deselected_card_config = util::xml::file::create().release(); - portnode->copy_into(*m_deselected_card_config); + device_slot_interface const *slot; + if (parent_device->interface(slot) && (slot->option_list().find(std::string(child_tag)) != slot->option_list().end())) + { + if (!m_deselected_card_config) + m_deselected_card_config = util::xml::file::create().release(); + portnode->copy_into(*m_deselected_card_config); + } + break; } - break; } } } diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp index 6ecc8ad6547..36d7896e467 100644 --- a/src/emu/romload.cpp +++ b/src/emu/romload.cpp @@ -1222,13 +1222,12 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list { // dispay a warning for unsupported software // TODO: list supported clones like we do for machines? - const u32 supported(swinfo->supported()); - if (supported == SOFTWARE_SUPPORTED_PARTIAL) + if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) { m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name())); m_softwarningstring.append(string_format("Support for software %s (in list %s) is only partial\n", swname, swlist.list_name())); } - if (supported == SOFTWARE_SUPPORTED_NO) + else if (swinfo->supported() == software_support::UNSUPPORTED) { m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name())); m_softwarningstring.append(string_format("Support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name())); diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp index 8166888f80a..d7dec822f3d 100644 --- a/src/emu/softlist.cpp +++ b/src/emu/softlist.cpp @@ -36,7 +36,6 @@ static std::regex s_potential_softlist_regex("\\w+(\\:\\w+)*"); //------------------------------------------------- feature_list_item::feature_list_item(const std::string &name, const std::string &value) : - m_next(nullptr), m_name(name), m_value(value) { @@ -48,7 +47,6 @@ feature_list_item::feature_list_item(const std::string &name, const std::string //------------------------------------------------- feature_list_item::feature_list_item(std::string &&name, std::string &&value) : - m_next(nullptr), m_name(std::move(name)), m_value(std::move(value)) { @@ -64,7 +62,6 @@ feature_list_item::feature_list_item(std::string &&name, std::string &&value) : //------------------------------------------------- software_part::software_part(software_info &info, std::string &&name, std::string &&interface) : - m_next(nullptr), m_info(info), m_name(std::move(name)), m_interface(std::move(interface)) @@ -77,7 +74,7 @@ software_part::software_part(software_info &info, std::string &&name, std::strin // feature, if specified //------------------------------------------------- -const char *software_part::feature(const std::string &feature_name) const noexcept +const char *software_part::feature(std::string_view feature_name) const noexcept { // scan the feature list for an entry matching feature_name and return the value auto iter = std::find_if( @@ -126,16 +123,16 @@ bool software_part::matches_interface(const char *interface_list) const noexcept // software_info - constructor //------------------------------------------------- -software_info::software_info(std::string &&name, std::string &&parent, const std::string &supported) : - m_supported(SOFTWARE_SUPPORTED_YES), +software_info::software_info(std::string &&name, std::string &&parent, std::string_view supported) : + m_supported(software_support::SUPPORTED), m_shortname(std::move(name)), m_parentname(std::move(parent)) { // handle the supported flag if provided if (supported == "partial") - m_supported = SOFTWARE_SUPPORTED_PARTIAL; + m_supported = software_support::PARTIALLY_SUPPORTED; else if (supported == "no") - m_supported = SOFTWARE_SUPPORTED_NO; + m_supported = software_support::UNSUPPORTED; } @@ -144,13 +141,13 @@ software_info::software_info(std::string &&name, std::string &&parent, const std // optional interface match //------------------------------------------------- -const software_part *software_info::find_part(const std::string &part_name, const char *interface) const +const software_part *software_info::find_part(std::string_view part_name, const char *interface) const { // look for the part by name and match against the interface if provided auto iter = std::find_if( m_partdata.begin(), m_partdata.end(), - [&](const software_part &part) + [&part_name, interface] (const software_part &part) { // try to match the part_name (or all parts if part_name is empty), and then try // to match the interface (or all interfaces if interface is nullptr) @@ -184,20 +181,97 @@ bool software_info::has_multiple_parts(const char *interface) const } +namespace detail { + //************************************************************************** // SOFTWARE LIST PARSER //************************************************************************** +class softlist_parser +{ +public: + // construction (== execution) + softlist_parser( + util::core_file &file, + std::string_view filename, + std::string &listname, + std::string &description, + std::list<software_info> &infolist, + std::ostream &errors); + +private: + enum parse_position + { + POS_ROOT, + POS_MAIN, + POS_SOFT, + POS_PART, + POS_DATA + }; + + // internal parsing helpers + const char *infoname() const { return m_current_info ? m_current_info->shortname().c_str() : "???"; } + int line() const { return XML_GetCurrentLineNumber(m_parser); } + int column() const { return XML_GetCurrentColumnNumber(m_parser); } + const char *parser_error() const { return XML_ErrorString(XML_GetErrorCode(m_parser)); } + + // internal error helpers + template <typename Format, typename... Params> void parse_error(Format &&fmt, Params &&... args); + void unknown_tag(const char *tagname) { parse_error("Unknown tag: %s", tagname); } + void unknown_attribute(const char *attrname) { parse_error("Unknown attribute: %s", attrname); } + + // internal helpers + template <typename T> std::vector<std::string> parse_attributes(const char **attributes, const T &attrlist); + bool parse_name_and_value(const char **attributes, std::string &name, std::string &value); + void add_rom_entry(std::string &&name, std::string &&hashdata, u32 offset, u32 length, u32 flags); + + // expat callbacks + static void start_handler(void *data, const char *tagname, const char **attributes); + static void data_handler(void *data, const char *s, int len); + static void end_handler(void *data, const char *name); + + // internal parsing + void parse_root_start(const char *tagname, const char **attributes); + void parse_main_start(const char *tagname, const char **attributes); + void parse_soft_start(const char *tagname, const char **attributes); + void parse_part_start(const char *tagname, const char **attributes); + void parse_data_start(const char *tagname, const char **attributes); + void parse_soft_end(const char *name); + + // internal parsing state + util::core_file & m_file; + const std::string_view m_filename; + std::list<software_info> & m_infolist; + std::ostream & m_errors; + struct XML_ParserStruct * m_parser; + bool m_done; + std::string & m_listname; + std::string & m_description; + bool m_data_accum_expected; + std::string m_data_accum; + software_info * m_current_info; + software_part * m_current_part; + parse_position m_pos; +}; + + //------------------------------------------------- // softlist_parser - constructor //------------------------------------------------- -softlist_parser::softlist_parser(util::core_file &file, const std::string &filename, std::string &description, std::list<software_info> &infolist, std::ostringstream &errors) : +softlist_parser::softlist_parser( + util::core_file &file, + std::string_view filename, + std::string &listname, + std::string &description, + std::list<software_info> &infolist, + std::ostream &errors) : m_file(file), m_filename(filename), m_infolist(infolist), m_errors(errors), m_done(false), + m_listname(listname), m_description(description), m_data_accum_expected(false), m_current_info(nullptr), @@ -234,36 +308,6 @@ softlist_parser::softlist_parser(util::core_file &file, const std::string &filen //------------------------------------------------- -// line -//------------------------------------------------- - -int softlist_parser::line() const -{ - return XML_GetCurrentLineNumber(m_parser); -} - - -//------------------------------------------------- -// column -//------------------------------------------------- - -int softlist_parser::column() const -{ - return XML_GetCurrentColumnNumber(m_parser); -} - - -//------------------------------------------------- -// parser_error -//------------------------------------------------- - -const char *softlist_parser::parser_error() const -{ - return XML_ErrorString(XML_GetErrorCode(m_parser)); -} - - -//------------------------------------------------- // parse_error - append a parsing error with // filename, line and column information //------------------------------------------------- @@ -459,18 +503,21 @@ void softlist_parser::data_handler(void *data, const char *s, int len) { softlist_parser *state = reinterpret_cast<softlist_parser *>(data); - // if we have an std::string to accumulate data in, do it if (state->m_data_accum_expected) + { + // if we have an std::string to accumulate data in, do it state->m_data_accum.append(s, len); - - // otherwise, report an error if the data is non-blank + } else + { + // otherwise, report an error if the data is non-blank for (int i = 0; i < len; i++) if (!isspace(s[i])) { state->parse_error("Unexpected content"); break; } + } } @@ -486,6 +533,9 @@ void softlist_parser::parse_root_start(const char *tagname, const char **attribu static char const *const attrnames[] = { "name", "description" }; const auto attrvalues = parse_attributes(attributes, attrnames); + if (!attrvalues[0].empty()) + m_listname = attrvalues[0]; + if (!attrvalues[1].empty()) m_description = attrvalues[1]; } @@ -831,6 +881,20 @@ void softlist_parser::parse_soft_end(const char *tagname) } } +} // namespace detail + + +void parse_software_list( + util::core_file &file, + std::string_view filename, + std::string &listname, + std::string &description, + std::list<software_info> &infolist, + std::ostream &errors) +{ + detail::softlist_parser(file, filename, listname, description, infolist, errors); +} + //------------------------------------------------- // software_name_parse - helper that splits a diff --git a/src/emu/softlist.h b/src/emu/softlist.h index 5f8f7fd2fbd..67c1f9b9535 100644 --- a/src/emu/softlist.h +++ b/src/emu/softlist.h @@ -22,20 +22,28 @@ //************************************************************************** +// FORWARD DECLARATIONS +//************************************************************************** + +namespace detail { class softlist_parser; } + + +//************************************************************************** // CONSTANTS //************************************************************************** -#define SOFTWARE_SUPPORTED_YES 0 -#define SOFTWARE_SUPPORTED_PARTIAL 1 -#define SOFTWARE_SUPPORTED_NO 2 +enum class software_support +{ + SUPPORTED, + PARTIALLY_SUPPORTED, + UNSUPPORTED +}; //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// ======================> feature_list_item - // an item in a list of name/value pairs class feature_list_item { @@ -49,24 +57,20 @@ public: feature_list_item& operator=(feature_list_item &&) = delete; // getters - feature_list_item *next() const noexcept { return m_next; } const std::string &name() const noexcept { return m_name; } const std::string &value() const noexcept { return m_value; } private: // internal state - feature_list_item * m_next; std::string m_name; std::string m_value; }; -// ======================> software_part - // a single part of a software item class software_part { - friend class softlist_parser; + friend class detail::softlist_parser; public: // construction/destruction @@ -77,7 +81,6 @@ public: software_part& operator=(software_part &&) = delete; // getters - software_part *next() const noexcept { return m_next; } software_info &info() const noexcept { return m_info; } const std::string &name() const noexcept { return m_name; } const std::string &interface() const noexcept { return m_interface; } @@ -86,11 +89,10 @@ public: // helpers bool matches_interface(const char *interface_list) const noexcept; - const char *feature(const std::string &feature_name) const noexcept; + const char *feature(std::string_view feature_name) const noexcept; private: // internal state - software_part * m_next; software_info & m_info; std::string m_name; std::string m_interface; @@ -99,16 +101,14 @@ private: }; -// ======================> software_info - // a single software item class software_info { - friend class softlist_parser; + friend class detail::softlist_parser; public: // construction/destruction - software_info(std::string &&name, std::string &&parent, const std::string &supported); + software_info(std::string &&name, std::string &&parent, std::string_view supported); software_info(software_info const &) = delete; software_info(software_info &&) = delete; software_info& operator=(software_info const &) = delete; @@ -122,16 +122,16 @@ public: const std::string &publisher() const { return m_publisher; } const std::list<feature_list_item> &other_info() const { return m_other_info; } const std::list<feature_list_item> &shared_info() const { return m_shared_info; } - u32 supported() const { return m_supported; } + software_support supported() const { return m_supported; } const std::list<software_part> &parts() const { return m_partdata; } // additional operations - const software_part *find_part(const std::string &part_name, const char *interface = nullptr) const; + const software_part *find_part(std::string_view part_name, const char *interface = nullptr) const; bool has_multiple_parts(const char *interface) const; private: // internal state - u32 m_supported; + software_support m_supported; std::string m_shortname; std::string m_longname; std::string m_parentname; @@ -144,71 +144,17 @@ private: }; -// ======================> softlist_parser - -class softlist_parser -{ -public: - // construction (== execution) - softlist_parser(util::core_file &file, const std::string &filename, std::string &description, std::list<software_info> &infolist, std::ostringstream &errors); - -private: - enum parse_position - { - POS_ROOT, - POS_MAIN, - POS_SOFT, - POS_PART, - POS_DATA - }; - - // internal parsing helpers - const char *infoname() const { return (m_current_info != nullptr) ? m_current_info->shortname().c_str() : "???"; } - int line() const; - int column() const; - const char *parser_error() const; - - // internal error helpers - template <typename Format, typename... Params> void parse_error(Format &&fmt, Params &&... args); - void unknown_tag(const char *tagname) { parse_error("Unknown tag: %s", tagname); } - void unknown_attribute(const char *attrname) { parse_error("Unknown attribute: %s", attrname); } - - // internal helpers - template <typename T> std::vector<std::string> parse_attributes(const char **attributes, const T &attrlist); - bool parse_name_and_value(const char **attributes, std::string &name, std::string &value); - void add_rom_entry(std::string &&name, std::string &&hashdata, u32 offset, u32 length, u32 flags); - - // expat callbacks - static void start_handler(void *data, const char *tagname, const char **attributes); - static void data_handler(void *data, const char *s, int len); - static void end_handler(void *data, const char *name); - - // internal parsing - void parse_root_start(const char *tagname, const char **attributes); - void parse_main_start(const char *tagname, const char **attributes); - void parse_soft_start(const char *tagname, const char **attributes); - void parse_part_start(const char *tagname, const char **attributes); - void parse_data_start(const char *tagname, const char **attributes); - void parse_soft_end(const char *name); - - // internal parsing state - util::core_file & m_file; - std::string m_filename; - std::list<software_info> & m_infolist; - std::ostringstream & m_errors; - struct XML_ParserStruct * m_parser; - bool m_done; - std::string & m_description; - bool m_data_accum_expected; - std::string m_data_accum; - software_info * m_current_info; - software_part * m_current_part; - parse_position m_pos; -}; - - // ----- Helpers ----- +// parses a software list +void parse_software_list( + util::core_file &file, + std::string_view filename, + std::string &listname, + std::string &description, + std::list<software_info> &infolist, + std::ostream &errors); + // parses a software identifier (e.g. - 'apple2e:agentusa:flop1') into its constituent parts (returns false if cannot parse) bool software_name_parse(std::string_view identifier, std::string *list_name = nullptr, std::string *software_name = nullptr, std::string *part_name = nullptr); diff --git a/src/emu/softlist_dev.cpp b/src/emu/softlist_dev.cpp index 4da6c9069b0..286e6da6d4a 100644 --- a/src/emu/softlist_dev.cpp +++ b/src/emu/softlist_dev.cpp @@ -89,7 +89,6 @@ software_list_device::software_list_device(const machine_config &mconfig, const m_list_type(softlist_type::ORIGINAL_SYSTEM), m_filter(nullptr), m_parsed(false), - m_file(mconfig.options().hash_path(), OPEN_FLAG_READ), m_description("") { } @@ -176,8 +175,10 @@ void software_list_device::find_approx_matches(std::string_view name, int matche void software_list_device::release() { - osd_printf_verbose("Resetting %s\n", m_file.filename()); + osd_printf_verbose("%s: Resetting %s\n", tag(), m_list_name); m_parsed = false; + m_filename.clear(); + m_shortname.clear(); m_description.clear(); m_errors.clear(); m_infolist.clear(); @@ -286,17 +287,25 @@ void software_list_device::parse() m_errors.clear(); // attempt to open the file - const osd_file::error filerr = m_file.open(m_list_name + ".xml"); + emu_file file(mconfig().options().hash_path(), OPEN_FLAG_READ); + const osd_file::error filerr = file.open(m_list_name + ".xml"); + m_filename = file.filename(); if (filerr == osd_file::error::NONE) { // parse if no error std::ostringstream errs; - softlist_parser parser(m_file, m_file.filename(), m_description, m_infolist, errs); - m_file.close(); + parse_software_list(file, m_filename, m_shortname, m_description, m_infolist, errs); + file.close(); m_errors = errs.str(); } + else if (filerr == osd_file::error::NOT_FOUND) + { + osd_printf_verbose("%s: Software list %s not found\n", m_filename); + } else - m_errors = string_format("Error opening file: %s\n", filename()); + { + m_errors = string_format("Error opening file: %s\n", m_filename); + } // indicate that we've been parsed m_parsed = true; @@ -421,98 +430,115 @@ void software_list_device::device_validity_check(validity_checker &valid) const void software_list_device::internal_validity_check(validity_checker &valid) { - enum { NAME_LEN_PARENT = 16, NAME_LEN_CLONE = 16, NAME_LEN_PART = 16 }; + enum { NAME_LEN_LIST = 24, NAME_LEN_PARENT = 16, NAME_LEN_CLONE = 16, NAME_LEN_PART = 16 }; auto const valid_name_char = [] (char ch) { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '_'); }; auto const valid_tag_char = [] (char ch) { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || strchr("$.:_", u8(ch)); }; auto const valid_year_char = [] (char ch) { return isdigit(u8(ch)) || (ch == '?') || (ch == '+'); }; auto const valid_label_char = [] (char ch) { return (ch >= ' ') && (ch <= '~') && !strchr("!$%/:\\", u8(ch)); }; + // first parse and output core errors if any + auto const &info(get_info()); + if (!m_errors.empty()) + { + osd_printf_error("%s: Errors parsing software list:\n%s", m_filename, m_errors); + release(); + return; + } + + // ignore empty shortname to work around ignoring missing software lists + if (!m_shortname.empty()) + { + if (m_list_name != m_shortname) + osd_printf_error("%s: Software list name %s does not match filename %s\n", m_filename, m_shortname, m_list_name); + + if (m_shortname.length() > NAME_LEN_LIST) + osd_printf_error("%s: %s software list name must be %d characters or less\n", m_filename, m_shortname, NAME_LEN_LIST); + } + + // now check the software items softlist_map names; softlist_map descriptions; - for (const software_info &swinfo : get_info()) + for (const software_info &swinfo : info) { - // first parse and output core errors if any - if (m_errors.length() > 0) - { - osd_printf_error("%s: Errors parsing software list:\n%s", filename(), errors_string()); - break; - } - - // Now check if the xml data is valid: std::string const &shortname(swinfo.shortname()); if (swinfo.longname().empty()) - osd_printf_error("%s: %s has no description\n", filename(), shortname); + osd_printf_error("%s: %s has no description\n", m_filename, shortname); if (swinfo.year().empty()) - osd_printf_error("%s: %s has no year\n", filename(), shortname); + osd_printf_error("%s: %s has no year\n", m_filename, shortname); if (swinfo.publisher().empty()) - osd_printf_error("%s: %s has no publisher\n", filename(), shortname); + osd_printf_error("%s: %s has no publisher\n", m_filename, shortname); // Did we lost the software parts? if (swinfo.parts().empty()) - osd_printf_error("%s: %s has no parts\n", filename(), shortname); + osd_printf_error("%s: %s has no parts\n", m_filename, shortname); // Second, since the xml is fine, run additional checks: // check for duplicate names auto const dupname(names.emplace(shortname, &swinfo)); if (!dupname.second) - osd_printf_error("%s: %s is a duplicate name (%s)\n", filename(), shortname, dupname.first->second->shortname()); + osd_printf_error("%s: %s is a duplicate name (%s)\n", m_filename, shortname, dupname.first->second->shortname()); // check for duplicate descriptions auto const dupdesc(descriptions.emplace(swinfo.longname(), &swinfo)); if (!dupdesc.second) - osd_printf_error("%s: %s has duplicate description '%s' (%s)\n", filename(), shortname, swinfo.longname(), dupdesc.first->second->shortname()); + osd_printf_error("%s: %s has duplicate description '%s' (%s)\n", m_filename, shortname, swinfo.longname(), dupdesc.first->second->shortname()); bool const is_clone(!swinfo.parentname().empty()); if (is_clone) { if (swinfo.parentname() == shortname) { - osd_printf_error("%s: %s is set as a clone of itself\n", filename(), shortname); + osd_printf_error("%s: %s is set as a clone of itself\n", m_filename, shortname); } else { software_info const *const parent = find(swinfo.parentname()); if (!parent) - osd_printf_error("%s: %s is a clone of non-existent parent %s\n", filename(), shortname, swinfo.parentname()); + osd_printf_error("%s: %s is a clone of non-existent parent %s\n", m_filename, shortname, swinfo.parentname()); else if (!parent->parentname().empty()) - osd_printf_error("%s: %s is a clone %s which is a clone of %s\n", filename(), shortname, swinfo.parentname(), parent->parentname()); + osd_printf_error("%s: %s is a clone %s which is a clone of %s\n", m_filename, shortname, swinfo.parentname(), parent->parentname()); } } // make sure the driver name isn't too long if (shortname.length() > (is_clone ? NAME_LEN_CLONE : NAME_LEN_PARENT)) - osd_printf_error("%s: %s %s software name must be %d characters or less\n", filename(), shortname, + { + osd_printf_error( + "%s: %s %s software name must be %d characters or less\n", + m_filename, + shortname, is_clone ? "clone" : "parent", is_clone ? NAME_LEN_CLONE : NAME_LEN_PARENT); + } // make sure the driver name doesn't contain invalid characters if (std::find_if_not(shortname.begin(), shortname.end(), valid_name_char) != shortname.end()) - osd_printf_error("%s: %s contains invalid characters\n", filename(), shortname); + osd_printf_error("%s: %s contains invalid characters\n", m_filename, shortname); // make sure the year is only digits, '?' or '+' if (std::find_if_not(swinfo.year().begin(), swinfo.year().end(), valid_year_char) != swinfo.year().end()) - osd_printf_error("%s: %s has an invalid year '%s'\n", filename(), shortname, swinfo.year()); + osd_printf_error("%s: %s has an invalid year '%s'\n", m_filename, shortname, swinfo.year()); std::set<std::string> part_names; for (software_part const &part : swinfo.parts()) { if (part.interface().empty()) - osd_printf_error("%s: %s part %s has no interface\n", filename(), shortname, part.name()); + osd_printf_error("%s: %s part %s has no interface\n", m_filename, shortname, part.name()); if (part.romdata().empty()) - osd_printf_error("%s: %s part %s has no data areas\n", filename(), shortname, part.name()); + osd_printf_error("%s: %s part %s has no data areas\n", m_filename, shortname, part.name()); if (!part_names.emplace(part.name()).second) - osd_printf_error("%s: %s part %s has duplicate name\n", filename(), shortname, part.name()); + osd_printf_error("%s: %s part %s has duplicate name\n", m_filename, shortname, part.name()); if (part.name().length() > NAME_LEN_PART) - osd_printf_error("%s: %s part %s name must be %d characters or less\n", filename(), shortname, part.name(), NAME_LEN_PART); + osd_printf_error("%s: %s part %s name must be %d characters or less\n", m_filename, shortname, part.name(), NAME_LEN_PART); if (std::find_if_not(part.name().begin(), part.name().end(), valid_name_char) != part.name().end()) - osd_printf_error("%s: %s part %s contains invalid characters\n", filename(), shortname, part.name()); + osd_printf_error("%s: %s part %s contains invalid characters\n", m_filename, shortname, part.name()); // validate data areas // based on ROM validation code from validity.cpp but adapted to work with rom_entry and ignore unavailable features like BIOS @@ -529,7 +555,7 @@ void software_list_device::internal_validity_check(validity_checker &valid) { // if we haven't seen any items since the last region, print a warning if (!items_since_region) - osd_printf_verbose("%s: %s part %s has empty data area '%s' (warning)\n", filename(), shortname, part.name(), last_region_name); + osd_printf_verbose("%s: %s part %s has empty data area '%s' (warning)\n", m_filename, shortname, part.name(), last_region_name); // reset our region tracking states items_since_region = (ROMREGION_ISERASE(romp) || ROMREGION_ISDISKDATA(romp)) ? 1 : 0; @@ -537,31 +563,31 @@ void software_list_device::internal_validity_check(validity_checker &valid) // check for a valid tag if (romp->name().size() < MIN_TAG_LENGTH) - osd_printf_error("%s: %s part %s data area name '%s' is too short (mut be at least %d characters)\n", filename(), shortname, part.name(), romp->name(), MIN_TAG_LENGTH); + osd_printf_error("%s: %s part %s data area name '%s' is too short (mut be at least %d characters)\n", m_filename, shortname, part.name(), romp->name(), MIN_TAG_LENGTH); if (std::find_if_not(romp->name().begin(), romp->name().end(), valid_tag_char) != romp->name().end()) - osd_printf_error("%s: %s part %s data area name '%s' contains invalid characters\n", filename(), shortname, part.name(), romp->name()); + osd_printf_error("%s: %s part %s data area name '%s' contains invalid characters\n", m_filename, shortname, part.name(), romp->name()); // attempt to add it to the map, reporting duplicates as errors current_length = ROMREGION_GETLENGTH(romp); if (!data_area_map.emplace(romp->name(), current_length).second) - osd_printf_error("%s: %s part %s data area has duplicate name '%s'\n", filename(), shortname, part.name(), romp->name()); + osd_printf_error("%s: %s part %s data area has duplicate name '%s'\n", m_filename, shortname, part.name(), romp->name()); } else if (ROMENTRY_ISFILE(romp)) // if this is a file, make sure it is properly formatted { - // track the last filename we found + // track the last ROM label we found last_name = romp->name().c_str(); // validate the name if (romp->name().length() > 127) - osd_printf_error("%s: %s part %s ROM label '%s' exceeds maximum 127 characters\n", filename(), shortname, part.name(), romp->name()); + osd_printf_error("%s: %s part %s ROM label '%s' exceeds maximum 127 characters\n", m_filename, shortname, part.name(), romp->name()); if (std::find_if_not(romp->name().begin(), romp->name().end(), valid_label_char) != romp->name().end()) - osd_printf_error("%s: %s part %s ROM label '%s' contains invalid characters\n", filename(), shortname, part.name(), romp->name()); + osd_printf_error("%s: %s part %s ROM label '%s' contains invalid characters\n", m_filename, shortname, part.name(), romp->name()); // make sure the hash is valid util::hash_collection hashes; if (!hashes.from_internal_string(romp->hashdata())) - osd_printf_error("%s: %s part %s ROM '%s' has invalid hash string '%s'\n", filename(), shortname, part.name(), romp->name(), romp->hashdata()); + osd_printf_error("%s: %s part %s ROM '%s' has invalid hash string '%s'\n", m_filename, shortname, part.name(), romp->name(), romp->hashdata()); } // for any non-region ending entries, make sure they don't extend past the end @@ -569,17 +595,17 @@ void software_list_device::internal_validity_check(validity_checker &valid) { items_since_region++; if (!ROMENTRY_ISIGNORE(romp) && (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > current_length)) - osd_printf_error("%s: %s part %s ROM '%s' extends past the defined data area\n", filename(), shortname, part.name(), last_name); + osd_printf_error("%s: %s part %s ROM '%s' extends past the defined data area\n", m_filename, shortname, part.name(), last_name); } } // if we haven't seen any items since the last region, print a warning if (!items_since_region) - osd_printf_verbose("%s: %s part %s has empty data area '%s' (warning)\n", filename(), shortname, part.name(), last_region_name); + osd_printf_verbose("%s: %s part %s has empty data area '%s' (warning)\n", m_filename, shortname, part.name(), last_region_name); } } } - // release all the memory + // discard parsed info release(); } diff --git a/src/emu/softlist_dev.h b/src/emu/softlist_dev.h index 598ea413b4f..b0e774b9519 100644 --- a/src/emu/softlist_dev.h +++ b/src/emu/softlist_dev.h @@ -115,7 +115,6 @@ public: bool is_original() const { return softlist_type::ORIGINAL_SYSTEM == m_list_type; } bool is_compatible() const { return softlist_type::COMPATIBLE_SYSTEM == m_list_type; } const char *filter() const { return m_filter; } - const char *filename() { return m_file.filename(); } // getters that may trigger a parse const std::string &description() { if (!m_parsed) parse(); return m_description; } @@ -152,7 +151,8 @@ private: // internal state bool m_parsed; - emu_file m_file; + std::string m_filename; + std::string m_shortname; std::string m_description; std::string m_errors; std::list<software_info> m_infolist; |