diff options
Diffstat (limited to 'src/frontend/mame/info.cpp')
-rw-r--r-- | src/frontend/mame/info.cpp | 2022 |
1 files changed, 0 insertions, 2022 deletions
diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp deleted file mode 100644 index b06453c0958..00000000000 --- a/src/frontend/mame/info.cpp +++ /dev/null @@ -1,2022 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles,Paul Priest -/*************************************************************************** - - info.cpp - - Dumps the MAME internal data as an XML file. - -***************************************************************************/ - -#include "emu.h" - -#include "info.h" -#include "mameopts.h" - -#include "machine/ram.h" -#include "sound/samples.h" - -#include "config.h" -#include "drivenum.h" -#include "romload.h" -#include "screen.h" -#include "softlist_dev.h" -#include "speaker.h" - -#include "xmlfile.h" - -#include <ctype.h> -#include <cstring> -#include <unordered_set> -#include <queue> -#include <future> - - -#define XML_ROOT "mame" -#define XML_TOP "machine" - - -//************************************************************************** -// ANONYMOUS NAMESPACE PROTOTYPES -//************************************************************************** - -namespace -{ - class device_type_compare - { - 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); - - // internal helper - void output_header(std::ostream &out, bool dtd); - 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_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); - void output_display(std::ostream &out, device_t &device, machine_flags::type const *flags, const char *root_tag); - void output_sound(std::ostream &out, device_t &device); - void output_ioport_condition(std::ostream &out, const ioport_condition &condition, unsigned indent); - void output_input(std::ostream &out, const ioport_list &portlist); - void output_switches(std::ostream &out, const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *loctag, const char *innertag); - void output_ports(std::ostream &out, const ioport_list &portlist); - void output_adjusters(std::ostream &out, const ioport_list &portlist); - void output_driver(std::ostream &out, game_driver const &driver, device_t::feature_type unemulated, device_t::feature_type imperfect); - void output_features(std::ostream &out, device_type type, device_t::feature_type unemulated, device_t::feature_type imperfect); - 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); - void output_software_list(std::ostream &out, device_t &root); - 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); -}; - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -// DTD string describing the data -static const char s_dtd_string[] = -"<!DOCTYPE __XML_ROOT__ [\n" -"<!ELEMENT __XML_ROOT__ (__XML_TOP__+)>\n" -"\t<!ATTLIST __XML_ROOT__ build CDATA #IMPLIED>\n" -"\t<!ATTLIST __XML_ROOT__ debug (yes|no) \"no\">\n" -"\t<!ATTLIST __XML_ROOT__ mameconfig CDATA #REQUIRED>\n" -"\t<!ELEMENT __XML_TOP__ (description, year?, manufacturer?, biosset*, rom*, disk*, device_ref*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, port*, adjuster*, driver?, feature*, device*, slot*, softwarelist*, ramoption*)>\n" -"\t\t<!ATTLIST __XML_TOP__ name CDATA #REQUIRED>\n" -"\t\t<!ATTLIST __XML_TOP__ sourcefile CDATA #IMPLIED>\n" -"\t\t<!ATTLIST __XML_TOP__ isbios (yes|no) \"no\">\n" -"\t\t<!ATTLIST __XML_TOP__ isdevice (yes|no) \"no\">\n" -"\t\t<!ATTLIST __XML_TOP__ ismechanical (yes|no) \"no\">\n" -"\t\t<!ATTLIST __XML_TOP__ runnable (yes|no) \"yes\">\n" -"\t\t<!ATTLIST __XML_TOP__ cloneof CDATA #IMPLIED>\n" -"\t\t<!ATTLIST __XML_TOP__ romof CDATA #IMPLIED>\n" -"\t\t<!ATTLIST __XML_TOP__ sampleof CDATA #IMPLIED>\n" -"\t\t<!ELEMENT description (#PCDATA)>\n" -"\t\t<!ELEMENT year (#PCDATA)>\n" -"\t\t<!ELEMENT manufacturer (#PCDATA)>\n" -"\t\t<!ELEMENT biosset EMPTY>\n" -"\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n" -"\t\t<!ELEMENT rom EMPTY>\n" -"\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n" -"\t\t\t<!ATTLIST rom optional (yes|no) \"no\">\n" -"\t\t<!ELEMENT disk EMPTY>\n" -"\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST disk writable (yes|no) \"no\">\n" -"\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n" -"\t\t\t<!ATTLIST disk optional (yes|no) \"no\">\n" -"\t\t<!ELEMENT device_ref EMPTY>\n" -"\t\t\t<!ATTLIST device_ref name CDATA #REQUIRED>\n" -"\t\t<!ELEMENT sample EMPTY>\n" -"\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n" -"\t\t<!ELEMENT chip EMPTY>\n" -"\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n" -"\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n" -"\t\t<!ELEMENT display EMPTY>\n" -"\t\t\t<!ATTLIST display tag CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display type (raster|vector|lcd|svg|unknown) #REQUIRED>\n" -"\t\t\t<!ATTLIST display rotate (0|90|180|270) #IMPLIED>\n" -"\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n" -"\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n" -"\t\t<!ELEMENT sound EMPTY>\n" -"\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n" -"\t\t<!ELEMENT condition EMPTY>\n" -"\t\t\t<!ATTLIST condition tag CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST condition mask CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST condition relation (eq|ne|gt|le|lt|ge) #REQUIRED>\n" -"\t\t\t<!ATTLIST condition value CDATA #REQUIRED>\n" -"\t\t<!ELEMENT input (control*)>\n" -"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n" -"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n" -"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n" -"\t\t\t<!ELEMENT control EMPTY>\n" -"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST control player CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control buttons CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control reqbuttons CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n" -"\t\t\t\t<!ATTLIST control ways CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control ways2 CDATA #IMPLIED>\n" -"\t\t\t\t<!ATTLIST control ways3 CDATA #IMPLIED>\n" -"\t\t<!ELEMENT dipswitch (condition?, diplocation*, dipvalue*)>\n" -"\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n" -"\t\t\t<!ELEMENT diplocation EMPTY>\n" -"\t\t\t\t<!ATTLIST diplocation name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST diplocation number CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST diplocation inverted (yes|no) \"no\">\n" -"\t\t\t<!ELEMENT dipvalue (condition?)>\n" -"\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n" -"\t\t<!ELEMENT configuration (condition?, conflocation*, confsetting*)>\n" -"\t\t\t<!ATTLIST configuration name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST configuration tag CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST configuration mask CDATA #REQUIRED>\n" -"\t\t\t<!ELEMENT conflocation EMPTY>\n" -"\t\t\t\t<!ATTLIST conflocation name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST conflocation number CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST conflocation inverted (yes|no) \"no\">\n" -"\t\t\t<!ELEMENT confsetting (condition?)>\n" -"\t\t\t\t<!ATTLIST confsetting name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST confsetting value CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST confsetting default (yes|no) \"no\">\n" -"\t\t<!ELEMENT port (analog*)>\n" -"\t\t\t<!ATTLIST port tag CDATA #REQUIRED>\n" -"\t\t\t<!ELEMENT analog EMPTY>\n" -"\t\t\t\t<!ATTLIST analog mask CDATA #REQUIRED>\n" -"\t\t<!ELEMENT adjuster (condition?)>\n" -"\t\t\t<!ATTLIST adjuster name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST adjuster default CDATA #REQUIRED>\n" -"\t\t<!ELEMENT driver EMPTY>\n" -"\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n" -"\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<!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" -"\t\t\t<!ATTLIST feature overall (unemulated|imperfect) #IMPLIED>\n" -"\t\t<!ELEMENT device (instance?, extension*)>\n" -"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST device fixed_image CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n" -"\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n" -"\t\t\t<!ELEMENT instance EMPTY>\n" -"\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n" -"\t\t\t<!ELEMENT extension EMPTY>\n" -"\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n" -"\t\t<!ELEMENT slot (slotoption*)>\n" -"\t\t\t<!ATTLIST slot name CDATA #REQUIRED>\n" -"\t\t\t<!ELEMENT slotoption EMPTY>\n" -"\t\t\t\t<!ATTLIST slotoption name CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST slotoption devname CDATA #REQUIRED>\n" -"\t\t\t\t<!ATTLIST slotoption default (yes|no) \"no\">\n" -"\t\t<!ELEMENT softwarelist EMPTY>\n" -"\t\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST softwarelist status (original|compatible) #REQUIRED>\n" -"\t\t\t<!ATTLIST softwarelist filter CDATA #IMPLIED>\n" -"\t\t<!ELEMENT ramoption (#PCDATA)>\n" -"\t\t\t<!ATTLIST ramoption name CDATA #REQUIRED>\n" -"\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n" -"]>"; - - -//************************************************************************** -// INFO XML CREATOR -//************************************************************************** - -//------------------------------------------------- -// info_xml_creator - constructor -//------------------------------------------------- - -info_xml_creator::info_xml_creator(emu_options const &options, bool dtd) - : m_dtd(dtd) -{ -} - - -//------------------------------------------------- -// output - print the XML information for all -// known machines matching a pattern -//------------------------------------------------- - -void info_xml_creator::output(std::ostream &out, const std::vector<std::string> &patterns) -{ - if (patterns.empty()) - { - // no patterns specified - show everything - output(out); - } - 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; - auto it = matched.begin(); - for (const std::string &pat : patterns) - { - if (!core_strwildcmp(pat.c_str(), shortname)) - { - // 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++; - } - return result; - }; - output(out, filter); - - // throw an error if there were unmatched patterns - auto iter = std::find(matched.begin(), matched.end(), false); - if (iter != matched.end()) - { - 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(std::ostream &out, const std::function<bool(const char *shortname, bool &done)> &filter, bool include_devices) -{ - struct prepared_info - { - 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; - 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; - } - }; - - // only keep a device set when we're asked to track it - std::unique_ptr<device_type_set> devfilter; - if (include_devices && filter) - devfilter = std::make_unique<device_type_set>(); - - // prepare a queue of futures - std::queue<std::future<prepared_info>> queue; - - // try enumerating drivers and outputting them - while (!queue.empty() || (!drivlist_done && !filter_done)) - { - // try populating the queue - while (queue.size() < 20 && !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 || 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)); - } - } - - // now that we have the queue populated, try grabbing one (assuming that it is not empty) - if (!queue.empty()) - { - // wait for the future to complete and get the info - prepared_info pi = queue.front().get(); - queue.pop(); - - // emit the XML - output_header_if_necessary(out); - out << pi.m_xml_snippet; - - // merge devices into devfilter, if appropriate - if (devfilter) - { - for (const auto &x : pi.m_dev_set) - devfilter->insert(x); - } - } - } - - // iterate through the device types if not everything matches a driver - if (devfilter && !filter_done) - { - for (device_type type : registered_device_types) - { - if (!filter || filter(type.shortname(), filter_done)) - devfilter->insert(&type); - - if (filter_done) - break; - } - } - - // output devices (both devices with roms and slot devices) - if (include_devices && (!devfilter || !devfilter->empty())) - { - output_header_if_necessary(out); - output_devices(out, m_lookup_options, devfilter.get()); - } - - if (header_outputted) - output_footer(out); -} - - -//************************************************************************** -// ANONYMOUS NAMESPACE IMPLEMENTATION -//************************************************************************** - -namespace -{ - -//------------------------------------------------- -// normalize_string -//------------------------------------------------- - -std::string normalize_string(const char *string) -{ - std::ostringstream stream; - - if (string != nullptr) - { - while (*string) - { - switch (*string) - { - case '\"': stream << """; break; - case '&': stream << "&"; break; - case '<': stream << "<"; break; - case '>': stream << ">"; break; - default: - stream << *string; - break; - } - ++string; - } - } - return stream.str(); -} - - -//------------------------------------------------- -// output_header - print the XML DTD and open -// the root element -//------------------------------------------------- - -void output_header(std::ostream &out, bool dtd) -{ - if (dtd) - { - // output the DTD - out << "<?xml version=\"1.0\"?>\n"; - std::string dtd(s_dtd_string); - strreplace(dtd, "__XML_ROOT__", XML_ROOT); - strreplace(dtd, "__XML_TOP__", XML_TOP); - - out << dtd << "\n\n"; - } - - // top-level tag - out << util::string_format("<%s build=\"%s\" debug=\"" -#ifdef MAME_DEBUG - "yes" -#else - "no" -#endif - "\" mameconfig=\"%d\">\n", - XML_ROOT, - normalize_string(emulator_info::get_build_version()), - CONFIG_VERSION); -} - - -//------------------------------------------------- -// output_header - close the root element -//------------------------------------------------- - -void output_footer(std::ostream &out) -{ - // close the top level tag - out << util::string_format("</%s>\n", XML_ROOT); -} - - -//------------------------------------------------- -// output_one - print the XML information -// for one particular machine driver -//------------------------------------------------- - -void output_one(std::ostream &out, driver_enumerator &drivlist, const game_driver &driver, device_type_set *devtypes) -{ - machine_config config(driver, drivlist.options()); - device_iterator iter(config.root_device()); - - // allocate input ports and build overall emulation status - ioport_list portlist; - std::string errors; - device_t::feature_type overall_unemulated(driver.type.unemulated_features()); - device_t::feature_type overall_imperfect(driver.type.imperfect_features()); - for (device_t &device : iter) - { - portlist.append(device, errors); - overall_unemulated |= device.type().unemulated_features(); - overall_imperfect |= device.type().imperfect_features(); - - if (devtypes && device.owner()) - devtypes->insert(&device.type()); - } - - // renumber player numbers for controller ports - int player_offset = 0; - // but treat keyboard count separately from players' number - int kbd_offset = 0; - for (device_t &device : iter) - { - int nplayers = 0; - bool new_kbd = false; - for (auto &port : portlist) - if (&port.second->device() == &device) - for (ioport_field &field : port.second->fields()) - if (field.type() >= IPT_START && field.type() < IPT_ANALOG_LAST) - { - if (field.type() == IPT_KEYBOARD) - { - if (!new_kbd) - new_kbd = true; - field.set_player(field.player() + kbd_offset); - } - else - { - nplayers = std::max(nplayers, field.player() + 1); - field.set_player(field.player() + player_offset); - } - } - player_offset += nplayers; - if (new_kbd) kbd_offset++; - } - - // print the header and the machine name - out << util::string_format("\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)); - - // append bios and runnable flags - if (driver.flags & machine_flags::IS_BIOS_ROOT) - out << " isbios=\"yes\""; - if (driver.flags & machine_flags::MECHANICAL) - out << " ismechanical=\"yes\""; - - // 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)); - if (clone_of != -1) - out << util::string_format(" romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name)); - - // display sample information and close the game tag - output_sampleof(out, config.root_device()); - out << ">\n"; - - // output game description - if (driver.type.fullname() != nullptr) - out << util::string_format("\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)); - - // print the manufacturer information - if (driver.manufacturer != nullptr) - out << util::string_format("\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_device_refs(out, config.root_device()); - output_sample(out, config.root_device()); - output_chips(out, config.root_device(), ""); - output_display(out, config.root_device(), &driver.flags, ""); - output_sound(out, config.root_device()); - output_input(out, portlist); - output_switches(out, portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue"); - output_switches(out, portlist, "", IPT_CONFIG, "configuration", "conflocation", "confsetting"); - output_ports(out, portlist); - output_adjusters(out, portlist); - output_driver(out, driver, overall_unemulated, overall_imperfect); - output_features(out, driver.type, overall_unemulated, overall_imperfect); - output_images(out, config.root_device(), ""); - output_slots(out, config, config.root_device(), "", devtypes); - output_software_list(out, config.root_device()); - output_ramoptions(out, config.root_device()); - - // close the topmost tag - out << util::string_format("\t</%s>\n", XML_TOP); -} - - -//------------------------------------------------- -// output_one_device - print the XML info for -// a single device -//------------------------------------------------- - -void output_one_device(std::ostream &out, machine_config &config, device_t &device, const char *devtag) -{ - bool has_speaker = false, has_input = false; - // check if the device adds speakers to the system - sound_interface_iterator snditer(device); - if (snditer.first() != nullptr) - has_speaker = true; - - // generate input list and build overall emulation status - ioport_list portlist; - 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)) - { - portlist.append(dev, errors); - overall_unemulated |= dev.type().unemulated_features(); - overall_imperfect |= dev.type().imperfect_features(); - } - - // check if the device adds player inputs (other than dsw and configs) to the system - for (auto &port : portlist) - for (ioport_field const &field : port.second->fields()) - if (field.type() >= IPT_START1 && field.type() < IPT_UI_FIRST) - { - has_input = true; - break; - } - - // 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())); - output_sampleof(out, device); - out << ">\n" << util::string_format("\t\t<description>%s</description>\n", normalize_string(device.name())); - - output_bios(out, device); - output_rom(out, nullptr, nullptr, device); - output_device_refs(out, device); - - if (device.type().type() != typeid(samples_device)) // ignore samples_device itself - output_sample(out, device); - - output_chips(out, device, devtag); - output_display(out, device, nullptr, devtag); - if (has_speaker) - output_sound(out, device); - if (has_input) - output_input(out, portlist); - output_switches(out, portlist, devtag, IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue"); - output_switches(out, portlist, devtag, IPT_CONFIG, "configuration", "conflocation", "confsetting"); - output_adjusters(out, portlist); - output_features(out, device.type(), overall_unemulated, overall_imperfect); - output_images(out, device, devtag); - output_slots(out, config, device, devtag, nullptr); - out << util::string_format("\t</%s>\n", XML_TOP); -} - - -//------------------------------------------------- -// output_devices - print the XML info for -// registered device types -//------------------------------------------------- - -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) - { - // 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_iterator(*dev)) - if (!device.configured()) - device.config_complete(); - - // 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"); - }; - - // run through devices - if (filter) - { - for (std::add_pointer_t<device_type> type : *filter) action(*type); - } - else - { - for (device_type type : registered_device_types) action(type); - } -} - - -//------------------------------------------------ -// output_device_refs - when a machine uses a -// subdevice, print a reference -//------------------------------------------------- - -void output_device_refs(std::ostream &out, device_t &root) -{ - for (device_t &device : device_iterator(root)) - if (&device != &root) - out << util::string_format("\t\t<device_ref name=\"%s\"/>\n", normalize_string(device.shortname())); -} - - -//------------------------------------------------ -// output_sampleof - print the 'sampleof' -// attribute, if appropriate -//------------------------------------------------- - -void output_sampleof(std::ostream &out, device_t &device) -{ - // iterate over sample devices - for (samples_device &samples : samples_device_iterator(device)) - { - samples_iterator sampiter(samples); - if (sampiter.altbasename() != nullptr) - { - out << util::string_format(" sampleof=\"%s\"", normalize_string(sampiter.altbasename())); - - // must stop here, as there can only be one attribute of the same name - return; - } - } -} - - -//------------------------------------------------- -// output_bios - print BIOS sets for a device -//------------------------------------------------- - -void output_bios(std::ostream &out, device_t const &device) -{ - // first determine the default BIOS name - char const *defaultname(nullptr); - for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom) - { - if (ROMENTRY_ISDEFAULT_BIOS(rom)) - defaultname = rom->name; - } - - // iterate over ROM entries and look for BIOSes - for (romload::system_bios const &bios : romload::entries(device.rom_region()).get_system_bioses()) - { - // 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())); - if (defaultname && !std::strcmp(defaultname, bios.get_name())) - out << " default=\"yes\""; - out << "/>\n"; - } -} - - -//------------------------------------------------- -// output_rom - print the roms section of -// the XML output -//------------------------------------------------- - -void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_driver *driver, device_t &device) -{ - enum class type { BIOS, NORMAL, DISK }; - std::map<u32, char const *> biosnames; - bool bios_scanned(false); - auto const get_biosname = - [&biosnames, &bios_scanned] (tiny_rom_entry const *rom) -> char const * - { - u32 const biosflags(ROM_GETBIOSFLAGS(rom)); - std::map<u32, char const *>::const_iterator const found(biosnames.find(biosflags)); - if (biosnames.end() != found) - return found->second; - - char const *result(nullptr); - if (!bios_scanned) - { - for (++rom; !ROMENTRY_ISEND(rom); ++rom) - { - if (ROMENTRY_ISSYSTEM_BIOS(rom)) - { - u32 const biosno(ROM_GETBIOSFLAGS(rom)); - biosnames.emplace(biosno, rom->name); - if (biosflags == biosno) - result = rom->name; - } - } - bios_scanned = true; - } - return result; - }; - auto const rom_file_size = // FIXME: need a common way to do this without the cost of allocating rom_entry - [] (tiny_rom_entry const *romp) -> u32 - { - u32 maxlength = 0; - - // loop until we run out of reloads - do - { - // loop until we run out of continues/ignores */ - u32 curlength(ROM_GETLENGTH(romp++)); - while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)) - curlength += ROM_GETLENGTH(romp++); - - // track the maximum length - maxlength = (std::max)(maxlength, curlength); - } - while (ROMENTRY_ISRELOAD(romp)); - - return maxlength; - }; - - // iterate over 3 different ROM "types": BIOS, ROMs, DISKs - bool const do_merge_name = 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) - { - if (ROMENTRY_ISREGION(rom)) - region = rom; - else if (ROMENTRY_ISSYSTEM_BIOS(rom)) - biosnames.emplace(ROM_GETBIOSFLAGS(rom), rom->name); - - if (!ROMENTRY_ISFILE(rom)) - continue; - - // only list disks on the disk pass - bool const is_disk = ROMREGION_ISDISKDATA(region); - if ((type::DISK == pass) != is_disk) - continue; - - // 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)) - continue; - char const *const bios_name((!is_disk && biosno) ? get_biosname(rom) : nullptr); - - // 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); - - // opening tag - if (is_disk) - out << "\t\t<disk"; - else - out << "\t\t<rom"; - - // 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)); - if (merge_name) - out << util::string_format(" merge=\"%s\"", normalize_string(merge_name)); - if (bios_name) - out << util::string_format(" bios=\"%s\"", normalize_string(bios_name)); - if (!is_disk) - out << util::string_format(" 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)) - out << ' ' << hashes.attribute_string(); // iterate over hash function types and print m_output their values - else - out << " status=\"nodump\""; - - // append a region name - out << util::string_format(" region=\"%s\"", region->name); - - if (!is_disk) - { - // for non-disk entries, print offset - out << util::string_format(" 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"); - } - - // add optional flag - if (ROM_ISOPTIONAL(rom)) - out << " optional=\"yes\""; - - out << "/>\n"; - } - bios_scanned = true; - } -} - - -//------------------------------------------------- -// output_sample - print a list of all -// samples referenced by a game_driver -//------------------------------------------------- - -void output_sample(std::ostream &out, device_t &device) -{ - // iterate over sample devices - for (samples_device &samples : samples_device_iterator(device)) - { - samples_iterator iter(samples); - std::unordered_set<std::string> already_printed; - for (const char *samplename = iter.first(); samplename != nullptr; samplename = iter.next()) - { - // filter out duplicates - if (!already_printed.insert(samplename).second) - continue; - - // output the sample name - out << util::string_format("\t\t<sample name=\"%s\"/>\n", normalize_string(samplename)); - } - } -} - - -/*------------------------------------------------- - output_chips - print a list of CPU and - sound chips used by a game --------------------------------------------------*/ - -void output_chips(std::ostream &out, device_t &device, const char *root_tag) -{ - // iterate over executable devices - for (device_execute_interface &exec : execute_interface_iterator(device)) - { - if (strcmp(exec.device().tag(), device.tag())) - { - std::string newtag(exec.device().tag()), oldtag(":"); - newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length()); - - 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()); - out << "/>\n"; - } - } - - // iterate over sound devices - for (device_sound_interface &sound : sound_interface_iterator(device)) - { - if (strcmp(sound.device().tag(), device.tag()) != 0 && sound.issound()) - { - std::string newtag(sound.device().tag()), oldtag(":"); - newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length()); - - 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())); - if (sound.device().clock() != 0) - out << util::string_format(" clock=\"%d\"", sound.device().clock()); - out << "/>\n"; - } - } -} - - -//------------------------------------------------- -// output_display - print a list of all the -// displays -//------------------------------------------------- - -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)) - { - 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())); - - switch (screendev.screen_type()) - { - case SCREEN_TYPE_RASTER: out << " type=\"raster\""; break; - case SCREEN_TYPE_VECTOR: out << " type=\"vector\""; break; - case SCREEN_TYPE_LCD: out << " type=\"lcd\""; break; - case SCREEN_TYPE_SVG: out << " type=\"svg\""; break; - default: out << " type=\"unknown\""; break; - } - - // output the orientation as a string - switch (screendev.orientation()) - { - case ORIENTATION_FLIP_X: - out << " rotate=\"0\" flipx=\"yes\""; - break; - case ORIENTATION_FLIP_Y: - out << " rotate=\"180\" flipx=\"yes\""; - break; - case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - out << " rotate=\"180\""; - break; - case ORIENTATION_SWAP_XY: - out << " rotate=\"90\" flipx=\"yes\""; - break; - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: - out << " rotate=\"90\""; - break; - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: - out << " rotate=\"270\""; - break; - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - out << " rotate=\"270\" flipx=\"yes\""; - break; - default: - out << " rotate=\"0\""; - break; - } - - // output width and height only for games that are not vector - 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()); - } - - // output refresh rate - out << util::string_format(" refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds())); - - // output raw video parameters only for games that are not vector - // and had raw parameters specified - if (screendev.screen_type() != SCREEN_TYPE_VECTOR && !screendev.oldstyle_vblank_supplied()) - { - 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); - } - out << " />\n"; - } - } -} - - -//------------------------------------------------- -// output_sound - print a list of all the -// speakers -//------------------------------------------------ - -void output_sound(std::ostream &out, device_t &device) -{ - speaker_device_iterator spkiter(device); - int speakers = spkiter.count(); - - // if we have no sound, zero m_output the speaker count - sound_interface_iterator snditer(device); - if (snditer.first() == nullptr) - speakers = 0; - - out << util::string_format("\t\t<sound channels=\"%d\"/>\n", speakers); -} - - -//------------------------------------------------- -// output_ioport_condition - print condition -// required to use I/O port field/setting -//------------------------------------------------- - -void output_ioport_condition(std::ostream &out, const ioport_condition &condition, unsigned indent) -{ - for (unsigned i = 0; indent > i; ++i) - out << '\t'; - - char const *rel(nullptr); - switch (condition.condition()) - { - case ioport_condition::ALWAYS: throw false; - case ioport_condition::EQUALS: rel = "eq"; break; - case ioport_condition::NOTEQUALS: rel = "ne"; break; - case ioport_condition::GREATERTHAN: rel = "gt"; break; - case ioport_condition::NOTGREATERTHAN: rel = "le"; break; - case ioport_condition::LESSTHAN: rel = "lt"; break; - 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()); -} - -//------------------------------------------------- -// output_input - print a summary of a game's -// input -//------------------------------------------------- - -void output_input(std::ostream &out, const ioport_list &portlist) -{ - // enumerated list of control types - // NOTE: the order is chosen so that 'spare' button inputs are assigned to the - // most-likely-correct input device when info is output (you can think of it as - // a sort of likelihood order of having buttons) - enum - { - CTRL_DIGITAL_BUTTONS, - CTRL_DIGITAL_JOYSTICK, - CTRL_ANALOG_JOYSTICK, - CTRL_ANALOG_LIGHTGUN, - CTRL_ANALOG_DIAL, - CTRL_ANALOG_POSITIONAL, - CTRL_ANALOG_TRACKBALL, - CTRL_ANALOG_MOUSE, - CTRL_ANALOG_PADDLE, - CTRL_ANALOG_PEDAL, - CTRL_DIGITAL_KEYPAD, - CTRL_DIGITAL_KEYBOARD, - CTRL_DIGITAL_MAHJONG, - CTRL_DIGITAL_HANAFUDA, - CTRL_DIGITAL_GAMBLING, - CTRL_COUNT - }; - - enum - { - CTRL_P1, - CTRL_P2, - CTRL_P3, - CTRL_P4, - CTRL_P5, - CTRL_P6, - CTRL_P7, - CTRL_P8, - CTRL_P9, - CTRL_P10, - CTRL_PCOUNT - }; - - // directions - const uint8_t DIR_UP = 0x01; - const uint8_t DIR_DOWN = 0x02; - const uint8_t DIR_LEFT = 0x04; - const uint8_t DIR_RIGHT = 0x08; - - // initialize the list of control types - struct - { - const char * type; // general type of input - 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] - 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 - bool reverse; // default analog reverse setting - } control_info[CTRL_COUNT * CTRL_PCOUNT]; - - memset(&control_info, 0, sizeof(control_info)); - - // tracking info as we iterate - int nplayer = 0; - int ncoin = 0; - bool service = false; - bool tilt = false; - - // iterate over the ports - for (auto &port : portlist) - { - int ctrl_type = CTRL_DIGITAL_BUTTONS; - bool ctrl_analog = false; - for (ioport_field &field : port.second->fields()) - { - // track the highest player number - if (nplayer < field.player() + 1) - nplayer = field.player() + 1; - - // switch off of the type - switch (field.type()) - { - // map joysticks - case IPT_JOYSTICK_UP: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_UP; - break; - case IPT_JOYSTICK_DOWN: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_DOWN; - break; - case IPT_JOYSTICK_LEFT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_LEFT; - break; - case IPT_JOYSTICK_RIGHT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_RIGHT; - break; - - case IPT_JOYSTICKLEFT_UP: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_UP; - break; - case IPT_JOYSTICKLEFT_DOWN: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_DOWN; - break; - case IPT_JOYSTICKLEFT_LEFT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_LEFT; - break; - case IPT_JOYSTICKLEFT_RIGHT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_RIGHT; - break; - - case IPT_JOYSTICKRIGHT_UP: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_UP; - break; - case IPT_JOYSTICKRIGHT_DOWN: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_DOWN; - break; - case IPT_JOYSTICKRIGHT_LEFT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_LEFT; - break; - case IPT_JOYSTICKRIGHT_RIGHT: - ctrl_type = CTRL_DIGITAL_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way(); - control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_RIGHT; - break; - - // map analog inputs - case IPT_AD_STICK_X: - case IPT_AD_STICK_Y: - case IPT_AD_STICK_Z: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_JOYSTICK; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "stick"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_PADDLE: - case IPT_PADDLE_V: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_PADDLE; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "paddle"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_PEDAL: - case IPT_PEDAL2: - case IPT_PEDAL3: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_PEDAL; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "pedal"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_LIGHTGUN_X: - case IPT_LIGHTGUN_Y: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_LIGHTGUN; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "lightgun"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_POSITIONAL: - case IPT_POSITIONAL_V: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_POSITIONAL; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "positional"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_DIAL: - case IPT_DIAL_V: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_DIAL; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "dial"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_TRACKBALL_X: - case IPT_TRACKBALL_Y: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_TRACKBALL; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "trackball"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - case IPT_MOUSE_X: - case IPT_MOUSE_Y: - ctrl_analog = true; - ctrl_type = CTRL_ANALOG_MOUSE; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mouse"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true; - break; - - // map buttons - case IPT_BUTTON1: - case IPT_BUTTON2: - case IPT_BUTTON3: - case IPT_BUTTON4: - case IPT_BUTTON5: - case IPT_BUTTON6: - case IPT_BUTTON7: - case IPT_BUTTON8: - case IPT_BUTTON9: - case IPT_BUTTON10: - case IPT_BUTTON11: - case IPT_BUTTON12: - case IPT_BUTTON13: - case IPT_BUTTON14: - case IPT_BUTTON15: - case IPT_BUTTON16: - ctrl_analog = false; - if (control_info[field.player() * CTRL_COUNT + ctrl_type].type == nullptr) - { - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "only_buttons"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].analog = false; - } - control_info[field.player() * CTRL_COUNT + ctrl_type].maxbuttons = std::max(control_info[field.player() * CTRL_COUNT + ctrl_type].maxbuttons, field.type() - IPT_BUTTON1 + 1); - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - break; - - // track maximum coin index - case IPT_COIN1: - case IPT_COIN2: - case IPT_COIN3: - case IPT_COIN4: - case IPT_COIN5: - case IPT_COIN6: - case IPT_COIN7: - case IPT_COIN8: - case IPT_COIN9: - case IPT_COIN10: - case IPT_COIN11: - case IPT_COIN12: - ncoin = std::max(ncoin, field.type() - IPT_COIN1 + 1); - break; - - // track presence of keypads and keyboards - case IPT_KEYPAD: - ctrl_type = CTRL_DIGITAL_KEYPAD; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keypad"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - break; - - case IPT_KEYBOARD: - ctrl_type = CTRL_DIGITAL_KEYBOARD; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keyboard"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - break; - - // additional types - case IPT_SERVICE: - service = true; - break; - - case IPT_TILT: - tilt = true; - break; - - default: - if (field.type() > IPT_MAHJONG_FIRST && field.type() < IPT_MAHJONG_LAST) - { - ctrl_type = CTRL_DIGITAL_MAHJONG; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mahjong"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - } - else if (field.type() > IPT_HANAFUDA_FIRST && field.type() < IPT_HANAFUDA_LAST) - { - ctrl_type = CTRL_DIGITAL_HANAFUDA; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "hanafuda"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - } - else if (field.type() > IPT_GAMBLING_FIRST && field.type() < IPT_GAMBLING_LAST) - { - ctrl_type = CTRL_DIGITAL_GAMBLING; - control_info[field.player() * CTRL_COUNT + ctrl_type].type = "gambling"; - control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1; - control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++; - if (!field.optional()) - control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++; - } - break; - } - - if (ctrl_analog) - { - // get the analog stats - if (field.minval() != 0) - control_info[field.player() * CTRL_COUNT + ctrl_type].min = field.minval(); - if (field.maxval() != 0) - control_info[field.player() * CTRL_COUNT + ctrl_type].max = field.maxval(); - if (field.sensitivity() != 0) - control_info[field.player() * CTRL_COUNT + ctrl_type].sensitivity = field.sensitivity(); - if (field.delta() != 0) - control_info[field.player() * CTRL_COUNT + ctrl_type].keydelta = field.delta(); - if (field.analog_reverse() != 0) - control_info[field.player() * CTRL_COUNT + ctrl_type].reverse = true; - } - } - } - - // Clean-up those entries, if any, where buttons were defined in a separate port than the actual controller they belong to. - // This is quite often the case, especially for arcades where controls can be easily mapped to separate input ports on PCB. - // If such situation would only happen for joystick, it would be possible to work it around by initializing differently - // ctrl_type above, but it is quite common among analog inputs as well (for instance, this is the tipical situation - // for lightguns) and therefore we really need this separate loop. - for (int i = 0; i < CTRL_PCOUNT; i++) - { - bool fix_done = false; - for (int j = 1; j < CTRL_COUNT; j++) - if (control_info[i * CTRL_COUNT].type != nullptr && control_info[i * CTRL_COUNT + j].type != nullptr && !fix_done) - { - control_info[i * CTRL_COUNT + j].nbuttons += control_info[i * CTRL_COUNT].nbuttons; - control_info[i * CTRL_COUNT + j].reqbuttons += control_info[i * CTRL_COUNT].reqbuttons; - control_info[i * CTRL_COUNT + j].maxbuttons = std::max(control_info[i * CTRL_COUNT + j].maxbuttons, control_info[i * CTRL_COUNT].maxbuttons); - - memset(&control_info[i * CTRL_COUNT], 0, sizeof(control_info[0])); - fix_done = true; - } - } - - // Output the input info - // First basic info - out << "\t\t<input"; - out << util::string_format(" players=\"%d\"", nplayer); - if (ncoin != 0) - out << util::string_format(" coins=\"%d\"", ncoin); - if (service) - out << util::string_format(" service=\"yes\""); - if (tilt) - out << util::string_format(" tilt=\"yes\""); - out << ">\n"; - - // Then controller specific ones - for (auto & elem : control_info) - if (elem.type != nullptr) - { - //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)); - if (nplayer > 1) - out << util::string_format(" player=\"%d\"", elem.player); - if (elem.nbuttons > 0) - { - out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons); - if (elem.reqbuttons < elem.nbuttons) - out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons); - } - if (elem.min != 0 || elem.max != 0) - out << util::string_format(" minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max); - if (elem.sensitivity != 0) - out << util::string_format(" sensitivity=\"%d\"", elem.sensitivity); - if (elem.keydelta != 0) - out << util::string_format(" keydelta=\"%d\"", elem.keydelta); - if (elem.reverse) - out << " reverse=\"yes\""; - - out << "/>\n"; - } - else - { - if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; } - 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)); - if (nplayer > 1) - out << util::string_format(" player=\"%d\"", elem.player); - if (elem.nbuttons > 0) - { - out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons); - if (elem.reqbuttons < elem.nbuttons) - out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons); - } - for (int lp = 0; lp < 3 && elem.helper[lp] != 0; lp++) - { - const char *plural = (lp==2) ? "3" : (lp==1) ? "2" : ""; - const char *ways; - std::string helper; - 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); - ways = helper.c_str(); - break; - case DIR_LEFT | DIR_RIGHT: - ways = "2"; - break; - case DIR_UP | DIR_DOWN: - ways = "vertical2"; - break; - case DIR_UP: - case DIR_DOWN: - case DIR_LEFT: - case DIR_RIGHT: - ways = "1"; - break; - case DIR_UP | DIR_DOWN | DIR_LEFT: - case DIR_UP | DIR_DOWN | DIR_RIGHT: - case DIR_UP | DIR_LEFT | DIR_RIGHT: - case DIR_DOWN | DIR_LEFT | DIR_RIGHT: - ways = (elem.ways == 4) ? "3 (half4)" : "5 (half8)"; - break; - default: - ways = "strange2"; - break; - } - out << util::string_format(" ways%s=\"%s\"", plural, ways); - } - out << "/>\n"; - } - } - - out << "\t\t</input>\n"; -} - - -//------------------------------------------------- -// output_switches - print the configurations or -// DIP switch settings -//------------------------------------------------- - -void output_switches(std::ostream &out, const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *loctag, const char *innertag) -{ - // iterate looking for DIP switches - for (auto &port : portlist) - for (ioport_field const &field : port.second->fields()) - if (field.type() == type) - { - 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()); - 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()); - if (diploc.inverted()) - out << " inverted=\"yes\""; - out << "/>\n"; - } - - // 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()); - if (setting.value() == field.defvalue()) - out << " default=\"yes\""; - if (setting.condition().none()) - { - out << "/>\n"; - } - else - { - out << ">\n"; - output_ioport_condition(out, setting.condition(), 4); - out << util::string_format("\t\t\t</%s>\n", innertag); - } - } - - // terminate the switch entry - out << util::string_format("\t\t</%s>\n", outertag); - } -} - -//------------------------------------------------- -// output_ports - print the structure of input -// ports in the driver -//------------------------------------------------- -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())); - 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()); - } - out << util::string_format("\t\t</port>\n"); - } - -} - -//------------------------------------------------- -// output_adjusters - print the Analog -// Adjusters for a game -//------------------------------------------------- - -void output_adjusters(std::ostream &out, const ioport_list &portlist) -{ - // iterate looking for Adjusters - for (auto &port : 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()); - } -} - - -//------------------------------------------------- -// output_driver - print driver status -//------------------------------------------------- - -void output_driver(std::ostream &out, game_driver const &driver, device_t::feature_type unemulated, device_t::feature_type imperfect) -{ - out << "\t\t<driver"; - - /* - The status entry is an hint for frontend authors to select working - and not working games without the need to know all the other status - entries. Games marked as status=good are perfectly emulated, games - marked as status=imperfect are emulated with only some minor issues, - games marked as status=preliminary don't work or have major - emulation problems. - */ - - u32 const flags = driver.flags; - bool const machine_preliminary(flags & (machine_flags::NOT_WORKING | machine_flags::MECHANICAL)); - bool const unemulated_preliminary(unemulated & (device_t::feature::PALETTE | device_t::feature::GRAPHICS | device_t::feature::SOUND | device_t::feature::KEYBOARD)); - bool const imperfect_preliminary((unemulated | imperfect) & device_t::feature::PROTECTION); - - if (machine_preliminary || unemulated_preliminary || imperfect_preliminary) - out << " status=\"preliminary\""; - else if (imperfect) - out << " status=\"imperfect\""; - else - out << " status=\"good\""; - - if (flags & machine_flags::NOT_WORKING) - out << " emulation=\"preliminary\""; - else - out << " emulation=\"good\""; - - if (flags & machine_flags::NO_COCKTAIL) - out << " cocktail=\"preliminary\""; - - if (flags & machine_flags::SUPPORTS_SAVE) - out << " savestate=\"supported\""; - else - out << " savestate=\"unsupported\""; - - out << "/>\n"; -} - - -//------------------------------------------------- -// output_features - print emulation features of -// -//------------------------------------------------- - -void output_features(std::ostream &out, device_type type, device_t::feature_type unemulated, device_t::feature_type imperfect) -{ - static constexpr std::pair<device_t::feature_type, char const *> features[] = { - { device_t::feature::PROTECTION, "protection" }, - { device_t::feature::TIMING, "timing" }, - { device_t::feature::GRAPHICS, "graphics" }, - { device_t::feature::PALETTE, "palette" }, - { device_t::feature::SOUND, "sound" }, - { device_t::feature::CAPTURE, "capture" }, - { device_t::feature::CAMERA, "camera" }, - { device_t::feature::MICROPHONE, "microphone" }, - { device_t::feature::CONTROLS, "controls" }, - { device_t::feature::KEYBOARD, "keyboard" }, - { device_t::feature::MOUSE, "mouse" }, - { device_t::feature::MEDIA, "media" }, - { device_t::feature::DISK, "disk" }, - { device_t::feature::PRINTER, "printer" }, - { device_t::feature::TAPE, "tape" }, - { device_t::feature::PUNCH, "punch" }, - { device_t::feature::DRUM, "drum" }, - { device_t::feature::ROM, "rom" }, - { device_t::feature::COMMS, "comms" }, - { device_t::feature::LAN, "lan" }, - { device_t::feature::WAN, "wan" } }; - - device_t::feature_type const flags(type.unemulated_features() | type.imperfect_features() | unemulated | imperfect); - for (auto const &feature : features) - { - if (flags & feature.first) - { - out << util::string_format("\t\t<feature type=\"%s\"", feature.second); - if (type.unemulated_features() & feature.first) - { - out << " status=\"unemulated\""; - } - else - { - if (type.imperfect_features() & feature.first) - out << " status=\"imperfect\""; - if (unemulated & feature.first) - out << " overall=\"unemulated\""; - else if ((~type.imperfect_features() & imperfect) & feature.first) - out << " overall=\"imperfect\""; - } - out << "/>\n"; - } - } -} - - -//------------------------------------------------- -// output_images - prints m_output all info on -// image devices -//------------------------------------------------- - -void output_images(std::ostream &out, device_t &device, const char *root_tag) -{ - for (const device_image_interface &imagedev : image_interface_iterator(device)) - { - if (strcmp(imagedev.device().tag(), device.tag())) - { - 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())); - - // does this device have a tag? - if (imagedev.device().tag()) - out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str())); - - // is this device available as media switch? - if (!loadable) - out << " fixed_image=\"1\""; - - // is this device mandatory? - if (imagedev.must_be_loaded()) - out << " mandatory=\"1\""; - - if (imagedev.image_interface() && imagedev.image_interface()[0]) - out << util::string_format(" interface=\"%s\"", normalize_string(imagedev.image_interface())); - - // close the XML tag - out << ">\n"; - - if (loadable) - { - char const *const name = imagedev.instance_name().c_str(); - 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)); - out << "/>\n"; - - char const *extensions(imagedev.file_extensions()); - while (extensions) - { - 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())); - extensions = *end ? (end + 1) : nullptr; - } - } - out << "\t\t</device>\n"; - } - } -} - - -//------------------------------------------------- -// output_slots - prints all info about slots -//------------------------------------------------- - -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)) - { - // shall we list fixed slots as non-configurable? - bool const listed(!slot.fixed() && strcmp(slot.device().tag(), device.tag())); - - if (devtypes || listed) - { - 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())); - - for (auto &option : slot.option_list()) - { - if (devtypes || (listed && option.second->selectable())) - { - device_t *const dev = config.device_add("_dummy", option.second->devtype(), option.second->clock()); - if (!dev->configured()) - dev->config_complete(); - - if (devtypes) - for (device_t &subdevice : device_iterator(*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) - out << " default=\"yes\""; - out << "/>\n"; - } - - config.device_remove("_dummy"); - } - } - - if (listed) - out << "\t\t</slot>\n"; - } - } -} - - -//------------------------------------------------- -// output_software_list - print the information -// for all known software lists for this system -//------------------------------------------------- - -void output_software_list(std::ostream &out, device_t &root) -{ - for (const software_list_device &swlist : software_list_device_iterator(root)) - { - out << util::string_format("\t\t<softwarelist name=\"%s\" status=\"%s\"", normalize_string(swlist.list_name().c_str()), (swlist.list_type() == SOFTWARE_LIST_ORIGINAL_SYSTEM) ? "original" : "compatible"); - if (swlist.filter()) - out << util::string_format(" filter=\"%s\"", normalize_string(swlist.filter())); - out << "/>\n"; - } -} - - - -//------------------------------------------------- -// output_ramoptions - prints m_output all RAM -// options for this system -//------------------------------------------------- - -void output_ramoptions(std::ostream &out, device_t &root) -{ - for (const ram_device &ram : ram_device_iterator(root, 1)) - { - if (!std::strcmp(ram.tag(), ":" RAM_TAG)) - { - uint32_t const defsize(ram.default_size()); - bool havedefault(false); - for (ram_device::extra_option const &option : ram.extra_options()) - { - if (defsize == option.second) - { - 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); - } - else - { - out << util::string_format("\t\t<ramoption name=\"%s\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second); - } - } - if (!havedefault) - out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize); - break; - } - } -} - - -//------------------------------------------------- -// get_merge_name - get the rom name from a -// parent set -//------------------------------------------------- - -const char *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(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()) - { - 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(); - } - } - } - - return nullptr; -} - - -//------------------------------------------------- -// device_type_compare::operator() -//------------------------------------------------- - -bool device_type_compare::operator()(const std::add_pointer_t<device_type> &lhs, const std::add_pointer_t<device_type> &rhs) const -{ - return strcmp(lhs->shortname(), rhs->shortname()) < 0; -} - -} |