mirror of
https://github.com/holub/mame
synced 2025-04-18 22:49:58 +03:00
-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.
This commit is contained in:
parent
12959e6e97
commit
c9a62818e9
@ -2,7 +2,7 @@
|
||||
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
|
||||
<!-- license:CC0 -->
|
||||
|
||||
<softwarelist name="leapfrog_leapster_explorer_cart" description="LeapFrog Leapster Explorer Cartridges">
|
||||
<softwarelist name="leapster_explorer_cart" description="LeapFrog Leapster Explorer Cartridges">
|
||||
|
||||
<software name="tblt" supported="no">
|
||||
<description>TinkerBell and the Lost Treasure (USA)</description>
|
@ -3,7 +3,7 @@
|
||||
<!--
|
||||
license:CC0
|
||||
-->
|
||||
<softwarelist name="leapfrog_turbotwistbrainquest_cart" description="LeapFrog Turbo Twist Brain Quest cartridges">
|
||||
<softwarelist name="ttwist_brainquest_cart" description="LeapFrog Turbo Twist Brain Quest cartridges">
|
||||
<!-- also compatible with Fact Blaster -->
|
||||
|
||||
<software name="grades5_6" supported="no">
|
@ -3,7 +3,7 @@
|
||||
<!--
|
||||
license:CC0
|
||||
-->
|
||||
<softwarelist name="leapfrog_turboextreme_cart" description="LeapFrog Turbo Extreme cartridges">
|
||||
<softwarelist name="turboextreme_cart" description="LeapFrog Turbo Extreme cartridges">
|
||||
|
||||
<software name="grade2" supported="no">
|
||||
<description>Grade 2 (500-10652)</description>
|
@ -8,7 +8,7 @@ license:CC0
|
||||
|
||||
<!-- Grey coloured 'pack-in' cartridge contains no ROM, only 2 pins bridged -->
|
||||
|
||||
<softwarelist name="vtech_innotv_innotabmax_cart" description="VTech InnoTV / InnoTAB MAX cartridges">
|
||||
<softwarelist name="vtech_innotv_cart" description="VTech InnoTV / InnoTAB MAX cartridges">
|
||||
|
||||
<software name="pawpatrl" supported="no">
|
||||
<description>Paw Patrol - Pups Save a UFO! (80-274103 UK)</description>
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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),
|
||||
@ -233,36 +307,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
|
||||
|
@ -21,21 +21,29 @@
|
||||
#include <list>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// 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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1090,9 +1090,9 @@ void cli_frontend::output_single_softlist(std::ostream &out, software_list_devic
|
||||
util::stream_format(out, "\t\t<software name=\"%s\"", util::xml::normalize_string(swinfo.shortname().c_str()));
|
||||
if (!swinfo.parentname().empty())
|
||||
util::stream_format(out, " cloneof=\"%s\"", util::xml::normalize_string(swinfo.parentname().c_str()));
|
||||
if (swinfo.supported() == SOFTWARE_SUPPORTED_PARTIAL)
|
||||
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()));
|
||||
|
@ -576,13 +576,13 @@ void menu_image_info::image_info(device_image_interface *image)
|
||||
// display supported information, if available
|
||||
switch (swinfo.supported())
|
||||
{
|
||||
case SOFTWARE_SUPPORTED_NO:
|
||||
case software_support::UNSUPPORTED:
|
||||
item_append(_("Not supported"), FLAG_DISABLE, nullptr);
|
||||
break;
|
||||
case SOFTWARE_SUPPORTED_PARTIAL:
|
||||
case software_support::PARTIALLY_SUPPORTED:
|
||||
item_append(_("Partially supported"), FLAG_DISABLE, nullptr);
|
||||
break;
|
||||
default:
|
||||
case software_support::SUPPORTED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ favorite_manager::favorite_manager(ui_options &options)
|
||||
file.gets(readbuf, 1024);
|
||||
tmpmatches.publisher = chartrimcarriage(readbuf);
|
||||
file.gets(readbuf, 1024);
|
||||
tmpmatches.supported = atoi(readbuf);
|
||||
tmpmatches.supported = software_support(atoi(readbuf));
|
||||
file.gets(readbuf, 1024);
|
||||
tmpmatches.part = chartrimcarriage(readbuf);
|
||||
file.gets(readbuf, 1024);
|
||||
@ -559,7 +559,7 @@ void favorite_manager::save_favorites()
|
||||
buf << info.parentname << '\n';
|
||||
buf << info.year << '\n';
|
||||
buf << info.publisher << '\n';
|
||||
util::stream_format(buf, "%d\n", info.supported);
|
||||
util::stream_format(buf, "%d\n", int(info.supported));
|
||||
buf << info.part << '\n';
|
||||
util::stream_format(buf, "%s\n", info.driver->name);
|
||||
buf << info.listname << '\n';
|
||||
|
@ -683,12 +683,12 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
|
||||
tempbuf[2] = _("Software is parent");
|
||||
|
||||
// next line is supported status
|
||||
if (swinfo->supported == SOFTWARE_SUPPORTED_NO)
|
||||
if (swinfo->supported == software_support::UNSUPPORTED)
|
||||
{
|
||||
tempbuf[3] = _("Supported: No");
|
||||
color = UI_RED_COLOR;
|
||||
}
|
||||
else if (swinfo->supported == SOFTWARE_SUPPORTED_PARTIAL)
|
||||
else if (swinfo->supported == software_support::PARTIALLY_SUPPORTED)
|
||||
{
|
||||
tempbuf[3] = _("Supported: Partial");
|
||||
color = UI_YELLOW_COLOR;
|
||||
@ -700,7 +700,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
|
||||
}
|
||||
|
||||
// last line is romset name
|
||||
tempbuf[4] = string_format(_("romset: %1$-.100s"), swinfo->shortname);
|
||||
tempbuf[4] = string_format(_("Software list/item: %1$s:%2$s"), swinfo->listname, swinfo->shortname);
|
||||
}
|
||||
else if (driver)
|
||||
{
|
||||
|
@ -250,20 +250,8 @@ void menu_select_software::populate(float &customtop, float &custombottom)
|
||||
icon.second.texture.reset();
|
||||
|
||||
uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW;
|
||||
m_has_empty_start = true;
|
||||
int old_software = -1;
|
||||
|
||||
// FIXME: why does it do this relatively expensive operation every time?
|
||||
machine_config config(m_driver, machine().options());
|
||||
for (device_image_interface &image : image_interface_enumerator(config.root_device()))
|
||||
{
|
||||
if (!image.filename() && image.must_be_loaded())
|
||||
{
|
||||
m_has_empty_start = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// start with an empty list
|
||||
m_displaylist.clear();
|
||||
filter_map::const_iterator const flt(m_filters.find(m_filter_type));
|
||||
@ -341,6 +329,17 @@ void menu_select_software::build_software_list()
|
||||
|
||||
machine_config config(m_driver, machine().options());
|
||||
|
||||
// see if any media devices require an image to be loaded
|
||||
m_has_empty_start = true;
|
||||
for (device_image_interface &image : image_interface_enumerator(config.root_device()))
|
||||
{
|
||||
if (!image.filename() && image.must_be_loaded())
|
||||
{
|
||||
m_has_empty_start = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through all software lists
|
||||
std::vector<std::size_t> orphans;
|
||||
struct orphan_less
|
||||
@ -425,7 +424,7 @@ void menu_select_software::build_software_list()
|
||||
}
|
||||
|
||||
std::string searchstr, curpath;
|
||||
for (auto & elem : m_filter_data.list_names())
|
||||
for (auto &elem : m_filter_data.list_names())
|
||||
{
|
||||
path_iterator path(machine().options().media_path());
|
||||
while (path.next(curpath))
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "drivenum.h"
|
||||
#include "rendfont.h"
|
||||
#include "romload.h"
|
||||
#include "softlist.h"
|
||||
|
||||
#include "corestr.h"
|
||||
|
||||
@ -1319,7 +1318,7 @@ class supported_software_filter : public simple_filter_impl_base<software_filter
|
||||
public:
|
||||
supported_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
|
||||
|
||||
virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_YES == info.supported; }
|
||||
virtual bool apply(ui_software_info const &info) const override { return software_support::SUPPORTED == info.supported; }
|
||||
};
|
||||
|
||||
|
||||
@ -1329,7 +1328,7 @@ class partial_supported_software_filter : public simple_filter_impl_base<softwar
|
||||
public:
|
||||
partial_supported_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
|
||||
|
||||
virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_PARTIAL == info.supported; }
|
||||
virtual bool apply(ui_software_info const &info) const override { return software_support::PARTIALLY_SUPPORTED == info.supported; }
|
||||
};
|
||||
|
||||
|
||||
@ -1338,7 +1337,7 @@ class unsupported_software_filter : public simple_filter_impl_base<software_filt
|
||||
public:
|
||||
unsupported_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
|
||||
|
||||
virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_NO == info.supported; }
|
||||
virtual bool apply(ui_software_info const &info) const override { return software_support::UNSUPPORTED == info.supported; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "softlist.h"
|
||||
#include "unicode.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
@ -19,8 +22,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
class mame_ui_manager;
|
||||
class render_container;
|
||||
@ -79,7 +80,7 @@ struct ui_software_info
|
||||
std::string parentname;
|
||||
std::string year;
|
||||
std::string publisher;
|
||||
uint8_t supported = 0;
|
||||
software_support supported = software_support::SUPPORTED;
|
||||
std::string part;
|
||||
game_driver const *driver = nullptr;
|
||||
std::string listname;
|
||||
|
@ -44,6 +44,9 @@
|
||||
#define CONTROL1_TAG "joy1"
|
||||
#define CONTROL2_TAG "joy2"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class c128_state : public driver_device
|
||||
{
|
||||
public:
|
||||
@ -218,6 +221,7 @@ public:
|
||||
|
||||
int m_user_pa2;
|
||||
int m_user_pb;
|
||||
void softlists(machine_config &config, const char *filter);
|
||||
void pal(machine_config &config);
|
||||
void ntsc(machine_config &config);
|
||||
void c128pal(machine_config &config);
|
||||
@ -1537,7 +1541,7 @@ WRITE_LINE_MEMBER( c128_state::exp_reset_w )
|
||||
// SLOT_INTERFACE( c128dcr_iec_devices )
|
||||
//-------------------------------------------------
|
||||
|
||||
void c128dcr_iec_devices(device_slot_interface &device)
|
||||
[[maybe_unused]] void c128dcr_iec_devices(device_slot_interface &device)
|
||||
{
|
||||
device.option_add("c1571", C1571);
|
||||
device.option_add("c1571cr", C1571CR);
|
||||
@ -1619,6 +1623,23 @@ void c128_state::machine_reset()
|
||||
// MACHINE DRIVERS
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_config( softlists )
|
||||
//-------------------------------------------------
|
||||
|
||||
void c128_state::softlists(machine_config &config, const char *filter)
|
||||
{
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("c128_cart").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "flop_list").set_original("c128_flop").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "from_list").set_original("c128_rom").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "cart_list_c64").set_original("c64_cart").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "cass_list_c64").set_original("c64_cass").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "cart_list_vic10").set_original("vic10").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "flop_list_c64_orig").set_compatible("c64_flop_orig").set_filter(filter);
|
||||
SOFTWARE_LIST(config, "flop_list_c64_misc").set_compatible("c64_flop_misc").set_filter(filter);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_config( ntsc )
|
||||
//-------------------------------------------------
|
||||
@ -1746,16 +1767,8 @@ void c128_state::ntsc(machine_config &config)
|
||||
|
||||
QUICKLOAD(config, "quickload", "p00,prg", CBM_QUICKLOAD_DELAY).set_load_callback(FUNC(c128_state::quickload_c128));
|
||||
|
||||
// software list
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("c128_cart").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "flop_list").set_original("c128_flop").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "from_list").set_original("c128_rom").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "cart_list_c64").set_original("c64_cart").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "cass_list_c64").set_original("c64_cass").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "cart_list_vic10").set_original("vic10").set_filter("NTSC");
|
||||
// disk softlist split into originals and misc (homebrew and cracks)
|
||||
SOFTWARE_LIST(config, "flop525_orig").set_original("c64_flop_orig").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "flop525_misc").set_compatible("c64_flop_misc").set_filter("NTSC");
|
||||
// software lists
|
||||
softlists(config, "NTSC");
|
||||
|
||||
// function ROM
|
||||
GENERIC_SOCKET(config, "from", generic_plain_slot, "c128_rom", "bin,rom");
|
||||
@ -1934,20 +1947,7 @@ void c128_state::pal(machine_config &config)
|
||||
QUICKLOAD(config, "quickload", "p00,prg", CBM_QUICKLOAD_DELAY).set_load_callback(FUNC(c128_state::quickload_c128));
|
||||
|
||||
// software list
|
||||
SOFTWARE_LIST(config, "cart_list_vic10").set_original("vic10");
|
||||
SOFTWARE_LIST(config, "cart_list_c64").set_original("c64_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("c128_cart");
|
||||
SOFTWARE_LIST(config, "cass_list_c64").set_original("c64_cass");
|
||||
SOFTWARE_LIST(config, "flop_list_c64").set_original("c64_flop");
|
||||
SOFTWARE_LIST(config, "flop_list").set_original("c128_flop");
|
||||
SOFTWARE_LIST(config, "from_list").set_original("c128_rom");
|
||||
subdevice<software_list_device>("cart_list_vic10")->set_filter("PAL");
|
||||
subdevice<software_list_device>("cart_list_c64")->set_filter("PAL");
|
||||
subdevice<software_list_device>("cart_list")->set_filter("PAL");
|
||||
subdevice<software_list_device>("cass_list_c64")->set_filter("PAL");
|
||||
subdevice<software_list_device>("flop_list_c64")->set_filter("PAL");
|
||||
subdevice<software_list_device>("flop_list")->set_filter("PAL");
|
||||
subdevice<software_list_device>("from_list")->set_filter("PAL");
|
||||
softlists(config, "PAL");
|
||||
|
||||
// function ROM
|
||||
GENERIC_SOCKET(config, "from", generic_plain_slot, "c128_rom", "bin,rom");
|
||||
@ -2158,6 +2158,8 @@ ROM_START( c128dcr_se )
|
||||
ROM_LOAD( "8721r3.u11", 0x000, 0xc88, BAD_DUMP CRC(154db186) SHA1(ccadcdb1db3b62c51dc4ce60fe6f96831586d297) )
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
|
@ -1562,7 +1562,7 @@ void c64_state::ntsc(machine_config &config)
|
||||
SOFTWARE_LIST(config, "cass_list").set_original("c64_cass").set_filter("NTSC");
|
||||
// disk softlist split into originals and misc (homebrew and cracks)
|
||||
SOFTWARE_LIST(config, "flop525_orig").set_original("c64_flop_orig").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "flop525_misc").set_compatible("c64_flop_misc").set_filter("NTSC");
|
||||
SOFTWARE_LIST(config, "flop525_misc").set_original("c64_flop_misc").set_filter("NTSC");
|
||||
|
||||
// internal ram
|
||||
RAM(config, RAM_TAG).set_default_size("64K");
|
||||
@ -1735,7 +1735,7 @@ void c64_state::pal(machine_config &config)
|
||||
SOFTWARE_LIST(config, "cass_list").set_original("c64_cass").set_filter("PAL");
|
||||
// disk softlist split into originals and misc (homebrew and cracks)
|
||||
SOFTWARE_LIST(config, "flop525_orig").set_original("c64_flop_orig").set_filter("PAL");
|
||||
SOFTWARE_LIST(config, "flop525_misc").set_compatible("c64_flop_misc").set_filter("PAL");
|
||||
SOFTWARE_LIST(config, "flop525_misc").set_original("c64_flop_misc").set_filter("PAL");
|
||||
|
||||
// internal ram
|
||||
RAM(config, RAM_TAG).set_default_size("64K");
|
||||
|
@ -152,7 +152,7 @@ void vtech_innotv_innotabmax_state::vtech_innotv_innotabmax(machine_config &conf
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(vtech_innotv_innotabmax_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("vtech_innotv_innotabmax_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("vtech_innotv_cart");
|
||||
}
|
||||
|
||||
ROM_START( innotv )
|
||||
|
@ -651,7 +651,7 @@ void leapfrog_turboextreme_state::leapfrog_turboex(machine_config &config)
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_turboextreme_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_turboextreme_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("turboextreme_cart");
|
||||
}
|
||||
|
||||
void leapfrog_turbotwistmath_state::leapfrog_turbotwistmath(machine_config &config)
|
||||
@ -670,7 +670,7 @@ void leapfrog_turbotwistmath_state::leapfrog_turbotwistmath(machine_config &conf
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_turbotwistmath_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_turbotwistmath_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ttwist_math_cart");
|
||||
}
|
||||
|
||||
void leapfrog_turbotwistspelling_state::leapfrog_turbotwistspelling(machine_config &config)
|
||||
@ -689,7 +689,7 @@ void leapfrog_turbotwistspelling_state::leapfrog_turbotwistspelling(machine_conf
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_turbotwistspelling_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_turbotwistspelling_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ttwist_spelling_cart");
|
||||
}
|
||||
|
||||
void leapfrog_turbotwistvocabulator_state::leapfrog_turbotwistvocabulator(machine_config &config)
|
||||
@ -708,7 +708,7 @@ void leapfrog_turbotwistvocabulator_state::leapfrog_turbotwistvocabulator(machin
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_turbotwistvocabulator_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_turbotwistvocabulator_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ttwist_vocabulator_cart");
|
||||
}
|
||||
|
||||
|
||||
@ -728,7 +728,7 @@ void leapfrog_turbotwistbrainquest_state::leapfrog_turbotwistbrainquest(machine_
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_turbotwistbrainquest_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_turbotwistbrainquest_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ttwist_brainquest_cart");
|
||||
}
|
||||
|
||||
ROM_START( iquest )
|
||||
|
@ -96,7 +96,7 @@ void leapfrog_leapster_explorer_state::leapfrog_leapster_explorer(machine_config
|
||||
m_cart->set_width(GENERIC_ROM16_WIDTH);
|
||||
m_cart->set_device_load(FUNC(leapfrog_leapster_explorer_state::cart_load));
|
||||
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapfrog_leapster_explorer_cart");
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("leapster_explorer_cart");
|
||||
}
|
||||
|
||||
ROM_START( leapexpr )
|
||||
|
Loading…
Reference in New Issue
Block a user