summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
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
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')
-rw-r--r--src/emu/diimage.cpp5
-rw-r--r--src/emu/ioport.cpp24
-rw-r--r--src/emu/romload.cpp5
-rw-r--r--src/emu/softlist.cpp152
-rw-r--r--src/emu/softlist.h112
-rw-r--r--src/emu/softlist_dev.cpp114
-rw-r--r--src/emu/softlist_dev.h4
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;