diff options
author | 2021-06-23 16:08:59 +1000 | |
---|---|---|
committer | 2021-06-23 16:08:59 +1000 | |
commit | c9a62818e9135c5b757cfbaa940c83ca5371e275 (patch) | |
tree | 2308021b4c003b9f6abe29efbb00aabe67909e01 /src/emu/softlist.cpp | |
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/softlist.cpp')
-rw-r--r-- | src/emu/softlist.cpp | 152 |
1 files changed, 108 insertions, 44 deletions
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 |