summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/infoxml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/infoxml.cpp')
-rw-r--r--src/frontend/mame/infoxml.cpp718
1 files changed, 476 insertions, 242 deletions
diff --git a/src/frontend/mame/infoxml.cpp b/src/frontend/mame/infoxml.cpp
index 59b3a637aee..37d649a1131 100644
--- a/src/frontend/mame/infoxml.cpp
+++ b/src/frontend/mame/infoxml.cpp
@@ -13,22 +13,28 @@
#include "mameopts.h"
+// devices
#include "machine/ram.h"
#include "sound/samples.h"
+// emu
#include "config.h"
#include "drivenum.h"
+#include "main.h"
#include "romload.h"
#include "screen.h"
#include "softlist_dev.h"
#include "speaker.h"
+// lib/util
+#include "corestr.h"
#include "xmlfile.h"
#include <algorithm>
#include <cctype>
#include <cstring>
#include <future>
+#include <locale>
#include <queue>
#include <type_traits>
#include <unordered_set>
@@ -51,9 +57,53 @@ public:
bool operator()(const std::add_pointer_t<device_type> &lhs, const std::add_pointer_t<device_type> &rhs) const;
};
-typedef std::set<std::add_pointer_t<device_type>, device_type_compare> device_type_set;
-std::string normalize_string(const char *string);
+class device_filter
+{
+public:
+ device_filter(const std::function<bool(const char *shortname, bool &done)> &callback)
+ : m_callback(callback)
+ , m_done(false)
+ {
+ }
+
+ // methods
+ bool filter(const char *shortname);
+
+ // accessors
+ bool done() const { return m_done; }
+
+private:
+ const std::function<bool(const char *shortname, bool &done)> & m_callback;
+ bool m_done;
+};
+
+
+class filtered_driver_enumerator
+{
+public:
+ filtered_driver_enumerator(driver_enumerator &drivlist, device_filter &devfilter)
+ : m_drivlist(drivlist)
+ , m_devfilter(devfilter)
+ , m_done(false)
+ {
+ }
+
+ // methods
+ std::vector<std::reference_wrapper<const game_driver>> next(int count);
+
+ // accessors
+ bool done() const { return m_done || m_devfilter.done(); }
+
+private:
+ driver_enumerator & m_drivlist;
+ device_filter & m_devfilter;
+ bool m_done;
+};
+
+
+using device_type_set = std::set<std::add_pointer_t<device_type>, device_type_compare>;
+using device_type_vector = std::vector<std::add_pointer_t<device_type> >;
// internal helper
void output_header(std::ostream &out, bool dtd);
@@ -62,7 +112,7 @@ void output_footer(std::ostream &out);
void output_one(std::ostream &out, driver_enumerator &drivlist, const game_driver &driver, device_type_set *devtypes);
void output_sampleof(std::ostream &out, device_t &device);
void output_bios(std::ostream &out, device_t const &device);
-void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_driver *driver, device_t &device);
+void output_rom(std::ostream &out, machine_config &config, driver_list const *drivlist, const game_driver *driver, device_t &device);
void output_device_refs(std::ostream &out, device_t &root);
void output_sample(std::ostream &out, device_t &device);
void output_chips(std::ostream &out, device_t &device, const char *root_tag);
@@ -83,7 +133,9 @@ void output_ramoptions(std::ostream &out, device_t &root);
void output_one_device(std::ostream &out, machine_config &config, device_t &device, const char *devtag);
void output_devices(std::ostream &out, emu_options &lookup_options, device_type_set const *filter);
-const char *get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes);
+char const *get_merge_name(driver_list const &drivlist, game_driver const &driver, util::hash_collection const &romhashes);
+char const *get_merge_name(machine_config &config, device_t const &device, util::hash_collection const &romhashes);
+char const *get_merge_name(tiny_rom_entry const *roms, util::hash_collection const &romhashes);
//**************************************************************************
@@ -219,6 +271,10 @@ constexpr char f_dtd_string[] =
"\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n"
"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
+ "\t\t\t<!ATTLIST driver requiresartwork (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST driver unofficial (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST driver nosoundhardware (yes|no) \"no\">\n"
+ "\t\t\t<!ATTLIST driver incomplete (yes|no) \"no\">\n"
"\t\t<!ELEMENT feature EMPTY>\n"
"\t\t\t<!ATTLIST feature type (protection|timing|graphics|palette|sound|capture|camera|microphone|controls|keyboard|mouse|media|disk|printer|tape|punch|drum|rom|comms|lan|wan) #REQUIRED>\n"
"\t\t\t<!ATTLIST feature status (unemulated|imperfect) #IMPLIED>\n"
@@ -284,7 +340,7 @@ constexpr std::pair<device_t::feature_type, char const *> f_feature_names[] = {
//-------------------------------------------------
-// get_feature_name - get XML name for feature
+// feature_name - get XML name for feature
//-------------------------------------------------
char const *info_xml_creator::feature_name(device_t::feature_type feature)
@@ -302,6 +358,33 @@ char const *info_xml_creator::feature_name(device_t::feature_type feature)
//-------------------------------------------------
+// format_sourcefile - sanitise source file path
+//-------------------------------------------------
+
+std::string info_xml_creator::format_sourcefile(std::string_view path)
+{
+ using namespace std::literals;
+
+ if (auto prefix(path.rfind("src/mame/"sv)); std::string_view::npos != prefix)
+ path.remove_prefix(prefix + 9);
+ else if (auto prefix(path.rfind("src\\mame\\"sv)); std::string_view::npos != prefix)
+ path.remove_prefix(prefix + 9);
+ else if (auto prefix(path.rfind("/src/"sv)); std::string_view::npos != prefix)
+ path.remove_prefix(prefix + 5);
+ else if (auto prefix(path.rfind("\\src\\"sv)); std::string_view::npos != prefix)
+ path.remove_prefix(prefix + 5);
+ else if (path.substr(0, 4) == "src/"sv)
+ path.remove_prefix(4);
+ else if (path.substr(0, 4) == "src\\"sv)
+ path.remove_prefix(4);
+
+ std::string result(path);
+ std::replace(result.begin(), result.end(), '\\', '/');
+ return result;
+}
+
+
+//-------------------------------------------------
// info_xml_creator - constructor
//-------------------------------------------------
@@ -334,7 +417,7 @@ void info_xml_creator::output(std::ostream &out, const std::vector<std::string>
auto it = matched.begin();
for (const std::string &pat : patterns)
{
- if (!core_strwildcmp(pat.c_str(), shortname))
+ if (!core_strwildcmp(pat, shortname))
{
// this driver matches the pattern - tell the caller
result = true;
@@ -343,7 +426,7 @@ void info_xml_creator::output(std::ostream &out, const std::vector<std::string>
if (!*it)
{
*it = true;
- if (!core_iswildstr(pat.c_str()))
+ if (!core_iswildstr(pat))
{
exact_matches++;
@@ -364,7 +447,7 @@ void info_xml_creator::output(std::ostream &out, const std::vector<std::string>
if (iter != matched.end())
{
int index = iter - matched.begin();
- throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching machines found for '%s'", patterns[index].c_str());
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching machines found for '%s'", patterns[index]);
}
}
}
@@ -379,99 +462,129 @@ void info_xml_creator::output(std::ostream &out, const std::function<bool(const
{
struct prepared_info
{
+ prepared_info() = default;
+ prepared_info(const prepared_info &) = delete;
+ prepared_info(prepared_info &&) = default;
+#if defined(_CPPLIB_VER) && defined(_MSVC_STL_VERSION)
+ // MSVCPRT currently requires default-constructible std::future promise types to be assignable
+ // remove this workaround when that's fixed
+ prepared_info &operator=(const prepared_info &) = default;
+#else
+ prepared_info &operator=(const prepared_info &) = delete;
+#endif
+
std::string m_xml_snippet;
device_type_set m_dev_set;
};
// prepare a driver enumerator and the queue
driver_enumerator drivlist(m_lookup_options);
- bool drivlist_done = false;
- bool filter_done = false;
+ device_filter devfilter(filter);
+ filtered_driver_enumerator filtered_drivlist(drivlist, devfilter);
bool header_outputted = false;
- auto output_header_if_necessary = [this, &header_outputted](std::ostream &out)
- {
- if (!header_outputted)
- {
- output_header(out, m_dtd);
- header_outputted = true;
- }
- };
+ // essentially a local method to emit the header if necessary
+ auto const output_header_if_necessary = [this, &header_outputted] (std::ostream &out)
+ {
+ if (!header_outputted)
+ {
+ output_header(out, m_dtd);
+ header_outputted = true;
+ }
+ };
// only keep a device set when we're asked to track it
- std::unique_ptr<device_type_set> devfilter;
+ std::optional<device_type_set> devset;
if (include_devices && filter)
- devfilter = std::make_unique<device_type_set>();
+ devset.emplace();
+
+ // prepare a queue of tasks - this is a FIFO queue because of the
+ // need to be deterministic
+ std::queue<std::future<prepared_info> > tasks;
- // prepare a queue of futures
- std::queue<std::future<prepared_info>> queue;
+ // while we want to be deterministic, asynchronous task scheduling is not; so we want to
+ // track the amount of active tasks so that we can keep on spawning tasks even if we're
+ // waiting on the task in the front of the queue
+ std::atomic<unsigned int> active_task_count = 0;
+ unsigned int const maximum_active_task_count = std::thread::hardware_concurrency() + 10;
+ unsigned int const maximum_outstanding_task_count = maximum_active_task_count + 20;
- // try enumerating drivers and outputting them
- while (!queue.empty() || (!drivlist_done && !filter_done))
+ // loop until we're done enumerating drivers, and until there are no outstanding tasks
+ while (!filtered_drivlist.done() || !tasks.empty())
{
- // try populating the queue
- while (queue.size() < 20 && !drivlist_done && !filter_done)
+ // loop until there are as many outstanding tasks as possible (we want to separately cap outstanding
+ // tasks and active tasks)
+ while (!filtered_drivlist.done()
+ && (active_task_count < maximum_active_task_count)
+ && (tasks.size() < maximum_outstanding_task_count))
{
- 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 || filter(drivlist.driver().name, filter_done))
- {
- const game_driver &driver(drivlist.driver());
- std::future<prepared_info> future_pi = std::async(std::launch::async, [&drivlist, &driver, &devfilter]
- {
- prepared_info result;
- std::ostringstream stream;
-
- output_one(stream, drivlist, driver, devfilter ? &result.m_dev_set : nullptr);
- result.m_xml_snippet = stream.str();
- return result;
- });
- queue.push(std::move(future_pi));
- }
+ // we want to launch a task; grab a packet of drivers to process
+ std::vector<std::reference_wrapper<const game_driver> > drivers = filtered_drivlist.next(20);
+ if (drivers.empty())
+ break;
+
+ // do the dirty work asynchronously
+ auto task_proc = [&drivlist, drivers = std::move(drivers), include_devices, &active_task_count]
+ {
+ prepared_info result;
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+
+ // output each of the drivers
+ for (const game_driver &driver : drivers)
+ output_one(stream, drivlist, driver, include_devices ? &result.m_dev_set : nullptr);
+
+ // capture the XML snippet
+ result.m_xml_snippet = std::move(stream).str();
+
+ // we're done with the task; decrement the counter and return
+ active_task_count--;
+ return result;
+ };
+
+ // add this task to the queue
+ active_task_count++;
+ tasks.emplace(std::async(std::launch::async, std::move(task_proc)));
}
- // now that we have the queue populated, try grabbing one (assuming that it is not empty)
- if (!queue.empty())
+ // we've put as many outstanding tasks out as we can; are there any tasks outstanding?
+ if (!tasks.empty())
{
- // wait for the future to complete and get the info
- prepared_info pi = queue.front().get();
- queue.pop();
+ // wait for the oldest task to complete and get the info, in the spirit of determinism
+ prepared_info pi = tasks.front().get();
+ tasks.pop();
- // emit the XML
+ // emit whatever XML we accumulated in the task
output_header_if_necessary(out);
out << pi.m_xml_snippet;
- // merge devices into devfilter, if appropriate
- if (devfilter)
+ // merge devices into devset, if appropriate
+ if (devset)
{
for (const auto &x : pi.m_dev_set)
- devfilter->insert(x);
+ devset->insert(x);
}
}
}
// iterate through the device types if not everything matches a driver
- if (devfilter && !filter_done)
+ if (devset && !devfilter.done())
{
for (device_type type : registered_device_types)
{
- if (!filter || filter(type.shortname(), filter_done))
- devfilter->insert(&type);
+ if (devfilter.filter(type.shortname()))
+ devset->insert(&type);
- if (filter_done)
+ if (devfilter.done())
break;
}
}
// output devices (both devices with roms and slot devices)
- if (include_devices && (!devfilter || !devfilter->empty()))
+ if (include_devices && (!devset || !devset->empty()))
{
output_header_if_necessary(out);
- output_devices(out, m_lookup_options, devfilter.get());
+ output_devices(out, m_lookup_options, devset ? &*devset : nullptr);
}
if (header_outputted)
@@ -487,31 +600,40 @@ namespace
{
//-------------------------------------------------
-// normalize_string
+// device_filter::filter - apply the filter, if
+// present
//-------------------------------------------------
-std::string normalize_string(const char *string)
+bool device_filter::filter(const char *shortname)
{
- std::ostringstream stream;
+ return !m_done && (!m_callback || m_callback(shortname, m_done));
+}
- if (string != nullptr)
+
+//-------------------------------------------------
+// filtered_driver_enumerator::next - take a number
+// of game_drivers, while applying filters
+//-------------------------------------------------
+
+std::vector<std::reference_wrapper<const game_driver> > filtered_driver_enumerator::next(int count)
+{
+ std::vector<std::reference_wrapper<const game_driver> > results;
+ results.reserve(count);
+ while (!done() && results.size() < count)
{
- while (*string)
+ if (!m_drivlist.next())
{
- switch (*string)
- {
- case '\"': stream << "&quot;"; break;
- case '&': stream << "&amp;"; break;
- case '<': stream << "&lt;"; break;
- case '>': stream << "&gt;"; break;
- default:
- stream << *string;
- break;
- }
- ++string;
+ // at this point we are done enumerating through drivlist and it is no
+ // longer safe to call next(), so record that we're done
+ m_done = true;
+ }
+ else if (m_devfilter.filter(m_drivlist.driver().name))
+ {
+ const game_driver &driver(m_drivlist.driver());
+ results.emplace_back(driver);
}
}
- return stream.str();
+ return results;
}
@@ -534,7 +656,9 @@ void output_header(std::ostream &out, bool dtd)
}
// top-level tag
- out << util::string_format("<%s build=\"%s\" debug=\""
+ assert(emulator_info::get_build_version() != nullptr);
+ util::stream_format(out,
+ "<%s build=\"%s\" debug=\""
#ifdef MAME_DEBUG
"yes"
#else
@@ -542,8 +666,8 @@ void output_header(std::ostream &out, bool dtd)
#endif
"\" mameconfig=\"%d\">\n",
XML_ROOT,
- normalize_string(emulator_info::get_build_version()),
- CONFIG_VERSION);
+ util::xml::normalize_string(emulator_info::get_build_version()),
+ configuration_manager::CONFIG_VERSION);
}
@@ -554,7 +678,7 @@ void output_header(std::ostream &out, bool dtd)
void output_footer(std::ostream &out)
{
// close the top level tag
- out << util::string_format("</%s>\n", XML_ROOT);
+ util::stream_format(out, "</%s>\n", XML_ROOT);
}
@@ -565,8 +689,10 @@ void output_footer(std::ostream &out)
void output_one(std::ostream &out, driver_enumerator &drivlist, const game_driver &driver, device_type_set *devtypes)
{
+ using util::xml::normalize_string;
+
machine_config config(driver, drivlist.options());
- device_iterator iter(config.root_device());
+ device_enumerator iter(config.root_device());
// allocate input ports and build overall emulation status
ioport_list portlist;
@@ -613,14 +739,10 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
}
// print the header and the machine name
- out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(driver.name));
+ util::stream_format(out, "\t<%s name=\"%s\"", XML_TOP, normalize_string(driver.name));
- // strip away any path information from the source_file and output it
- const char *start = strrchr(driver.type.source(), '/');
- if (!start)
- start = strrchr(driver.type.source(), '\\');
- start = start ? (start + 1) : driver.type.source();
- out << util::string_format(" sourcefile=\"%s\"", normalize_string(start));
+ // strip away extra path information from the source file and output it
+ util::stream_format(out, " sourcefile=\"%s\"", normalize_string(info_xml_creator::format_sourcefile(driver.type.source())));
// append bios and runnable flags
if (driver.flags & machine_flags::IS_BIOS_ROOT)
@@ -631,9 +753,9 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
// display clone information
int clone_of = drivlist.find(driver.parent);
if (clone_of != -1 && !(drivlist.driver(clone_of).flags & machine_flags::IS_BIOS_ROOT))
- out << util::string_format(" cloneof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
+ util::stream_format(out, " cloneof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
if (clone_of != -1)
- out << util::string_format(" romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
+ util::stream_format(out, " romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
// display sample information and close the game tag
output_sampleof(out, config.root_device());
@@ -641,19 +763,19 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
// output game description
if (driver.type.fullname() != nullptr)
- out << util::string_format("\t\t<description>%s</description>\n", normalize_string(driver.type.fullname()));
+ util::stream_format(out, "\t\t<description>%s</description>\n", normalize_string(driver.type.fullname()));
// print the year only if is a number or another allowed character (? or +)
- if (driver.year != nullptr && strspn(driver.year, "0123456789?+") == strlen(driver.year))
- out << util::string_format("\t\t<year>%s</year>\n", normalize_string(driver.year));
+ if (driver.year && strspn(driver.year, "0123456789?+") == strlen(driver.year))
+ util::stream_format(out, "\t\t<year>%s</year>\n", normalize_string(driver.year));
// print the manufacturer information
if (driver.manufacturer != nullptr)
- out << util::string_format("\t\t<manufacturer>%s</manufacturer>\n", normalize_string(driver.manufacturer));
+ util::stream_format(out, "\t\t<manufacturer>%s</manufacturer>\n", normalize_string(driver.manufacturer));
// now print various additional information
output_bios(out, config.root_device());
- output_rom(out, &drivlist, &driver, config.root_device());
+ output_rom(out, config, &drivlist, &driver, config.root_device());
output_device_refs(out, config.root_device());
output_sample(out, config.root_device());
output_chips(out, config.root_device(), "");
@@ -672,7 +794,7 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
output_ramoptions(out, config.root_device());
// close the topmost tag
- out << util::string_format("\t</%s>\n", XML_TOP);
+ util::stream_format(out, "\t</%s>\n", XML_TOP);
}
@@ -683,9 +805,11 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
void output_one_device(std::ostream &out, machine_config &config, device_t &device, const char *devtag)
{
+ using util::xml::normalize_string;
+
bool has_speaker = false, has_input = false;
// check if the device adds speakers to the system
- sound_interface_iterator snditer(device);
+ sound_interface_enumerator snditer(device);
if (snditer.first() != nullptr)
has_speaker = true;
@@ -694,7 +818,7 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
std::string errors;
device_t::feature_type overall_unemulated(device.type().unemulated_features());
device_t::feature_type overall_imperfect(device.type().imperfect_features());
- for (device_t &dev : device_iterator(device))
+ for (device_t &dev : device_enumerator(device))
{
portlist.append(dev, errors);
overall_unemulated |= dev.type().unemulated_features();
@@ -711,15 +835,17 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
}
// start to output info
- out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(device.shortname()));
- std::string src(device.source());
- strreplace(src,"../", "");
- out << util::string_format(" sourcefile=\"%s\" isdevice=\"yes\" runnable=\"no\"", normalize_string(src.c_str()));
+ util::stream_format(out, "\t<%s name=\"%s\"", XML_TOP, normalize_string(device.shortname()));
+ util::stream_format(out, " sourcefile=\"%s\" isdevice=\"yes\" runnable=\"no\"", normalize_string(info_xml_creator::format_sourcefile(device.source())));
+ auto const parent(device.type().parent_rom_device_type());
+ if (parent)
+ util::stream_format(out, " romof=\"%s\"", normalize_string(parent->shortname()));
output_sampleof(out, device);
- out << ">\n" << util::string_format("\t\t<description>%s</description>\n", normalize_string(device.name()));
+ out << ">\n";
+ util::stream_format(out, "\t\t<description>%s</description>\n", normalize_string(device.name()));
output_bios(out, device);
- output_rom(out, nullptr, nullptr, device);
+ output_rom(out, config, nullptr, nullptr, device);
output_device_refs(out, device);
if (device.type().type() != typeid(samples_device)) // ignore samples_device itself
@@ -738,7 +864,7 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
output_images(out, device, devtag);
output_slots(out, config, device, devtag, nullptr);
output_software_lists(out, device, devtag);
- out << util::string_format("\t</%s>\n", XML_TOP);
+ util::stream_format(out, "\t</%s>\n", XML_TOP);
}
@@ -749,38 +875,85 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
void output_devices(std::ostream &out, emu_options &lookup_options, device_type_set const *filter)
{
- // get config for empty machine
- machine_config config(GAME_NAME(___empty), lookup_options);
-
- auto const action = [&config, &out] (device_type type)
+ auto const action = [&lookup_options, &out] (auto &types, auto deref)
{
- // add it at the root of the machine config
- device_t *dev;
+ // machinery for making output order deterministic and capping outstanding tasks
+ std::queue<std::future<std::string> > tasks;
+ std::atomic<unsigned int> active_task_count = 0;
+ unsigned int const maximum_active_task_count = std::thread::hardware_concurrency() + 10;
+ unsigned int const maximum_outstanding_task_count = maximum_active_task_count + 20;
+
+ // loop until we're done enumerating devices and there are no outstanding tasks
+ auto it = std::begin(types);
+ while ((std::end(types) != it) || !tasks.empty())
{
- machine_config::token const tok(config.begin_configuration(config.root_device()));
- dev = config.device_add("_tmp", type, 0);
- }
+ // look until there are as many outstanding tasks as possible
+ while ((std::end(types) != it)
+ && (active_task_count < maximum_active_task_count)
+ && (tasks.size() < maximum_outstanding_task_count))
+ {
+ device_type_vector batch;
+ batch.reserve(10);
+ while ((std::end(types) != it) && (batch.size() < 10))
+ batch.emplace_back(deref(*it++));
+ if (batch.empty())
+ break;
+
+ // do the dirty work asynchronously
+ auto task_proc = [&active_task_count, &lookup_options, batch = std::move(batch)]
+ {
+ // use a single machine configuration and stream for a batch of devices
+ machine_config config(GAME_NAME(___empty), lookup_options);
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+ for (auto type : batch)
+ {
+ // add it at the root of the machine config
+ device_t *dev;
+ {
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ dev = config.device_add("_tmp", *type, 0);
+ }
+
+ // notify this device and all its subdevices that they are now configured
+ for (device_t &device : device_enumerator(*dev))
+ if (!device.configured())
+ device.config_complete();
+
+ // print details and remove it
+ output_one_device(stream, config, *dev, dev->tag());
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ config.device_remove("_tmp");
+ }
+
+ // we're done with the task; decrement the counter and return
+ active_task_count--;
+ return std::move(stream).str();
+ };
+
+ // add this task to the queue
+ active_task_count++;
+ tasks.emplace(std::async(std::launch::async, std::move(task_proc)));
+ }
- // notify this device and all its subdevices that they are now configured
- for (device_t &device : device_iterator(*dev))
- if (!device.configured())
- device.config_complete();
+ // we've put as many outstanding tasks out as we can; are there any tasks outstanding?
+ if (!tasks.empty())
+ {
+ // wait for the oldest task to complete and get the info, in the spirit of determinism
+ std::string snippet = tasks.front().get();
+ tasks.pop();
- // print details and remove it
- output_one_device(out, config, *dev, dev->tag());
- machine_config::token const tok(config.begin_configuration(config.root_device()));
- config.device_remove("_tmp");
+ // emit whatever XML we accumulated in the task
+ out << snippet;
+ }
+ }
};
// run through devices
if (filter)
- {
- for (std::add_pointer_t<device_type> type : *filter) action(*type);
- }
+ action(*filter, [] (auto &x) { return x; });
else
- {
- for (device_type type : registered_device_types) action(type);
- }
+ action(registered_device_types, [] (auto &x) { return &x; });
}
@@ -791,9 +964,9 @@ void output_devices(std::ostream &out, emu_options &lookup_options, device_type_
void output_device_refs(std::ostream &out, device_t &root)
{
- for (device_t &device : device_iterator(root))
+ for (device_t &device : device_enumerator(root))
if (&device != &root)
- out << util::string_format("\t\t<device_ref name=\"%s\"/>\n", normalize_string(device.shortname()));
+ util::stream_format(out, "\t\t<device_ref name=\"%s\"/>\n", util::xml::normalize_string(device.shortname()));
}
@@ -805,12 +978,12 @@ void output_device_refs(std::ostream &out, device_t &root)
void output_sampleof(std::ostream &out, device_t &device)
{
// iterate over sample devices
- for (samples_device &samples : samples_device_iterator(device))
+ for (samples_device &samples : samples_device_enumerator(device))
{
samples_iterator sampiter(samples);
if (sampiter.altbasename() != nullptr)
{
- out << util::string_format(" sampleof=\"%s\"", normalize_string(sampiter.altbasename()));
+ util::stream_format(out, " sampleof=\"%s\"", util::xml::normalize_string(sampiter.altbasename()));
// must stop here, as there can only be one attribute of the same name
return;
@@ -838,8 +1011,8 @@ void output_bios(std::ostream &out, device_t const &device)
{
// output extracted name and descriptions'
out << "\t\t<biosset";
- out << util::string_format(" name=\"%s\"", normalize_string(bios.get_name()));
- out << util::string_format(" description=\"%s\"", normalize_string(bios.get_description()));
+ util::stream_format(out, " name=\"%s\"", util::xml::normalize_string(bios.get_name()));
+ util::stream_format(out, " description=\"%s\"", util::xml::normalize_string(bios.get_description()));
if (defaultname && !std::strcmp(defaultname, bios.get_name()))
out << " default=\"yes\"";
out << "/>\n";
@@ -852,7 +1025,7 @@ void output_bios(std::ostream &out, device_t const &device)
// the XML output
//-------------------------------------------------
-void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_driver *driver, device_t &device)
+void output_rom(std::ostream &out, machine_config &config, driver_list const *drivlist, const game_driver *driver, device_t &device)
{
enum class type { BIOS, NORMAL, DISK };
std::map<u32, char const *> biosnames;
@@ -890,7 +1063,7 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
// loop until we run out of reloads
do
{
- // loop until we run out of continues/ignores */
+ // loop until we run out of continues/ignores
u32 curlength(ROM_GETLENGTH(romp++));
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
curlength += ROM_GETLENGTH(romp++);
@@ -904,12 +1077,14 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
};
// iterate over 3 different ROM "types": BIOS, ROMs, DISKs
- bool const do_merge_name = drivlist && dynamic_cast<driver_device *>(&device);
+ bool const driver_merge = drivlist && dynamic_cast<driver_device *>(&device);
for (type pass : { type::BIOS, type::NORMAL, type::DISK })
{
tiny_rom_entry const *region(nullptr);
for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom)
{
+ using util::xml::normalize_string;
+
if (ROMENTRY_ISREGION(rom))
region = rom;
else if (ROMENTRY_ISSYSTEM_BIOS(rom))
@@ -923,7 +1098,7 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
if ((type::DISK == pass) != is_disk)
continue;
- // BIOS ROMs only apply to bioses
+ // BIOS ROMs only apply to BIOSes
// FIXME: disk images associated with a system BIOS will never be listed
u32 const biosno(ROM_GETBIOSFLAGS(rom));
if ((type::BIOS == pass) != bool(biosno))
@@ -932,7 +1107,10 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
// 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, *driver, hashes) : nullptr);
+ char const *const merge_name(
+ hashes.flag(util::hash_collection::FLAG_NO_DUMP) ? nullptr :
+ driver_merge ? get_merge_name(*drivlist, *driver, hashes) :
+ get_merge_name(config, device, hashes));
// opening tag
if (is_disk)
@@ -940,16 +1118,16 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
else
out << "\t\t<rom";
- // add name, merge, bios, and size tags */
+ // add name, merge, bios, and size tags
char const *const name(rom->name);
if (name && name[0])
- out << util::string_format(" name=\"%s\"", normalize_string(name));
+ util::stream_format(out, " name=\"%s\"", normalize_string(name));
if (merge_name)
- out << util::string_format(" merge=\"%s\"", normalize_string(merge_name));
+ util::stream_format(out, " merge=\"%s\"", normalize_string(merge_name));
if (bios_name)
- out << util::string_format(" bios=\"%s\"", normalize_string(bios_name));
+ util::stream_format(out, " bios=\"%s\"", normalize_string(bios_name));
if (!is_disk)
- out << util::string_format(" size=\"%u\"", rom_file_size(rom));
+ util::stream_format(out, " size=\"%u\"", rom_file_size(rom));
// dump checksum information only if there is a known dump
if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP))
@@ -958,17 +1136,17 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
out << " status=\"nodump\"";
// append a region name
- out << util::string_format(" region=\"%s\"", region->name);
+ util::stream_format(out, " region=\"%s\"", region->name);
if (!is_disk)
{
// for non-disk entries, print offset
- out << util::string_format(" offset=\"%x\"", ROM_GETOFFSET(rom));
+ util::stream_format(out, " offset=\"%x\"", ROM_GETOFFSET(rom));
}
else
{
// for disk entries, add the disk index
- out << util::string_format(" index=\"%x\" writable=\"%s\"", DISK_GETINDEX(rom), DISK_ISREADONLY(rom) ? "no" : "yes");
+ util::stream_format(out, " index=\"%x\" writable=\"%s\"", DISK_GETINDEX(rom), DISK_ISREADONLY(rom) ? "no" : "yes");
}
// add optional flag
@@ -990,7 +1168,7 @@ void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_drive
void output_sample(std::ostream &out, device_t &device)
{
// iterate over sample devices
- for (samples_device &samples : samples_device_iterator(device))
+ for (samples_device &samples : samples_device_enumerator(device))
{
samples_iterator iter(samples);
std::unordered_set<std::string> already_printed;
@@ -1001,7 +1179,7 @@ void output_sample(std::ostream &out, device_t &device)
continue;
// output the sample name
- out << util::string_format("\t\t<sample name=\"%s\"/>\n", normalize_string(samplename));
+ util::stream_format(out, "\t\t<sample name=\"%s\"/>\n", util::xml::normalize_string(samplename));
}
}
}
@@ -1014,8 +1192,10 @@ void output_sample(std::ostream &out, device_t &device)
void output_chips(std::ostream &out, device_t &device, const char *root_tag)
{
+ using util::xml::normalize_string;
+
// iterate over executable devices
- for (device_execute_interface &exec : execute_interface_iterator(device))
+ for (device_execute_interface &exec : execute_interface_enumerator(device))
{
if (strcmp(exec.device().tag(), device.tag()))
{
@@ -1024,15 +1204,15 @@ void output_chips(std::ostream &out, device_t &device, const char *root_tag)
out << "\t\t<chip";
out << " type=\"cpu\"";
- out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
- out << util::string_format(" name=\"%s\"", normalize_string(exec.device().name()));
- out << util::string_format(" clock=\"%d\"", exec.device().clock());
+ util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
+ util::stream_format(out, " name=\"%s\"", normalize_string(exec.device().name()));
+ util::stream_format(out, " clock=\"%d\"", exec.device().clock());
out << "/>\n";
}
}
// iterate over sound devices
- for (device_sound_interface &sound : sound_interface_iterator(device))
+ for (device_sound_interface &sound : sound_interface_enumerator(device))
{
if (strcmp(sound.device().tag(), device.tag()) != 0 && sound.issound())
{
@@ -1041,10 +1221,10 @@ void output_chips(std::ostream &out, device_t &device, const char *root_tag)
out << "\t\t<chip";
out << " type=\"audio\"";
- out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
- out << util::string_format(" name=\"%s\"", normalize_string(sound.device().name()));
+ util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
+ util::stream_format(out, " name=\"%s\"", normalize_string(sound.device().name()));
if (sound.device().clock() != 0)
- out << util::string_format(" clock=\"%d\"", sound.device().clock());
+ util::stream_format(out, " clock=\"%d\"", sound.device().clock());
out << "/>\n";
}
}
@@ -1059,14 +1239,14 @@ void output_chips(std::ostream &out, device_t &device, const char *root_tag)
void output_display(std::ostream &out, device_t &device, machine_flags::type const *flags, const char *root_tag)
{
// iterate over screens
- for (const screen_device &screendev : screen_device_iterator(device))
+ for (const screen_device &screendev : screen_device_enumerator(device))
{
if (strcmp(screendev.tag(), device.tag()))
{
std::string newtag(screendev.tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
- out << util::string_format("\t\t<display tag=\"%s\"", normalize_string(newtag.c_str()));
+ util::stream_format(out, "\t\t<display tag=\"%s\"", util::xml::normalize_string(newtag));
switch (screendev.screen_type())
{
@@ -1110,12 +1290,12 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
if (screendev.screen_type() != SCREEN_TYPE_VECTOR)
{
const rectangle &visarea = screendev.visible_area();
- out << util::string_format(" width=\"%d\"", visarea.width());
- out << util::string_format(" height=\"%d\"", visarea.height());
+ util::stream_format(out, " width=\"%d\"", visarea.width());
+ util::stream_format(out, " height=\"%d\"", visarea.height());
}
// output refresh rate
- out << util::string_format(" refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds()));
+ util::stream_format(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds()));
// output raw video parameters only for games that are not vector
// and had raw parameters specified
@@ -1123,13 +1303,13 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
{
int pixclock = screendev.width() * screendev.height() * ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds());
- out << util::string_format(" pixclock=\"%d\"", pixclock);
- out << util::string_format(" htotal=\"%d\"", screendev.width());
- out << util::string_format(" hbend=\"%d\"", screendev.visible_area().min_x);
- out << util::string_format(" hbstart=\"%d\"", screendev.visible_area().max_x+1);
- out << util::string_format(" vtotal=\"%d\"", screendev.height());
- out << util::string_format(" vbend=\"%d\"", screendev.visible_area().min_y);
- out << util::string_format(" vbstart=\"%d\"", screendev.visible_area().max_y+1);
+ util::stream_format(out, " pixclock=\"%d\"", pixclock);
+ util::stream_format(out, " htotal=\"%d\"", screendev.width());
+ util::stream_format(out, " hbend=\"%d\"", screendev.visible_area().min_x);
+ util::stream_format(out, " hbstart=\"%d\"", screendev.visible_area().max_x+1);
+ util::stream_format(out, " vtotal=\"%d\"", screendev.height());
+ util::stream_format(out, " vbend=\"%d\"", screendev.visible_area().min_y);
+ util::stream_format(out, " vbstart=\"%d\"", screendev.visible_area().max_y+1);
}
out << " />\n";
}
@@ -1144,15 +1324,15 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
void output_sound(std::ostream &out, device_t &device)
{
- speaker_device_iterator spkiter(device);
+ speaker_device_enumerator spkiter(device);
int speakers = spkiter.count();
// if we have no sound, zero m_output the speaker count
- sound_interface_iterator snditer(device);
+ sound_interface_enumerator snditer(device);
if (snditer.first() == nullptr)
speakers = 0;
- out << util::string_format("\t\t<sound channels=\"%d\"/>\n", speakers);
+ util::stream_format(out, "\t\t<sound channels=\"%d\"/>\n", speakers);
}
@@ -1178,7 +1358,7 @@ void output_ioport_condition(std::ostream &out, const ioport_condition &conditio
case ioport_condition::NOTLESSTHAN: rel = "ge"; break;
}
- out << util::string_format("<condition tag=\"%s\" mask=\"%u\" relation=\"%s\" value=\"%u\"/>\n", normalize_string(condition.tag()), condition.mask(), rel, condition.value());
+ util::stream_format(out, "<condition tag=\"%s\" mask=\"%u\" relation=\"%s\" value=\"%u\"/>\n", util::xml::normalize_string(condition.tag()), condition.mask(), rel, condition.value());
}
//-------------------------------------------------
@@ -1240,14 +1420,14 @@ void output_input(std::ostream &out, const ioport_list &portlist)
int player; // player which the input belongs to
int nbuttons; // total number of buttons
int reqbuttons; // total number of non-optional buttons
- int maxbuttons; // max index of buttons (using IPT_BUTTONn) [probably to be removed soonish]
+ uint32_t maxbuttons; // max index of buttons (using IPT_BUTTONn) [probably to be removed soonish]
int ways; // directions for joystick
bool analog; // is analog input?
- uint8_t helper[3]; // for dual joysticks [possibly to be removed soonish]
- int32_t min; // analog minimum value
- int32_t max; // analog maximum value
- int32_t sensitivity; // default analog sensitivity
- int32_t keydelta; // default analog keydelta
+ uint8_t helper[3]; // for dual joysticks [possibly to be removed soonish]
+ int32_t min; // analog minimum value
+ int32_t max; // analog maximum value
+ int32_t sensitivity; // default analog sensitivity
+ int32_t keydelta; // default analog keydelta
bool reverse; // default analog reverse setting
} control_info[CTRL_COUNT * CTRL_PCOUNT];
@@ -1255,7 +1435,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
// tracking info as we iterate
int nplayer = 0;
- int ncoin = 0;
+ uint32_t ncoin = 0;
bool service = false;
bool tilt = false;
@@ -1264,7 +1444,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
{
int ctrl_type = CTRL_DIGITAL_BUTTONS;
bool ctrl_analog = false;
- for (ioport_field &field : port.second->fields())
+ for (ioport_field const &field : port.second->fields())
{
// track the highest player number
if (nplayer < field.player() + 1)
@@ -1581,37 +1761,39 @@ void output_input(std::ostream &out, const ioport_list &portlist)
// Output the input info
// First basic info
out << "\t\t<input";
- out << util::string_format(" players=\"%d\"", nplayer);
+ util::stream_format(out, " players=\"%d\"", nplayer);
if (ncoin != 0)
- out << util::string_format(" coins=\"%d\"", ncoin);
+ util::stream_format(out, " coins=\"%u\"", ncoin);
if (service)
- out << util::string_format(" service=\"yes\"");
+ util::stream_format(out, " service=\"yes\"");
if (tilt)
- out << util::string_format(" tilt=\"yes\"");
+ util::stream_format(out, " tilt=\"yes\"");
out << ">\n";
// Then controller specific ones
for (auto & elem : control_info)
if (elem.type != nullptr)
{
+ using util::xml::normalize_string;
+
//printf("type %s - player %d - buttons %d\n", elem.type, elem.player, elem.nbuttons);
if (elem.analog)
{
- out << util::string_format("\t\t\t<control type=\"%s\"", normalize_string(elem.type));
+ util::stream_format(out, "\t\t\t<control type=\"%s\"", normalize_string(elem.type));
if (nplayer > 1)
- out << util::string_format(" player=\"%d\"", elem.player);
+ util::stream_format(out, " player=\"%d\"", elem.player);
if (elem.nbuttons > 0)
{
- out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
+ util::stream_format(out, " buttons=\"%u\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
if (elem.reqbuttons < elem.nbuttons)
- out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
+ util::stream_format(out, " reqbuttons=\"%d\"", elem.reqbuttons);
}
if (elem.min != 0 || elem.max != 0)
- out << util::string_format(" minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max);
+ util::stream_format(out, " minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max);
if (elem.sensitivity != 0)
- out << util::string_format(" sensitivity=\"%d\"", elem.sensitivity);
+ util::stream_format(out, " sensitivity=\"%d\"", elem.sensitivity);
if (elem.keydelta != 0)
- out << util::string_format(" keydelta=\"%d\"", elem.keydelta);
+ util::stream_format(out, " keydelta=\"%d\"", elem.keydelta);
if (elem.reverse)
out << " reverse=\"yes\"";
@@ -1623,14 +1805,14 @@ void output_input(std::ostream &out, const ioport_list &portlist)
if (elem.helper[0] == 0 && elem.helper[1] != 0) { elem.helper[0] = elem.helper[1]; elem.helper[1] = 0; }
if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
const char *joys = (elem.helper[2] != 0) ? "triple" : (elem.helper[1] != 0) ? "double" : "";
- out << util::string_format("\t\t\t<control type=\"%s%s\"", joys, normalize_string(elem.type));
+ util::stream_format(out, "\t\t\t<control type=\"%s%s\"", joys, normalize_string(elem.type));
if (nplayer > 1)
- out << util::string_format(" player=\"%d\"", elem.player);
+ util::stream_format(out, " player=\"%d\"", elem.player);
if (elem.nbuttons > 0)
{
- out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
+ util::stream_format(out, " buttons=\"%u\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
if (elem.reqbuttons < elem.nbuttons)
- out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
+ util::stream_format(out, " reqbuttons=\"%d\"", elem.reqbuttons);
}
for (int lp = 0; lp < 3 && elem.helper[lp] != 0; lp++)
{
@@ -1640,7 +1822,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
switch (elem.helper[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
{
case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
- helper = string_format("%d", (elem.ways == 0) ? 8 : elem.ways);
+ helper = util::string_format(std::locale::classic(), "%d", (elem.ways == 0) ? 8 : elem.ways);
ways = helper.c_str();
break;
case DIR_LEFT | DIR_RIGHT:
@@ -1665,7 +1847,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
ways = "strange2";
break;
}
- out << util::string_format(" ways%s=\"%s\"", plural, ways);
+ util::stream_format(out, " ways%s=\"%s\"", plural, ways);
}
out << "/>\n";
}
@@ -1687,20 +1869,23 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
for (ioport_field const &field : port.second->fields())
if (field.type() == type)
{
+ using util::xml::normalize_string;
+
std::string newtag(port.second->tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
// output the switch name information
- std::string const normalized_field_name(normalize_string(field.name()));
- std::string const normalized_newtag(normalize_string(newtag.c_str()));
- out << util::string_format("\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name.c_str(), normalized_newtag.c_str(), field.mask());
+ assert(field.specific_name() != nullptr);
+ std::string const normalized_field_name(normalize_string(field.specific_name()));
+ std::string const normalized_newtag(normalize_string(newtag));
+ util::stream_format(out, "\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name, normalized_newtag, field.mask());
if (!field.condition().none())
output_ioport_condition(out, field.condition(), 3);
// loop over locations
for (ioport_diplocation const &diploc : field.diplocations())
{
- out << util::string_format("\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, normalize_string(diploc.name()), diploc.number());
+ util::stream_format(out, "\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, normalize_string(diploc.name()), diploc.number());
if (diploc.inverted())
out << " inverted=\"yes\"";
out << "/>\n";
@@ -1709,7 +1894,7 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
// loop over settings
for (ioport_setting const &setting : field.settings())
{
- out << util::string_format("\t\t\t<%s name=\"%s\" value=\"%u\"", innertag, normalize_string(setting.name()), setting.value());
+ util::stream_format(out, "\t\t\t<%s name=\"%s\" value=\"%u\"", innertag, normalize_string(setting.name()), setting.value());
if (setting.value() == field.defvalue())
out << " default=\"yes\"";
if (setting.condition().none())
@@ -1720,12 +1905,12 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
{
out << ">\n";
output_ioport_condition(out, setting.condition(), 4);
- out << util::string_format("\t\t\t</%s>\n", innertag);
+ util::stream_format(out, "\t\t\t</%s>\n", innertag);
}
}
// terminate the switch entry
- out << util::string_format("\t\t</%s>\n", outertag);
+ util::stream_format(out, "\t\t</%s>\n", outertag);
}
}
@@ -1738,13 +1923,13 @@ void output_ports(std::ostream &out, const ioport_list &portlist)
// cycle through ports
for (auto &port : portlist)
{
- out << util::string_format("\t\t<port tag=\"%s\">\n", normalize_string(port.second->tag()));
+ util::stream_format(out, "\t\t<port tag=\"%s\">\n", util::xml::normalize_string(port.second->tag()));
for (ioport_field const &field : port.second->fields())
{
if (field.is_analog())
- out << util::string_format("\t\t\t<analog mask=\"%u\"/>\n", field.mask());
+ util::stream_format(out, "\t\t\t<analog mask=\"%u\"/>\n", field.mask());
}
- out << util::string_format("\t\t</port>\n");
+ util::stream_format(out, "\t\t</port>\n");
}
}
@@ -1761,7 +1946,7 @@ void output_adjusters(std::ostream &out, const ioport_list &portlist)
for (ioport_field const &field : port.second->fields())
if (field.type() == IPT_ADJUSTER)
{
- out << util::string_format("\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", normalize_string(field.name()), field.defvalue());
+ util::stream_format(out, "\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", util::xml::normalize_string(field.specific_name()), field.defvalue());
}
}
@@ -1808,6 +1993,18 @@ void output_driver(std::ostream &out, game_driver const &driver, device_t::featu
else
out << " savestate=\"unsupported\"";
+ if (flags & machine_flags::REQUIRES_ARTWORK)
+ out << " requiresartwork=\"yes\"";
+
+ if (flags & machine_flags::UNOFFICIAL)
+ out << " unofficial=\"yes\"";
+
+ if (flags & machine_flags::NO_SOUND_HW)
+ out << " nosoundhardware=\"yes\"";
+
+ if (flags & machine_flags::IS_INCOMPLETE)
+ out << " incomplete=\"yes\"";
+
out << "/>\n";
}
@@ -1824,7 +2021,7 @@ void output_features(std::ostream &out, device_type type, device_t::feature_type
{
if (flags & feature.first)
{
- out << util::string_format("\t\t<feature type=\"%s\"", feature.second);
+ util::stream_format(out, "\t\t<feature type=\"%s\"", feature.second);
if (type.unemulated_features() & feature.first)
{
out << " status=\"unemulated\"";
@@ -1851,20 +2048,23 @@ void output_features(std::ostream &out, device_type type, device_t::feature_type
void output_images(std::ostream &out, device_t &device, const char *root_tag)
{
- for (const device_image_interface &imagedev : image_interface_iterator(device))
+ for (const device_image_interface &imagedev : image_interface_enumerator(device))
{
if (strcmp(imagedev.device().tag(), device.tag()))
{
+ using util::xml::normalize_string;
+
bool loadable = imagedev.user_loadable();
std::string newtag(imagedev.device().tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
// print m_output device type
- out << util::string_format("\t\t<device type=\"%s\"", normalize_string(imagedev.image_type_name()));
+ assert(imagedev.image_type_name() != nullptr);
+ util::stream_format(out, "\t\t<device type=\"%s\"", normalize_string(imagedev.image_type_name()));
// does this device have a tag?
if (imagedev.device().tag())
- out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
+ util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
// is this device available as media switch?
if (!loadable)
@@ -1875,7 +2075,7 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
out << " mandatory=\"1\"";
if (imagedev.image_interface() && imagedev.image_interface()[0])
- out << util::string_format(" interface=\"%s\"", normalize_string(imagedev.image_interface()));
+ util::stream_format(out, " interface=\"%s\"", normalize_string(imagedev.image_interface()));
// close the XML tag
out << ">\n";
@@ -1886,8 +2086,8 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
char const *const shortname = imagedev.brief_instance_name().c_str();
out << "\t\t\t<instance";
- out << util::string_format(" name=\"%s\"", normalize_string(name));
- out << util::string_format(" briefname=\"%s\"", normalize_string(shortname));
+ util::stream_format(out, " name=\"%s\"", normalize_string(name));
+ util::stream_format(out, " briefname=\"%s\"", normalize_string(shortname));
out << "/>\n";
char const *extensions(imagedev.file_extensions());
@@ -1896,7 +2096,7 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
char const *end(extensions);
while (*end && (',' != *end))
++end;
- out << util::string_format("\t\t\t<extension name=\"%s\"/>\n", normalize_string(std::string(extensions, end).c_str()));
+ util::stream_format(out, "\t\t\t<extension name=\"%s\"/>\n", normalize_string(std::string_view(extensions, end - extensions)));
extensions = *end ? (end + 1) : nullptr;
}
}
@@ -1912,20 +2112,22 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
void output_slots(std::ostream &out, machine_config &config, device_t &device, const char *root_tag, device_type_set *devtypes)
{
- for (device_slot_interface &slot : slot_interface_iterator(device))
+ for (device_slot_interface &slot : slot_interface_enumerator(device))
{
// shall we list fixed slots as non-configurable?
bool const listed(!slot.fixed() && strcmp(slot.device().tag(), device.tag()));
if (devtypes || listed)
{
+ using util::xml::normalize_string;
+
machine_config::token const tok(config.begin_configuration(slot.device()));
std::string newtag(slot.device().tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
// print m_output device type
if (listed)
- out << util::string_format("\t\t<slot name=\"%s\">\n", normalize_string(newtag.c_str()));
+ util::stream_format(out, "\t\t<slot name=\"%s\">\n", normalize_string(newtag));
for (auto &option : slot.option_list())
{
@@ -1936,13 +2138,13 @@ void output_slots(std::ostream &out, machine_config &config, device_t &device, c
dev->config_complete();
if (devtypes)
- for (device_t &subdevice : device_iterator(*dev)) devtypes->insert(&subdevice.type());
+ for (device_t &subdevice : device_enumerator(*dev)) devtypes->insert(&subdevice.type());
if (listed && option.second->selectable())
{
- out << util::string_format("\t\t\t<slotoption name=\"%s\"", normalize_string(option.second->name()));
- out << util::string_format(" devname=\"%s\"", normalize_string(dev->shortname()));
- if (slot.default_option() != nullptr && strcmp(slot.default_option(), option.second->name())==0)
+ util::stream_format(out, "\t\t\t<slotoption name=\"%s\"", normalize_string(option.second->name()));
+ util::stream_format(out, " devname=\"%s\"", normalize_string(dev->shortname()));
+ if (slot.default_option() && !strcmp(slot.default_option(), option.second->name()))
out << " default=\"yes\"";
out << "/>\n";
}
@@ -1965,8 +2167,10 @@ void output_slots(std::ostream &out, machine_config &config, device_t &device, c
void output_software_lists(std::ostream &out, device_t &root, const char *root_tag)
{
- for (const software_list_device &swlist : software_list_device_iterator(root))
+ for (const software_list_device &swlist : software_list_device_enumerator(root))
{
+ using util::xml::normalize_string;
+
if (&static_cast<const device_t &>(swlist) == &root)
{
assert(swlist.list_name().empty());
@@ -1975,10 +2179,10 @@ void output_software_lists(std::ostream &out, device_t &root, const char *root_t
std::string newtag(swlist.tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
- out << util::string_format("\t\t<softwarelist tag=\"%s\" name=\"%s\" status=\"%s\"", normalize_string(newtag.c_str()), normalize_string(swlist.list_name().c_str()), swlist.is_original() ? "original" : "compatible");
+ util::stream_format(out, "\t\t<softwarelist tag=\"%s\" name=\"%s\" status=\"%s\"", normalize_string(newtag), normalize_string(swlist.list_name()), swlist.is_original() ? "original" : "compatible");
if (swlist.filter())
- out << util::string_format(" filter=\"%s\"", normalize_string(swlist.filter()));
+ util::stream_format(out, " filter=\"%s\"", normalize_string(swlist.filter()));
out << "/>\n";
}
}
@@ -1992,7 +2196,7 @@ void output_software_lists(std::ostream &out, device_t &root, const char *root_t
void output_ramoptions(std::ostream &out, device_t &root)
{
- for (const ram_device &ram : ram_device_iterator(root, 1))
+ for (const ram_device &ram : ram_device_enumerator(root, 1))
{
if (!std::strcmp(ram.tag(), ":" RAM_TAG))
{
@@ -2004,15 +2208,15 @@ void output_ramoptions(std::ostream &out, device_t &root)
{
assert(!havedefault);
havedefault = true;
- out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
+ util::stream_format(out, "\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", util::xml::normalize_string(option.first), option.second);
}
else
{
- out << util::string_format("\t\t<ramoption name=\"%s\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
+ util::stream_format(out, "\t\t<ramoption name=\"%s\">%u</ramoption>\n", util::xml::normalize_string(option.first), option.second);
}
}
if (!havedefault)
- out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize);
+ util::stream_format(out, "\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize);
break;
}
}
@@ -2024,21 +2228,51 @@ void output_ramoptions(std::ostream &out, device_t &root)
// parent set
//-------------------------------------------------
-const char *get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes)
+char const *get_merge_name(driver_list const &drivlist, game_driver const &driver, util::hash_collection const &romhashes)
{
+ char const *result = nullptr;
+
// walk the parent chain
- for (int clone_of = drivlist.find(driver.parent); 0 <= clone_of; clone_of = drivlist.find(drivlist.driver(clone_of).parent))
+ for (int clone_of = drivlist.find(driver.parent); !result && (0 <= clone_of); clone_of = drivlist.find(drivlist.driver(clone_of).parent))
+ result = get_merge_name(drivlist.driver(clone_of).rom, romhashes);
+
+ return result;
+}
+
+
+char const *get_merge_name(machine_config &config, device_t const &device, util::hash_collection const &romhashes)
+{
+ char const *result = nullptr;
+
+ // check for a parent type
+ auto const parenttype(device.type().parent_rom_device_type());
+ if (parenttype)
{
+ // instantiate the parent device
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ device_t *const parent = config.device_add("_parent", *parenttype, 0);
+
// look in the parent's ROMs
- for (romload::region const &pregion : romload::entries(drivlist.driver(clone_of).rom).get_regions())
+ result = get_merge_name(parent->rom_region(), romhashes);
+
+ // remember to remove the device
+ config.device_remove("_parent");
+ }
+
+ return result;
+}
+
+
+char const *get_merge_name(tiny_rom_entry const *roms, util::hash_collection const &romhashes)
+{
+ for (romload::region const &pregion : romload::entries(roms).get_regions())
+ {
+ for (romload::file const &prom : pregion.get_files())
{
- for (romload::file const &prom : pregion.get_files())
- {
- // stop when we find a match
- util::hash_collection const phashes(prom.get_hashdata());
- if (!phashes.flag(util::hash_collection::FLAG_NO_DUMP) && (romhashes == phashes))
- return prom.get_name();
- }
+ // stop when we find a match
+ util::hash_collection const phashes(prom.get_hashdata());
+ if (!phashes.flag(util::hash_collection::FLAG_NO_DUMP) && (romhashes == phashes))
+ return prom.get_name();
}
}