summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/softlist.cpp
diff options
context:
space:
mode:
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
commitc9a62818e9135c5b757cfbaa940c83ca5371e275 (patch)
tree2308021b4c003b9f6abe29efbb00aabe67909e01 /src/emu/softlist.cpp
parent12959e6e97a229c91757dff52f5153ca49cc7ced (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.cpp152
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