mirror of
https://github.com/holub/mame
synced 2025-04-26 18:23:08 +03:00
Refactored info_xml_creator::output()
- The two variations of output() no longer duplicate logic - No longer relying on driver_enumerator::config() to create machine_config objects. Because driver_enumerator would cache all objects created, we would needlessly hog memory
This commit is contained in:
parent
78ca6157e4
commit
fc9e5602b6
@ -2,7 +2,7 @@
|
|||||||
// copyright-holders:Aaron Giles,Paul Priest
|
// copyright-holders:Aaron Giles,Paul Priest
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
||||||
info.c
|
info.cpp
|
||||||
|
|
||||||
Dumps the MAME internal data as an XML file.
|
Dumps the MAME internal data as an XML file.
|
||||||
|
|
||||||
@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
#define XML_ROOT "mame"
|
#define XML_ROOT "mame"
|
||||||
@ -214,124 +213,141 @@ info_xml_creator::info_xml_creator(emu_options const &options, bool dtd)
|
|||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// output_mame_xml - print the XML information
|
// output - print the XML information for all
|
||||||
// for all known games
|
// known machines matching a pattern
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void info_xml_creator::output(FILE *out, std::vector<std::string> const &patterns)
|
void info_xml_creator::output(FILE *out, const std::vector<std::string> &patterns)
|
||||||
{
|
|
||||||
m_output = out;
|
|
||||||
|
|
||||||
std::unique_ptr<device_type_set> devfilter(patterns.empty() ? nullptr : new device_type_set);
|
|
||||||
|
|
||||||
// track which patterns match machines
|
|
||||||
driver_enumerator drivlist(m_lookup_options);
|
|
||||||
std::vector<bool> matched(patterns.size(), false);
|
|
||||||
size_t exact_matches = 0;
|
|
||||||
auto const included = [&patterns, &matched, &exact_matches] (char const *const name) -> bool
|
|
||||||
{
|
{
|
||||||
if (patterns.empty())
|
if (patterns.empty())
|
||||||
|
{
|
||||||
|
// no patterns specified - show everything
|
||||||
|
auto filter = [](const char *, bool &) -> bool
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
};
|
||||||
|
output(out, filter, devices_disposition::ALL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// patterns specified - we have to filter output
|
||||||
|
std::vector<bool> matched(patterns.size(), false);
|
||||||
|
size_t exact_matches = 0;
|
||||||
|
const auto filter = [&patterns, &matched, &exact_matches](const char *shortname, bool &done) -> bool
|
||||||
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
auto it = matched.begin();
|
auto it = matched.begin();
|
||||||
for (std::string const &pat : patterns)
|
for (const std::string &pat : patterns)
|
||||||
{
|
{
|
||||||
if (!core_strwildcmp(pat.c_str(), name))
|
if (!core_strwildcmp(pat.c_str(), shortname))
|
||||||
{
|
{
|
||||||
|
// this driver matches the pattern - tell the caller
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
|
// did we see this particular pattern before? if not, track that we have
|
||||||
if (!*it)
|
if (!*it)
|
||||||
{
|
{
|
||||||
*it = true;
|
*it = true;
|
||||||
if (!core_iswildstr(pat.c_str()))
|
if (!core_iswildstr(pat.c_str()))
|
||||||
++exact_matches;
|
{
|
||||||
|
exact_matches++;
|
||||||
|
|
||||||
|
// stop looking if we found everything specified
|
||||||
|
if (exact_matches == patterns.size())
|
||||||
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++it;
|
}
|
||||||
|
it++;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
output(out, filter, devices_disposition::FILTERED);
|
||||||
|
|
||||||
// iterate through the drivers, outputting one at a time
|
// throw an error if there were unmatched patterns
|
||||||
bool first = true;
|
auto iter = std::find(matched.begin(), matched.end(), false);
|
||||||
while (drivlist.next())
|
if (iter != matched.end())
|
||||||
{
|
{
|
||||||
if (included(drivlist.driver().name))
|
int index = iter - matched.begin();
|
||||||
|
throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching machines found for '%s'", patterns[index].c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// output - print the XML information for all
|
||||||
|
// known (and filtered) machines
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void info_xml_creator::output(FILE *out, const std::function<bool(const char *shortname, bool &done)> &filter, devices_disposition devdisp)
|
||||||
{
|
{
|
||||||
if (first)
|
// sanity checks
|
||||||
|
assert(out);
|
||||||
|
assert(filter);
|
||||||
|
|
||||||
|
// set up output
|
||||||
|
m_output = out;
|
||||||
|
|
||||||
|
// prepare a driver enumerator and the queue
|
||||||
|
driver_enumerator drivlist(m_lookup_options);
|
||||||
|
bool drivlist_done = false;
|
||||||
|
bool filter_done = false;
|
||||||
|
bool header_outputted = false;
|
||||||
|
|
||||||
|
// only keep a device set when we're asked to track it
|
||||||
|
std::unique_ptr<device_type_set> devfilter;
|
||||||
|
if (devdisp == devices_disposition::FILTERED)
|
||||||
|
devfilter = std::make_unique<device_type_set>();
|
||||||
|
|
||||||
|
// try enumerating drivers and outputting them
|
||||||
|
while (!drivlist_done && !filter_done)
|
||||||
|
{
|
||||||
|
if (!drivlist.next())
|
||||||
|
{
|
||||||
|
// at this point we are done enumerating through drivlist and it is no
|
||||||
|
// longer safe to call next(), so record that we're done
|
||||||
|
drivlist_done = true;
|
||||||
|
}
|
||||||
|
else if (filter(drivlist.driver().name, filter_done))
|
||||||
|
{
|
||||||
|
// output the header if we have to
|
||||||
|
if (!header_outputted)
|
||||||
{
|
{
|
||||||
output_header();
|
output_header();
|
||||||
first = false;
|
header_outputted = true;
|
||||||
}
|
}
|
||||||
output_one(drivlist, devfilter.get());
|
|
||||||
|
|
||||||
// stop looking if we found everything specified
|
// output it
|
||||||
if (!patterns.empty() && exact_matches == patterns.size())
|
output_one(drivlist, devfilter.get());
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through the device types if not everything matches a driver
|
// iterate through the device types if not everything matches a driver
|
||||||
if (!patterns.empty() && exact_matches != patterns.size())
|
if (devfilter && !filter_done)
|
||||||
{
|
{
|
||||||
for (device_type type : registered_device_types)
|
for (device_type type : registered_device_types)
|
||||||
{
|
{
|
||||||
if (included(type.shortname()))
|
if (filter(type.shortname(), filter_done))
|
||||||
{
|
|
||||||
devfilter->insert(&type);
|
devfilter->insert(&type);
|
||||||
if (exact_matches == patterns.size())
|
|
||||||
|
if (filter_done)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// output devices (both devices with roms and slot devices)
|
// output devices (both devices with roms and slot devices)
|
||||||
if (!devfilter || !devfilter->empty())
|
if (devdisp != devices_disposition::NONE && (!devfilter || !devfilter->empty()))
|
||||||
{
|
{
|
||||||
if (first)
|
if (!header_outputted)
|
||||||
{
|
{
|
||||||
output_header();
|
output_header();
|
||||||
first = false;
|
header_outputted = true;
|
||||||
}
|
}
|
||||||
output_devices(devfilter.get());
|
output_devices(devfilter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!first)
|
if (header_outputted)
|
||||||
output_footer();
|
|
||||||
|
|
||||||
// throw an error if there were unmatched patterns
|
|
||||||
auto it = matched.begin();
|
|
||||||
for (std::string const &pat : patterns)
|
|
||||||
{
|
|
||||||
if (!*it)
|
|
||||||
throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching machines found for '%s'", pat.c_str());
|
|
||||||
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// output_mame_xml - print the XML information
|
|
||||||
// for a subset of games
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
void info_xml_creator::output(FILE *out, driver_enumerator &drivlist, bool nodevices)
|
|
||||||
{
|
|
||||||
m_output = out;
|
|
||||||
|
|
||||||
device_type_set devfilter;
|
|
||||||
|
|
||||||
output_header();
|
|
||||||
|
|
||||||
// iterate through the drivers, outputting one at a time
|
|
||||||
while (drivlist.next())
|
|
||||||
output_one(drivlist, &devfilter);
|
|
||||||
|
|
||||||
// output devices (both devices with roms and slot devices)
|
|
||||||
if (!nodevices)
|
|
||||||
output_devices(&devfilter);
|
|
||||||
|
|
||||||
output_footer();
|
output_footer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,14 +397,14 @@ void info_xml_creator::output_footer()
|
|||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// output_one - print the XML information
|
// output_one - print the XML information
|
||||||
// for one particular game driver
|
// for one particular machine driver
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *devtypes)
|
void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *devtypes)
|
||||||
{
|
{
|
||||||
const game_driver &driver = drivlist.driver();
|
const game_driver &driver = drivlist.driver();
|
||||||
std::shared_ptr<machine_config> const config(drivlist.config());
|
machine_config config(driver, drivlist.options());
|
||||||
device_iterator iter(config->root_device());
|
device_iterator iter(config.root_device());
|
||||||
|
|
||||||
// allocate input ports and build overall emulation status
|
// allocate input ports and build overall emulation status
|
||||||
ioport_list portlist;
|
ioport_list portlist;
|
||||||
@ -458,7 +474,7 @@ void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *
|
|||||||
fprintf(m_output, " romof=\"%s\"", util::xml::normalize_string(drivlist.driver(clone_of).name));
|
fprintf(m_output, " romof=\"%s\"", util::xml::normalize_string(drivlist.driver(clone_of).name));
|
||||||
|
|
||||||
// display sample information and close the game tag
|
// display sample information and close the game tag
|
||||||
output_sampleof(config->root_device());
|
output_sampleof(config.root_device());
|
||||||
fprintf(m_output, ">\n");
|
fprintf(m_output, ">\n");
|
||||||
|
|
||||||
// output game description
|
// output game description
|
||||||
@ -474,13 +490,13 @@ void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *
|
|||||||
fprintf(m_output, "\t\t<manufacturer>%s</manufacturer>\n", util::xml::normalize_string(driver.manufacturer));
|
fprintf(m_output, "\t\t<manufacturer>%s</manufacturer>\n", util::xml::normalize_string(driver.manufacturer));
|
||||||
|
|
||||||
// now print various additional information
|
// now print various additional information
|
||||||
output_bios(config->root_device());
|
output_bios(config.root_device());
|
||||||
output_rom(&drivlist, config->root_device());
|
output_rom(&drivlist, &driver, config.root_device());
|
||||||
output_device_refs(config->root_device());
|
output_device_refs(config.root_device());
|
||||||
output_sample(config->root_device());
|
output_sample(config.root_device());
|
||||||
output_chips(config->root_device(), "");
|
output_chips(config.root_device(), "");
|
||||||
output_display(config->root_device(), &drivlist.driver().flags, "");
|
output_display(config.root_device(), &driver.flags, "");
|
||||||
output_sound(config->root_device());
|
output_sound(config.root_device());
|
||||||
output_input(portlist);
|
output_input(portlist);
|
||||||
output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
|
output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
|
||||||
output_switches(portlist, "", IPT_CONFIG, "configuration", "conflocation", "confsetting");
|
output_switches(portlist, "", IPT_CONFIG, "configuration", "conflocation", "confsetting");
|
||||||
@ -488,10 +504,10 @@ void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *
|
|||||||
output_adjusters(portlist);
|
output_adjusters(portlist);
|
||||||
output_driver(driver, overall_unemulated, overall_imperfect);
|
output_driver(driver, overall_unemulated, overall_imperfect);
|
||||||
output_features(driver.type, overall_unemulated, overall_imperfect);
|
output_features(driver.type, overall_unemulated, overall_imperfect);
|
||||||
output_images(config->root_device(), "");
|
output_images(config.root_device(), "");
|
||||||
output_slots(*config, config->root_device(), "", devtypes);
|
output_slots(config, config.root_device(), "", devtypes);
|
||||||
output_software_list(config->root_device());
|
output_software_list(config.root_device());
|
||||||
output_ramoptions(config->root_device());
|
output_ramoptions(config.root_device());
|
||||||
|
|
||||||
// close the topmost tag
|
// close the topmost tag
|
||||||
fprintf(m_output, "\t</%s>\n", XML_TOP);
|
fprintf(m_output, "\t</%s>\n", XML_TOP);
|
||||||
@ -541,7 +557,7 @@ void info_xml_creator::output_one_device(machine_config &config, device_t &devic
|
|||||||
fprintf(m_output, ">\n\t\t<description>%s</description>\n", util::xml::normalize_string(device.name()));
|
fprintf(m_output, ">\n\t\t<description>%s</description>\n", util::xml::normalize_string(device.name()));
|
||||||
|
|
||||||
output_bios(device);
|
output_bios(device);
|
||||||
output_rom(nullptr, device);
|
output_rom(nullptr, nullptr, device);
|
||||||
output_device_refs(device);
|
output_device_refs(device);
|
||||||
|
|
||||||
if (device.type().type() != typeid(samples_device)) // ignore samples_device itself
|
if (device.type().type() != typeid(samples_device)) // ignore samples_device itself
|
||||||
@ -673,7 +689,7 @@ void info_xml_creator::output_bios(device_t const &device)
|
|||||||
// the XML output
|
// the XML output
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void info_xml_creator::output_rom(driver_enumerator *drivlist, device_t &device)
|
void info_xml_creator::output_rom(driver_enumerator *drivlist, const game_driver *driver, device_t &device)
|
||||||
{
|
{
|
||||||
enum class type { BIOS, NORMAL, DISK };
|
enum class type { BIOS, NORMAL, DISK };
|
||||||
std::map<u32, char const *> biosnames;
|
std::map<u32, char const *> biosnames;
|
||||||
@ -753,7 +769,7 @@ void info_xml_creator::output_rom(driver_enumerator *drivlist, device_t &device)
|
|||||||
|
|
||||||
// if we have a valid ROM and we are a clone, see if we can find the parent ROM
|
// if we have a valid ROM and we are a clone, see if we can find the parent ROM
|
||||||
util::hash_collection const hashes(rom->hashdata);
|
util::hash_collection const hashes(rom->hashdata);
|
||||||
char const *const merge_name((do_merge_name && !hashes.flag(util::hash_collection::FLAG_NO_DUMP)) ? get_merge_name(*drivlist, hashes) : nullptr);
|
char const *const merge_name((do_merge_name && !hashes.flag(util::hash_collection::FLAG_NO_DUMP)) ? get_merge_name(*drivlist, *driver, hashes) : nullptr);
|
||||||
|
|
||||||
// opening tag
|
// opening tag
|
||||||
fprintf(m_output, is_disk ? "\t\t<disk" : "\t\t<rom");
|
fprintf(m_output, is_disk ? "\t\t<disk" : "\t\t<rom");
|
||||||
@ -1855,10 +1871,10 @@ void info_xml_creator::output_ramoptions(device_t &root)
|
|||||||
// parent set
|
// parent set
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
const char *info_xml_creator::get_merge_name(driver_enumerator &drivlist, util::hash_collection const &romhashes)
|
const char *info_xml_creator::get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes)
|
||||||
{
|
{
|
||||||
// walk the parent chain
|
// walk the parent chain
|
||||||
for (int clone_of = drivlist.find(drivlist.driver().parent); 0 <= clone_of; clone_of = drivlist.find(drivlist.driver(clone_of).parent))
|
for (int clone_of = drivlist.find(driver.parent); 0 <= clone_of; clone_of = drivlist.find(drivlist.driver(clone_of).parent))
|
||||||
{
|
{
|
||||||
// look in the parent's ROMs
|
// look in the parent's ROMs
|
||||||
for (romload::region const &pregion : romload::entries(drivlist.driver(clone_of).rom).get_regions())
|
for (romload::region const &pregion : romload::entries(drivlist.driver(clone_of).rom).get_regions())
|
||||||
|
@ -31,12 +31,19 @@ class driver_enumerator;
|
|||||||
class info_xml_creator
|
class info_xml_creator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class devices_disposition
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
FILTERED,
|
||||||
|
ALL
|
||||||
|
};
|
||||||
|
|
||||||
// construction/destruction
|
// construction/destruction
|
||||||
info_xml_creator(emu_options const &options, bool dtd = true);
|
info_xml_creator(emu_options const &options, bool dtd = true);
|
||||||
|
|
||||||
// output
|
// output
|
||||||
void output(FILE *out, std::vector<std::string> const &patterns);
|
void output(FILE *out, const std::vector<std::string> &patterns);
|
||||||
void output(FILE *out, driver_enumerator &drivlist, bool nodevices);
|
void output(FILE *out, const std::function<bool(const char *shortname, bool &done)> &filter, devices_disposition devdisp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::unordered_set<std::add_pointer_t<device_type> > device_type_set;
|
typedef std::unordered_set<std::add_pointer_t<device_type> > device_type_set;
|
||||||
@ -48,7 +55,7 @@ private:
|
|||||||
void output_one(driver_enumerator &drivlist, device_type_set *devtypes);
|
void output_one(driver_enumerator &drivlist, device_type_set *devtypes);
|
||||||
void output_sampleof(device_t &device);
|
void output_sampleof(device_t &device);
|
||||||
void output_bios(device_t const &device);
|
void output_bios(device_t const &device);
|
||||||
void output_rom(driver_enumerator *drivlist, device_t &device);
|
void output_rom(driver_enumerator *drivlist, const game_driver *driver, device_t &device);
|
||||||
void output_device_refs(device_t &root);
|
void output_device_refs(device_t &root);
|
||||||
void output_sample(device_t &device);
|
void output_sample(device_t &device);
|
||||||
void output_chips(device_t &device, const char *root_tag);
|
void output_chips(device_t &device, const char *root_tag);
|
||||||
@ -69,7 +76,7 @@ private:
|
|||||||
void output_one_device(machine_config &config, device_t &device, const char *devtag);
|
void output_one_device(machine_config &config, device_t &device, const char *devtag);
|
||||||
void output_devices(device_type_set const *filter);
|
void output_devices(device_type_set const *filter);
|
||||||
|
|
||||||
const char *get_merge_name(driver_enumerator &drivlist, util::hash_collection const &romhashes);
|
const char *get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes);
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
FILE * m_output; // FIXME: this is not reentrancy-safe
|
FILE * m_output; // FIXME: this is not reentrancy-safe
|
||||||
|
@ -590,14 +590,25 @@ void menu_export::handle()
|
|||||||
file.close();
|
file.close();
|
||||||
pfile = fopen(fullpath.c_str(), "w");
|
pfile = fopen(fullpath.c_str(), "w");
|
||||||
|
|
||||||
// create the XML and save to file
|
// prepare a filter for the drivers we want to show
|
||||||
driver_enumerator drvlist(machine().options());
|
std::unordered_set<const game_driver *> driver_list(m_list.begin(), m_list.end());
|
||||||
drvlist.exclude_all();
|
auto filter = [&driver_list](const char *shortname, bool &)
|
||||||
for (auto & elem : m_list)
|
{
|
||||||
drvlist.include(driver_list::find(*elem));
|
auto iter = std::find_if(
|
||||||
|
driver_list.begin(),
|
||||||
|
driver_list.end(),
|
||||||
|
[shortname](const game_driver *driver) { return !strcmp(shortname, driver->name); });
|
||||||
|
return iter != driver_list.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
// do we want to show devices?
|
||||||
|
info_xml_creator::devices_disposition devdisp = (uintptr_t(menu_event->itemref) == 1)
|
||||||
|
? info_xml_creator::devices_disposition::FILTERED
|
||||||
|
: info_xml_creator::devices_disposition::NONE;
|
||||||
|
|
||||||
|
// and do the dirty work
|
||||||
info_xml_creator creator(machine().options());
|
info_xml_creator creator(machine().options());
|
||||||
creator.output(pfile, drvlist, (uintptr_t(menu_event->itemref) == 1) ? false : true);
|
creator.output(pfile, filter, devdisp);
|
||||||
fclose(pfile);
|
fclose(pfile);
|
||||||
machine().popmessage(_("%s.xml saved under ui folder."), filename.c_str());
|
machine().popmessage(_("%s.xml saved under ui folder."), filename.c_str());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user