mirror of
https://github.com/holub/mame
synced 2025-04-26 02:07:14 +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
|
||||
/***************************************************************************
|
||||
|
||||
info.c
|
||||
info.cpp
|
||||
|
||||
Dumps the MAME internal data as an XML file.
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
|
||||
#define XML_ROOT "mame"
|
||||
@ -214,125 +213,142 @@ info_xml_creator::info_xml_creator(emu_options const &options, bool dtd)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// output_mame_xml - print the XML information
|
||||
// for all known games
|
||||
// output - print the XML information for all
|
||||
// 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;
|
||||
|
||||
bool result = false;
|
||||
auto it = matched.begin();
|
||||
for (std::string const &pat : patterns)
|
||||
};
|
||||
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
|
||||
{
|
||||
if (!core_strwildcmp(pat.c_str(), name))
|
||||
bool result = false;
|
||||
auto it = matched.begin();
|
||||
for (const std::string &pat : patterns)
|
||||
{
|
||||
result = true;
|
||||
if (!*it)
|
||||
if (!core_strwildcmp(pat.c_str(), shortname))
|
||||
{
|
||||
*it = true;
|
||||
if (!core_iswildstr(pat.c_str()))
|
||||
++exact_matches;
|
||||
// this driver matches the pattern - tell the caller
|
||||
result = true;
|
||||
|
||||
// did we see this particular pattern before? if not, track that we have
|
||||
if (!*it)
|
||||
{
|
||||
*it = true;
|
||||
if (!core_iswildstr(pat.c_str()))
|
||||
{
|
||||
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
|
||||
bool first = true;
|
||||
while (drivlist.next())
|
||||
{
|
||||
if (included(drivlist.driver().name))
|
||||
// throw an error if there were unmatched patterns
|
||||
auto iter = std::find(matched.begin(), matched.end(), false);
|
||||
if (iter != matched.end())
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
output_header();
|
||||
first = false;
|
||||
}
|
||||
output_one(drivlist, devfilter.get());
|
||||
|
||||
// stop looking if we found everything specified
|
||||
if (!patterns.empty() && exact_matches == patterns.size())
|
||||
break;
|
||||
int index = iter - matched.begin();
|
||||
throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching machines found for '%s'", patterns[index].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through the device types if not everything matches a driver
|
||||
if (!patterns.empty() && exact_matches != patterns.size())
|
||||
{
|
||||
for (device_type type : registered_device_types)
|
||||
{
|
||||
if (included(type.shortname()))
|
||||
{
|
||||
devfilter->insert(&type);
|
||||
if (exact_matches == patterns.size())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// output devices (both devices with roms and slot devices)
|
||||
if (!devfilter || !devfilter->empty())
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
output_header();
|
||||
first = false;
|
||||
}
|
||||
output_devices(devfilter.get());
|
||||
}
|
||||
|
||||
if (!first)
|
||||
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
|
||||
// output - print the XML information for all
|
||||
// known (and filtered) machines
|
||||
//-------------------------------------------------
|
||||
|
||||
void info_xml_creator::output(FILE *out, driver_enumerator &drivlist, bool nodevices)
|
||||
void info_xml_creator::output(FILE *out, const std::function<bool(const char *shortname, bool &done)> &filter, devices_disposition devdisp)
|
||||
{
|
||||
// sanity checks
|
||||
assert(out);
|
||||
assert(filter);
|
||||
|
||||
// set up output
|
||||
m_output = out;
|
||||
|
||||
device_type_set devfilter;
|
||||
// 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;
|
||||
|
||||
output_header();
|
||||
// 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>();
|
||||
|
||||
// iterate through the drivers, outputting one at a time
|
||||
while (drivlist.next())
|
||||
output_one(drivlist, &devfilter);
|
||||
// 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();
|
||||
header_outputted = true;
|
||||
}
|
||||
|
||||
// output it
|
||||
output_one(drivlist, devfilter.get());
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through the device types if not everything matches a driver
|
||||
if (devfilter && !filter_done)
|
||||
{
|
||||
for (device_type type : registered_device_types)
|
||||
{
|
||||
if (filter(type.shortname(), filter_done))
|
||||
devfilter->insert(&type);
|
||||
|
||||
if (filter_done)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// output devices (both devices with roms and slot devices)
|
||||
if (!nodevices)
|
||||
output_devices(&devfilter);
|
||||
if (devdisp != devices_disposition::NONE && (!devfilter || !devfilter->empty()))
|
||||
{
|
||||
if (!header_outputted)
|
||||
{
|
||||
output_header();
|
||||
header_outputted = true;
|
||||
}
|
||||
output_devices(devfilter.get());
|
||||
}
|
||||
|
||||
output_footer();
|
||||
if (header_outputted)
|
||||
output_footer();
|
||||
}
|
||||
|
||||
|
||||
@ -381,14 +397,14 @@ void info_xml_creator::output_footer()
|
||||
|
||||
//-------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
const game_driver &driver = drivlist.driver();
|
||||
std::shared_ptr<machine_config> const config(drivlist.config());
|
||||
device_iterator iter(config->root_device());
|
||||
machine_config config(driver, drivlist.options());
|
||||
device_iterator iter(config.root_device());
|
||||
|
||||
// allocate input ports and build overall emulation status
|
||||
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));
|
||||
|
||||
// display sample information and close the game tag
|
||||
output_sampleof(config->root_device());
|
||||
output_sampleof(config.root_device());
|
||||
fprintf(m_output, ">\n");
|
||||
|
||||
// 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));
|
||||
|
||||
// now print various additional information
|
||||
output_bios(config->root_device());
|
||||
output_rom(&drivlist, config->root_device());
|
||||
output_device_refs(config->root_device());
|
||||
output_sample(config->root_device());
|
||||
output_chips(config->root_device(), "");
|
||||
output_display(config->root_device(), &drivlist.driver().flags, "");
|
||||
output_sound(config->root_device());
|
||||
output_bios(config.root_device());
|
||||
output_rom(&drivlist, &driver, config.root_device());
|
||||
output_device_refs(config.root_device());
|
||||
output_sample(config.root_device());
|
||||
output_chips(config.root_device(), "");
|
||||
output_display(config.root_device(), &driver.flags, "");
|
||||
output_sound(config.root_device());
|
||||
output_input(portlist);
|
||||
output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
|
||||
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_driver(driver, overall_unemulated, overall_imperfect);
|
||||
output_features(driver.type, overall_unemulated, overall_imperfect);
|
||||
output_images(config->root_device(), "");
|
||||
output_slots(*config, config->root_device(), "", devtypes);
|
||||
output_software_list(config->root_device());
|
||||
output_ramoptions(config->root_device());
|
||||
output_images(config.root_device(), "");
|
||||
output_slots(config, config.root_device(), "", devtypes);
|
||||
output_software_list(config.root_device());
|
||||
output_ramoptions(config.root_device());
|
||||
|
||||
// close the topmost tag
|
||||
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()));
|
||||
|
||||
output_bios(device);
|
||||
output_rom(nullptr, device);
|
||||
output_rom(nullptr, nullptr, device);
|
||||
output_device_refs(device);
|
||||
|
||||
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
|
||||
//-------------------------------------------------
|
||||
|
||||
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 };
|
||||
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
|
||||
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
|
||||
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
|
||||
//-------------------------------------------------
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
{
|
||||
public:
|
||||
enum class devices_disposition
|
||||
{
|
||||
NONE,
|
||||
FILTERED,
|
||||
ALL
|
||||
};
|
||||
|
||||
// construction/destruction
|
||||
info_xml_creator(emu_options const &options, bool dtd = true);
|
||||
|
||||
// output
|
||||
void output(FILE *out, std::vector<std::string> const &patterns);
|
||||
void output(FILE *out, driver_enumerator &drivlist, bool nodevices);
|
||||
void output(FILE *out, const std::vector<std::string> &patterns);
|
||||
void output(FILE *out, const std::function<bool(const char *shortname, bool &done)> &filter, devices_disposition devdisp);
|
||||
|
||||
private:
|
||||
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_sampleof(device_t &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_sample(device_t &device);
|
||||
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_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
|
||||
FILE * m_output; // FIXME: this is not reentrancy-safe
|
||||
|
@ -590,14 +590,25 @@ void menu_export::handle()
|
||||
file.close();
|
||||
pfile = fopen(fullpath.c_str(), "w");
|
||||
|
||||
// create the XML and save to file
|
||||
driver_enumerator drvlist(machine().options());
|
||||
drvlist.exclude_all();
|
||||
for (auto & elem : m_list)
|
||||
drvlist.include(driver_list::find(*elem));
|
||||
// prepare a filter for the drivers we want to show
|
||||
std::unordered_set<const game_driver *> driver_list(m_list.begin(), m_list.end());
|
||||
auto filter = [&driver_list](const char *shortname, bool &)
|
||||
{
|
||||
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());
|
||||
creator.output(pfile, drvlist, (uintptr_t(menu_event->itemref) == 1) ? false : true);
|
||||
creator.output(pfile, filter, devdisp);
|
||||
fclose(pfile);
|
||||
machine().popmessage(_("%s.xml saved under ui folder."), filename.c_str());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user