1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles,Paul Priest
3 /***************************************************************************
4 
5     info.cpp
6 
7     Dumps the MAME internal data as an XML file.
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "infoxml.h"
13 
14 #include "mameopts.h"
15 
16 #include "machine/ram.h"
17 #include "sound/samples.h"
18 
19 #include "config.h"
20 #include "drivenum.h"
21 #include "romload.h"
22 #include "screen.h"
23 #include "softlist_dev.h"
24 #include "speaker.h"
25 
26 #include "xmlfile.h"
27 
28 #include <algorithm>
29 #include <cctype>
30 #include <cstring>
31 #include <future>
32 #include <queue>
33 #include <type_traits>
34 #include <unordered_set>
35 #include <utility>
36 
37 
38 #define XML_ROOT    "mame"
39 #define XML_TOP     "machine"
40 
41 
42 namespace {
43 
44 //**************************************************************************
45 //  ANONYMOUS NAMESPACE PROTOTYPES
46 //**************************************************************************
47 
48 class device_type_compare
49 {
50 public:
51 	bool operator()(const std::add_pointer_t<device_type> &lhs, const std::add_pointer_t<device_type> &rhs) const;
52 };
53 
54 typedef std::set<std::add_pointer_t<device_type>, device_type_compare> device_type_set;
55 
56 std::string normalize_string(const char *string);
57 
58 // internal helper
59 void output_header(std::ostream &out, bool dtd);
60 void output_footer(std::ostream &out);
61 
62 void output_one(std::ostream &out, driver_enumerator &drivlist, const game_driver &driver, device_type_set *devtypes);
63 void output_sampleof(std::ostream &out, device_t &device);
64 void output_bios(std::ostream &out, device_t const &device);
65 void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_driver *driver, device_t &device);
66 void output_device_refs(std::ostream &out, device_t &root);
67 void output_sample(std::ostream &out, device_t &device);
68 void output_chips(std::ostream &out, device_t &device, const char *root_tag);
69 void output_display(std::ostream &out, device_t &device, machine_flags::type const *flags, const char *root_tag);
70 void output_sound(std::ostream &out, device_t &device);
71 void output_ioport_condition(std::ostream &out, const ioport_condition &condition, unsigned indent);
72 void output_input(std::ostream &out, const ioport_list &portlist);
73 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);
74 void output_ports(std::ostream &out, const ioport_list &portlist);
75 void output_adjusters(std::ostream &out, const ioport_list &portlist);
76 void output_driver(std::ostream &out, game_driver const &driver, device_t::feature_type unemulated, device_t::feature_type imperfect);
77 void output_features(std::ostream &out, device_type type, device_t::feature_type unemulated, device_t::feature_type imperfect);
78 void output_images(std::ostream &out, device_t &device, const char *root_tag);
79 void output_slots(std::ostream &out, machine_config &config, device_t &device, const char *root_tag, device_type_set *devtypes);
80 void output_software_lists(std::ostream &out, device_t &root, const char *root_tag);
81 void output_ramoptions(std::ostream &out, device_t &root);
82 
83 void output_one_device(std::ostream &out, machine_config &config, device_t &device, const char *devtag);
84 void output_devices(std::ostream &out, emu_options &lookup_options, device_type_set const *filter);
85 
86 const char *get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes);
87 
88 
89 //**************************************************************************
90 //  GLOBAL VARIABLES
91 //**************************************************************************
92 
93 // DTD string describing the data
94 constexpr char f_dtd_string[] =
95 		"<!DOCTYPE __XML_ROOT__ [\n"
96 		"<!ELEMENT __XML_ROOT__ (__XML_TOP__+)>\n"
97 		"\t<!ATTLIST __XML_ROOT__ build CDATA #IMPLIED>\n"
98 		"\t<!ATTLIST __XML_ROOT__ debug (yes|no) \"no\">\n"
99 		"\t<!ATTLIST __XML_ROOT__ mameconfig CDATA #REQUIRED>\n"
100 		"\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"
101 		"\t\t<!ATTLIST __XML_TOP__ name CDATA #REQUIRED>\n"
102 		"\t\t<!ATTLIST __XML_TOP__ sourcefile CDATA #IMPLIED>\n"
103 		"\t\t<!ATTLIST __XML_TOP__ isbios (yes|no) \"no\">\n"
104 		"\t\t<!ATTLIST __XML_TOP__ isdevice (yes|no) \"no\">\n"
105 		"\t\t<!ATTLIST __XML_TOP__ ismechanical (yes|no) \"no\">\n"
106 		"\t\t<!ATTLIST __XML_TOP__ runnable (yes|no) \"yes\">\n"
107 		"\t\t<!ATTLIST __XML_TOP__ cloneof CDATA #IMPLIED>\n"
108 		"\t\t<!ATTLIST __XML_TOP__ romof CDATA #IMPLIED>\n"
109 		"\t\t<!ATTLIST __XML_TOP__ sampleof CDATA #IMPLIED>\n"
110 		"\t\t<!ELEMENT description (#PCDATA)>\n"
111 		"\t\t<!ELEMENT year (#PCDATA)>\n"
112 		"\t\t<!ELEMENT manufacturer (#PCDATA)>\n"
113 		"\t\t<!ELEMENT biosset EMPTY>\n"
114 		"\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n"
115 		"\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n"
116 		"\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n"
117 		"\t\t<!ELEMENT rom EMPTY>\n"
118 		"\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n"
119 		"\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n"
120 		"\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n"
121 		"\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n"
122 		"\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n"
123 		"\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n"
124 		"\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n"
125 		"\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n"
126 		"\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n"
127 		"\t\t\t<!ATTLIST rom optional (yes|no) \"no\">\n"
128 		"\t\t<!ELEMENT disk EMPTY>\n"
129 		"\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n"
130 		"\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n"
131 		"\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n"
132 		"\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n"
133 		"\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n"
134 		"\t\t\t<!ATTLIST disk writable (yes|no) \"no\">\n"
135 		"\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n"
136 		"\t\t\t<!ATTLIST disk optional (yes|no) \"no\">\n"
137 		"\t\t<!ELEMENT device_ref EMPTY>\n"
138 		"\t\t\t<!ATTLIST device_ref name CDATA #REQUIRED>\n"
139 		"\t\t<!ELEMENT sample EMPTY>\n"
140 		"\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n"
141 		"\t\t<!ELEMENT chip EMPTY>\n"
142 		"\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n"
143 		"\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n"
144 		"\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n"
145 		"\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n"
146 		"\t\t<!ELEMENT display EMPTY>\n"
147 		"\t\t\t<!ATTLIST display tag CDATA #IMPLIED>\n"
148 		"\t\t\t<!ATTLIST display type (raster|vector|lcd|svg|unknown) #REQUIRED>\n"
149 		"\t\t\t<!ATTLIST display rotate (0|90|180|270) #IMPLIED>\n"
150 		"\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n"
151 		"\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n"
152 		"\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n"
153 		"\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n"
154 		"\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n"
155 		"\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n"
156 		"\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n"
157 		"\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n"
158 		"\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n"
159 		"\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n"
160 		"\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n"
161 		"\t\t<!ELEMENT sound EMPTY>\n"
162 		"\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n"
163 		"\t\t<!ELEMENT condition EMPTY>\n"
164 		"\t\t\t<!ATTLIST condition tag CDATA #REQUIRED>\n"
165 		"\t\t\t<!ATTLIST condition mask CDATA #REQUIRED>\n"
166 		"\t\t\t<!ATTLIST condition relation (eq|ne|gt|le|lt|ge) #REQUIRED>\n"
167 		"\t\t\t<!ATTLIST condition value CDATA #REQUIRED>\n"
168 		"\t\t<!ELEMENT input (control*)>\n"
169 		"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n"
170 		"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n"
171 		"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n"
172 		"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n"
173 		"\t\t\t<!ELEMENT control EMPTY>\n"
174 		"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n"
175 		"\t\t\t\t<!ATTLIST control player CDATA #IMPLIED>\n"
176 		"\t\t\t\t<!ATTLIST control buttons CDATA #IMPLIED>\n"
177 		"\t\t\t\t<!ATTLIST control reqbuttons CDATA #IMPLIED>\n"
178 		"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n"
179 		"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n"
180 		"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n"
181 		"\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n"
182 		"\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n"
183 		"\t\t\t\t<!ATTLIST control ways CDATA #IMPLIED>\n"
184 		"\t\t\t\t<!ATTLIST control ways2 CDATA #IMPLIED>\n"
185 		"\t\t\t\t<!ATTLIST control ways3 CDATA #IMPLIED>\n"
186 		"\t\t<!ELEMENT dipswitch (condition?, diplocation*, dipvalue*)>\n"
187 		"\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n"
188 		"\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n"
189 		"\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n"
190 		"\t\t\t<!ELEMENT diplocation EMPTY>\n"
191 		"\t\t\t\t<!ATTLIST diplocation name CDATA #REQUIRED>\n"
192 		"\t\t\t\t<!ATTLIST diplocation number CDATA #REQUIRED>\n"
193 		"\t\t\t\t<!ATTLIST diplocation inverted (yes|no) \"no\">\n"
194 		"\t\t\t<!ELEMENT dipvalue (condition?)>\n"
195 		"\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n"
196 		"\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n"
197 		"\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n"
198 		"\t\t<!ELEMENT configuration (condition?, conflocation*, confsetting*)>\n"
199 		"\t\t\t<!ATTLIST configuration name CDATA #REQUIRED>\n"
200 		"\t\t\t<!ATTLIST configuration tag CDATA #REQUIRED>\n"
201 		"\t\t\t<!ATTLIST configuration mask CDATA #REQUIRED>\n"
202 		"\t\t\t<!ELEMENT conflocation EMPTY>\n"
203 		"\t\t\t\t<!ATTLIST conflocation name CDATA #REQUIRED>\n"
204 		"\t\t\t\t<!ATTLIST conflocation number CDATA #REQUIRED>\n"
205 		"\t\t\t\t<!ATTLIST conflocation inverted (yes|no) \"no\">\n"
206 		"\t\t\t<!ELEMENT confsetting (condition?)>\n"
207 		"\t\t\t\t<!ATTLIST confsetting name CDATA #REQUIRED>\n"
208 		"\t\t\t\t<!ATTLIST confsetting value CDATA #REQUIRED>\n"
209 		"\t\t\t\t<!ATTLIST confsetting default (yes|no) \"no\">\n"
210 		"\t\t<!ELEMENT port (analog*)>\n"
211 		"\t\t\t<!ATTLIST port tag CDATA #REQUIRED>\n"
212 		"\t\t\t<!ELEMENT analog EMPTY>\n"
213 		"\t\t\t\t<!ATTLIST analog mask CDATA #REQUIRED>\n"
214 		"\t\t<!ELEMENT adjuster (condition?)>\n"
215 		"\t\t\t<!ATTLIST adjuster name CDATA #REQUIRED>\n"
216 		"\t\t\t<!ATTLIST adjuster default CDATA #REQUIRED>\n"
217 		"\t\t<!ELEMENT driver EMPTY>\n"
218 		"\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n"
219 		"\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n"
220 		"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
221 		"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
222 		"\t\t<!ELEMENT feature EMPTY>\n"
223 		"\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"
224 		"\t\t\t<!ATTLIST feature status (unemulated|imperfect) #IMPLIED>\n"
225 		"\t\t\t<!ATTLIST feature overall (unemulated|imperfect) #IMPLIED>\n"
226 		"\t\t<!ELEMENT device (instance?, extension*)>\n"
227 		"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n"
228 		"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n"
229 		"\t\t\t<!ATTLIST device fixed_image CDATA #IMPLIED>\n"
230 		"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n"
231 		"\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n"
232 		"\t\t\t<!ELEMENT instance EMPTY>\n"
233 		"\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n"
234 		"\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n"
235 		"\t\t\t<!ELEMENT extension EMPTY>\n"
236 		"\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n"
237 		"\t\t<!ELEMENT slot (slotoption*)>\n"
238 		"\t\t\t<!ATTLIST slot name CDATA #REQUIRED>\n"
239 		"\t\t\t<!ELEMENT slotoption EMPTY>\n"
240 		"\t\t\t\t<!ATTLIST slotoption name CDATA #REQUIRED>\n"
241 		"\t\t\t\t<!ATTLIST slotoption devname CDATA #REQUIRED>\n"
242 		"\t\t\t\t<!ATTLIST slotoption default (yes|no) \"no\">\n"
243 		"\t\t<!ELEMENT softwarelist EMPTY>\n"
244 		"\t\t\t<!ATTLIST softwarelist tag CDATA #REQUIRED>\n"
245 		"\t\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n"
246 		"\t\t\t<!ATTLIST softwarelist status (original|compatible) #REQUIRED>\n"
247 		"\t\t\t<!ATTLIST softwarelist filter CDATA #IMPLIED>\n"
248 		"\t\t<!ELEMENT ramoption (#PCDATA)>\n"
249 		"\t\t\t<!ATTLIST ramoption name CDATA #REQUIRED>\n"
250 		"\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\n"
251 		"]>";
252 
253 
254 // XML feature names
255 constexpr std::pair<device_t::feature_type, char const *> f_feature_names[] = {
256 		{ device_t::feature::PROTECTION,    "protection"    },
257 		{ device_t::feature::TIMING,        "timing"        },
258 		{ device_t::feature::GRAPHICS,      "graphics"      },
259 		{ device_t::feature::PALETTE,       "palette"       },
260 		{ device_t::feature::SOUND,         "sound"         },
261 		{ device_t::feature::CAPTURE,       "capture"       },
262 		{ device_t::feature::CAMERA,        "camera"        },
263 		{ device_t::feature::MICROPHONE,    "microphone"    },
264 		{ device_t::feature::CONTROLS,      "controls"      },
265 		{ device_t::feature::KEYBOARD,      "keyboard"      },
266 		{ device_t::feature::MOUSE,         "mouse"         },
267 		{ device_t::feature::MEDIA,         "media"         },
268 		{ device_t::feature::DISK,          "disk"          },
269 		{ device_t::feature::PRINTER,       "printer"       },
270 		{ device_t::feature::TAPE,          "tape"          },
271 		{ device_t::feature::PUNCH,         "punch"         },
272 		{ device_t::feature::DRUM,          "drum"          },
273 		{ device_t::feature::ROM,           "rom"           },
274 		{ device_t::feature::COMMS,         "comms"         },
275 		{ device_t::feature::LAN,           "lan"           },
276 		{ device_t::feature::WAN,           "wan"           } };
277 
278 } // anonymous namespace
279 
280 
281 //**************************************************************************
282 //  INFO XML CREATOR
283 //**************************************************************************
284 
285 
286 //-------------------------------------------------
287 //  get_feature_name - get XML name for feature
288 //-------------------------------------------------
289 
feature_name(device_t::feature_type feature)290 char const *info_xml_creator::feature_name(device_t::feature_type feature)
291 {
292 	auto const found = std::lower_bound(
293 			std::begin(f_feature_names),
294 			std::end(f_feature_names),
295 			std::underlying_type_t<device_t::feature_type>(feature),
296 			[] (auto const &a, auto const &b)
297 			{
298 				return std::underlying_type_t<device_t::feature_type>(a.first) < b;
299 			});
300 	return ((std::end(f_feature_names) != found) && (found->first == feature)) ? found->second : nullptr;
301 }
302 
303 
304 //-------------------------------------------------
305 //  info_xml_creator - constructor
306 //-------------------------------------------------
307 
info_xml_creator(emu_options const & options,bool dtd)308 info_xml_creator::info_xml_creator(emu_options const &options, bool dtd)
309 	: m_dtd(dtd)
310 {
311 }
312 
313 
314 //-------------------------------------------------
315 //  output - print the XML information for all
316 //  known machines matching a pattern
317 //-------------------------------------------------
318 
output(std::ostream & out,const std::vector<std::string> & patterns)319 void info_xml_creator::output(std::ostream &out, const std::vector<std::string> &patterns)
320 {
321 	if (patterns.empty())
322 	{
323 		// no patterns specified - show everything
324 		output(out);
325 	}
326 	else
327 	{
328 		// patterns specified - we have to filter output
329 		std::vector<bool> matched(patterns.size(), false);
330 		size_t exact_matches = 0;
331 		const auto filter = [&patterns, &matched, &exact_matches](const char *shortname, bool &done) -> bool
332 		{
333 			bool result = false;
334 			auto it = matched.begin();
335 			for (const std::string &pat : patterns)
336 			{
337 				if (!core_strwildcmp(pat.c_str(), shortname))
338 				{
339 					// this driver matches the pattern - tell the caller
340 					result = true;
341 
342 					// did we see this particular pattern before?  if not, track that we have
343 					if (!*it)
344 					{
345 						*it = true;
346 						if (!core_iswildstr(pat.c_str()))
347 						{
348 							exact_matches++;
349 
350 							// stop looking if we found everything specified
351 							if (exact_matches == patterns.size())
352 								done = true;
353 						}
354 					}
355 				}
356 				it++;
357 			}
358 			return result;
359 		};
360 		output(out, filter);
361 
362 		// throw an error if there were unmatched patterns
363 		auto iter = std::find(matched.begin(), matched.end(), false);
364 		if (iter != matched.end())
365 		{
366 			int index = iter - matched.begin();
367 			throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching machines found for '%s'", patterns[index].c_str());
368 		}
369 	}
370 }
371 
372 
373 //-------------------------------------------------
374 //  output - print the XML information for all
375 //  known (and filtered) machines
376 //-------------------------------------------------
377 
output(std::ostream & out,const std::function<bool (const char * shortname,bool & done)> & filter,bool include_devices)378 void info_xml_creator::output(std::ostream &out, const std::function<bool(const char *shortname, bool &done)> &filter, bool include_devices)
379 {
380 	struct prepared_info
381 	{
382 		std::string     m_xml_snippet;
383 		device_type_set m_dev_set;
384 	};
385 
386 	// prepare a driver enumerator and the queue
387 	driver_enumerator drivlist(m_lookup_options);
388 	bool drivlist_done = false;
389 	bool filter_done = false;
390 	bool header_outputted = false;
391 
392 	auto output_header_if_necessary = [this, &header_outputted](std::ostream &out)
393 	{
394 		if (!header_outputted)
395 		{
396 			output_header(out, m_dtd);
397 			header_outputted = true;
398 		}
399 	};
400 
401 	// only keep a device set when we're asked to track it
402 	std::unique_ptr<device_type_set> devfilter;
403 	if (include_devices && filter)
404 		devfilter = std::make_unique<device_type_set>();
405 
406 	// prepare a queue of futures
407 	std::queue<std::future<prepared_info>> queue;
408 
409 	// try enumerating drivers and outputting them
410 	while (!queue.empty() || (!drivlist_done && !filter_done))
411 	{
412 		// try populating the queue
413 		while (queue.size() < 20 && !drivlist_done && !filter_done)
414 		{
415 			if (!drivlist.next())
416 			{
417 				// at this point we are done enumerating through drivlist and it is no
418 				// longer safe to call next(), so record that we're done
419 				drivlist_done = true;
420 			}
421 			else if (!filter || filter(drivlist.driver().name, filter_done))
422 			{
423 				const game_driver &driver(drivlist.driver());
424 				std::future<prepared_info> future_pi = std::async(std::launch::async, [&drivlist, &driver, &devfilter]
425 				{
426 					prepared_info result;
427 					std::ostringstream stream;
428 
429 					output_one(stream, drivlist, driver, devfilter ? &result.m_dev_set : nullptr);
430 					result.m_xml_snippet = stream.str();
431 					return result;
432 				});
433 				queue.push(std::move(future_pi));
434 			}
435 		}
436 
437 		// now that we have the queue populated, try grabbing one (assuming that it is not empty)
438 		if (!queue.empty())
439 		{
440 			// wait for the future to complete and get the info
441 			prepared_info pi = queue.front().get();
442 			queue.pop();
443 
444 			// emit the XML
445 			output_header_if_necessary(out);
446 			out << pi.m_xml_snippet;
447 
448 			// merge devices into devfilter, if appropriate
449 			if (devfilter)
450 			{
451 				for (const auto &x : pi.m_dev_set)
452 					devfilter->insert(x);
453 			}
454 		}
455 	}
456 
457 	// iterate through the device types if not everything matches a driver
458 	if (devfilter && !filter_done)
459 	{
460 		for (device_type type : registered_device_types)
461 		{
462 			if (!filter || filter(type.shortname(), filter_done))
463 				devfilter->insert(&type);
464 
465 			if (filter_done)
466 				break;
467 		}
468 	}
469 
470 	// output devices (both devices with roms and slot devices)
471 	if (include_devices && (!devfilter || !devfilter->empty()))
472 	{
473 		output_header_if_necessary(out);
474 		output_devices(out, m_lookup_options, devfilter.get());
475 	}
476 
477 	if (header_outputted)
478 		output_footer(out);
479 }
480 
481 
482 //**************************************************************************
483 //  ANONYMOUS NAMESPACE IMPLEMENTATION
484 //**************************************************************************
485 
486 namespace
487 {
488 
489 //-------------------------------------------------
490 //  normalize_string
491 //-------------------------------------------------
492 
normalize_string(const char * string)493 std::string normalize_string(const char *string)
494 {
495 	std::ostringstream stream;
496 
497 	if (string != nullptr)
498 	{
499 		while (*string)
500 		{
501 			switch (*string)
502 			{
503 			case '\"': stream << "&quot;"; break;
504 			case '&': stream << "&amp;"; break;
505 			case '<': stream << "&lt;"; break;
506 			case '>': stream << "&gt;"; break;
507 			default:
508 				stream << *string;
509 				break;
510 			}
511 			++string;
512 		}
513 	}
514 	return stream.str();
515 }
516 
517 
518 //-------------------------------------------------
519 //  output_header - print the XML DTD and open
520 //  the root element
521 //-------------------------------------------------
522 
output_header(std::ostream & out,bool dtd)523 void output_header(std::ostream &out, bool dtd)
524 {
525 	if (dtd)
526 	{
527 		// output the DTD
528 		out << "<?xml version=\"1.0\"?>\n";
529 		std::string dtd(f_dtd_string);
530 		strreplace(dtd, "__XML_ROOT__", XML_ROOT);
531 		strreplace(dtd, "__XML_TOP__", XML_TOP);
532 
533 		out << dtd << "\n\n";
534 	}
535 
536 	// top-level tag
537 	out << util::string_format("<%s build=\"%s\" debug=\""
538 #ifdef MAME_DEBUG
539 			"yes"
540 #else
541 			"no"
542 #endif
543 			"\" mameconfig=\"%d\">\n",
544 			XML_ROOT,
545 			normalize_string(emulator_info::get_build_version()),
546 			CONFIG_VERSION);
547 }
548 
549 
550 //-------------------------------------------------
551 //  output_header - close the root element
552 //-------------------------------------------------
553 
output_footer(std::ostream & out)554 void output_footer(std::ostream &out)
555 {
556 	// close the top level tag
557 	out << util::string_format("</%s>\n", XML_ROOT);
558 }
559 
560 
561 //-------------------------------------------------
562 //  output_one - print the XML information
563 //  for one particular machine driver
564 //-------------------------------------------------
565 
output_one(std::ostream & out,driver_enumerator & drivlist,const game_driver & driver,device_type_set * devtypes)566 void output_one(std::ostream &out, driver_enumerator &drivlist, const game_driver &driver, device_type_set *devtypes)
567 {
568 	machine_config config(driver, drivlist.options());
569 	device_iterator iter(config.root_device());
570 
571 	// allocate input ports and build overall emulation status
572 	ioport_list portlist;
573 	std::string errors;
574 	device_t::feature_type overall_unemulated(driver.type.unemulated_features());
575 	device_t::feature_type overall_imperfect(driver.type.imperfect_features());
576 	for (device_t &device : iter)
577 	{
578 		portlist.append(device, errors);
579 		overall_unemulated |= device.type().unemulated_features();
580 		overall_imperfect |= device.type().imperfect_features();
581 
582 		if (devtypes && device.owner())
583 			devtypes->insert(&device.type());
584 	}
585 
586 	// renumber player numbers for controller ports
587 	int player_offset = 0;
588 	// but treat keyboard count separately from players' number
589 	int kbd_offset = 0;
590 	for (device_t &device : iter)
591 	{
592 		int nplayers = 0;
593 		bool new_kbd = false;
594 		for (auto &port : portlist)
595 			if (&port.second->device() == &device)
596 				for (ioport_field &field : port.second->fields())
597 					if (field.type() >= IPT_START && field.type() < IPT_ANALOG_LAST)
598 					{
599 						if (field.type() == IPT_KEYBOARD)
600 						{
601 							if (!new_kbd)
602 								new_kbd = true;
603 							field.set_player(field.player() + kbd_offset);
604 						}
605 						else
606 						{
607 							nplayers = std::max(nplayers, field.player() + 1);
608 							field.set_player(field.player() + player_offset);
609 						}
610 					}
611 		player_offset += nplayers;
612 		if (new_kbd) kbd_offset++;
613 	}
614 
615 	// print the header and the machine name
616 	out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(driver.name));
617 
618 	// strip away any path information from the source_file and output it
619 	const char *start = strrchr(driver.type.source(), '/');
620 	if (!start)
621 		start = strrchr(driver.type.source(), '\\');
622 	start = start ? (start + 1) : driver.type.source();
623 	out << util::string_format(" sourcefile=\"%s\"", normalize_string(start));
624 
625 	// append bios and runnable flags
626 	if (driver.flags & machine_flags::IS_BIOS_ROOT)
627 		out << " isbios=\"yes\"";
628 	if (driver.flags & machine_flags::MECHANICAL)
629 		out << " ismechanical=\"yes\"";
630 
631 	// display clone information
632 	int clone_of = drivlist.find(driver.parent);
633 	if (clone_of != -1 && !(drivlist.driver(clone_of).flags & machine_flags::IS_BIOS_ROOT))
634 		out << util::string_format(" cloneof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
635 	if (clone_of != -1)
636 		out << util::string_format(" romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
637 
638 	// display sample information and close the game tag
639 	output_sampleof(out, config.root_device());
640 	out << ">\n";
641 
642 	// output game description
643 	if (driver.type.fullname() != nullptr)
644 		out << util::string_format("\t\t<description>%s</description>\n", normalize_string(driver.type.fullname()));
645 
646 	// print the year only if is a number or another allowed character (? or +)
647 	if (driver.year != nullptr && strspn(driver.year, "0123456789?+") == strlen(driver.year))
648 		out << util::string_format("\t\t<year>%s</year>\n", normalize_string(driver.year));
649 
650 	// print the manufacturer information
651 	if (driver.manufacturer != nullptr)
652 		out << util::string_format("\t\t<manufacturer>%s</manufacturer>\n", normalize_string(driver.manufacturer));
653 
654 	// now print various additional information
655 	output_bios(out, config.root_device());
656 	output_rom(out, &drivlist, &driver, config.root_device());
657 	output_device_refs(out, config.root_device());
658 	output_sample(out, config.root_device());
659 	output_chips(out, config.root_device(), "");
660 	output_display(out, config.root_device(), &driver.flags, "");
661 	output_sound(out, config.root_device());
662 	output_input(out, portlist);
663 	output_switches(out, portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
664 	output_switches(out, portlist, "", IPT_CONFIG, "configuration", "conflocation", "confsetting");
665 	output_ports(out, portlist);
666 	output_adjusters(out, portlist);
667 	output_driver(out, driver, overall_unemulated, overall_imperfect);
668 	output_features(out, driver.type, overall_unemulated, overall_imperfect);
669 	output_images(out, config.root_device(), "");
670 	output_slots(out, config, config.root_device(), "", devtypes);
671 	output_software_lists(out, config.root_device(), "");
672 	output_ramoptions(out, config.root_device());
673 
674 	// close the topmost tag
675 	out << util::string_format("\t</%s>\n", XML_TOP);
676 }
677 
678 
679 //-------------------------------------------------
680 //  output_one_device - print the XML info for
681 //  a single device
682 //-------------------------------------------------
683 
output_one_device(std::ostream & out,machine_config & config,device_t & device,const char * devtag)684 void output_one_device(std::ostream &out, machine_config &config, device_t &device, const char *devtag)
685 {
686 	bool has_speaker = false, has_input = false;
687 	// check if the device adds speakers to the system
688 	sound_interface_iterator snditer(device);
689 	if (snditer.first() != nullptr)
690 		has_speaker = true;
691 
692 	// generate input list and build overall emulation status
693 	ioport_list portlist;
694 	std::string errors;
695 	device_t::feature_type overall_unemulated(device.type().unemulated_features());
696 	device_t::feature_type overall_imperfect(device.type().imperfect_features());
697 	for (device_t &dev : device_iterator(device))
698 	{
699 		portlist.append(dev, errors);
700 		overall_unemulated |= dev.type().unemulated_features();
701 		overall_imperfect |= dev.type().imperfect_features();
702 	}
703 
704 	// check if the device adds player inputs (other than dsw and configs) to the system
705 	for (auto &port : portlist)
706 		for (ioport_field const &field : port.second->fields())
707 			if (field.type() >= IPT_START1 && field.type() < IPT_UI_FIRST)
708 			{
709 				has_input = true;
710 				break;
711 			}
712 
713 	// start to output info
714 	out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(device.shortname()));
715 	std::string src(device.source());
716 	strreplace(src,"../", "");
717 	out << util::string_format(" sourcefile=\"%s\" isdevice=\"yes\" runnable=\"no\"", normalize_string(src.c_str()));
718 	output_sampleof(out, device);
719 	out << ">\n" << util::string_format("\t\t<description>%s</description>\n", normalize_string(device.name()));
720 
721 	output_bios(out, device);
722 	output_rom(out, nullptr, nullptr, device);
723 	output_device_refs(out, device);
724 
725 	if (device.type().type() != typeid(samples_device)) // ignore samples_device itself
726 		output_sample(out, device);
727 
728 	output_chips(out, device, devtag);
729 	output_display(out, device, nullptr, devtag);
730 	if (has_speaker)
731 		output_sound(out, device);
732 	if (has_input)
733 		output_input(out, portlist);
734 	output_switches(out, portlist, devtag, IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
735 	output_switches(out, portlist, devtag, IPT_CONFIG, "configuration", "conflocation", "confsetting");
736 	output_adjusters(out, portlist);
737 	output_features(out, device.type(), overall_unemulated, overall_imperfect);
738 	output_images(out, device, devtag);
739 	output_slots(out, config, device, devtag, nullptr);
740 	output_software_lists(out, device, devtag);
741 	out << util::string_format("\t</%s>\n", XML_TOP);
742 }
743 
744 
745 //-------------------------------------------------
746 //  output_devices - print the XML info for
747 //  registered device types
748 //-------------------------------------------------
749 
output_devices(std::ostream & out,emu_options & lookup_options,device_type_set const * filter)750 void output_devices(std::ostream &out, emu_options &lookup_options, device_type_set const *filter)
751 {
752 	// get config for empty machine
753 	machine_config config(GAME_NAME(___empty), lookup_options);
754 
755 	auto const action = [&config, &out] (device_type type)
756 			{
757 				// add it at the root of the machine config
758 				device_t *dev;
759 				{
760 					machine_config::token const tok(config.begin_configuration(config.root_device()));
761 					dev = config.device_add("_tmp", type, 0);
762 				}
763 
764 				// notify this device and all its subdevices that they are now configured
765 				for (device_t &device : device_iterator(*dev))
766 					if (!device.configured())
767 						device.config_complete();
768 
769 				// print details and remove it
770 				output_one_device(out, config, *dev, dev->tag());
771 				machine_config::token const tok(config.begin_configuration(config.root_device()));
772 				config.device_remove("_tmp");
773 			};
774 
775 	// run through devices
776 	if (filter)
777 	{
778 		for (std::add_pointer_t<device_type> type : *filter) action(*type);
779 	}
780 	else
781 	{
782 		for (device_type type : registered_device_types) action(type);
783 	}
784 }
785 
786 
787 //------------------------------------------------
788 //  output_device_refs - when a machine uses a
789 //  subdevice, print a reference
790 //-------------------------------------------------
791 
output_device_refs(std::ostream & out,device_t & root)792 void output_device_refs(std::ostream &out, device_t &root)
793 {
794 	for (device_t &device : device_iterator(root))
795 		if (&device != &root)
796 			out << util::string_format("\t\t<device_ref name=\"%s\"/>\n", normalize_string(device.shortname()));
797 }
798 
799 
800 //------------------------------------------------
801 //  output_sampleof - print the 'sampleof'
802 //  attribute, if appropriate
803 //-------------------------------------------------
804 
output_sampleof(std::ostream & out,device_t & device)805 void output_sampleof(std::ostream &out, device_t &device)
806 {
807 	// iterate over sample devices
808 	for (samples_device &samples : samples_device_iterator(device))
809 	{
810 		samples_iterator sampiter(samples);
811 		if (sampiter.altbasename() != nullptr)
812 		{
813 			out << util::string_format(" sampleof=\"%s\"", normalize_string(sampiter.altbasename()));
814 
815 			// must stop here, as there can only be one attribute of the same name
816 			return;
817 		}
818 	}
819 }
820 
821 
822 //-------------------------------------------------
823 //  output_bios - print BIOS sets for a device
824 //-------------------------------------------------
825 
output_bios(std::ostream & out,device_t const & device)826 void output_bios(std::ostream &out, device_t const &device)
827 {
828 	// first determine the default BIOS name
829 	char const *defaultname(nullptr);
830 	for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom)
831 	{
832 		if (ROMENTRY_ISDEFAULT_BIOS(rom))
833 			defaultname = rom->name;
834 	}
835 
836 	// iterate over ROM entries and look for BIOSes
837 	for (romload::system_bios const &bios : romload::entries(device.rom_region()).get_system_bioses())
838 	{
839 		// output extracted name and descriptions'
840 		out << "\t\t<biosset";
841 		out << util::string_format(" name=\"%s\"", normalize_string(bios.get_name()));
842 		out << util::string_format(" description=\"%s\"", normalize_string(bios.get_description()));
843 		if (defaultname && !std::strcmp(defaultname, bios.get_name()))
844 			out << " default=\"yes\"";
845 		out << "/>\n";
846 	}
847 }
848 
849 
850 //-------------------------------------------------
851 //  output_rom - print the roms section of
852 //  the XML output
853 //-------------------------------------------------
854 
output_rom(std::ostream & out,driver_enumerator * drivlist,const game_driver * driver,device_t & device)855 void output_rom(std::ostream &out, driver_enumerator *drivlist, const game_driver *driver, device_t &device)
856 {
857 	enum class type { BIOS, NORMAL, DISK };
858 	std::map<u32, char const *> biosnames;
859 	bool bios_scanned(false);
860 	auto const get_biosname =
861 			[&biosnames, &bios_scanned] (tiny_rom_entry const *rom) -> char const *
862 			{
863 				u32 const biosflags(ROM_GETBIOSFLAGS(rom));
864 				std::map<u32, char const *>::const_iterator const found(biosnames.find(biosflags));
865 				if (biosnames.end() != found)
866 					return found->second;
867 
868 				char const *result(nullptr);
869 				if (!bios_scanned)
870 				{
871 					for (++rom; !ROMENTRY_ISEND(rom); ++rom)
872 					{
873 						if (ROMENTRY_ISSYSTEM_BIOS(rom))
874 						{
875 							u32 const biosno(ROM_GETBIOSFLAGS(rom));
876 							biosnames.emplace(biosno, rom->name);
877 							if (biosflags == biosno)
878 								result = rom->name;
879 						}
880 					}
881 					bios_scanned = true;
882 				}
883 				return result;
884 			};
885 	auto const rom_file_size = // FIXME: need a common way to do this without the cost of allocating rom_entry
886 			[] (tiny_rom_entry const *romp) -> u32
887 			{
888 				u32 maxlength = 0;
889 
890 				// loop until we run out of reloads
891 				do
892 				{
893 					// loop until we run out of continues/ignores */
894 					u32 curlength(ROM_GETLENGTH(romp++));
895 					while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
896 						curlength += ROM_GETLENGTH(romp++);
897 
898 					// track the maximum length
899 					maxlength = (std::max)(maxlength, curlength);
900 				}
901 				while (ROMENTRY_ISRELOAD(romp));
902 
903 				return maxlength;
904 			};
905 
906 	// iterate over 3 different ROM "types": BIOS, ROMs, DISKs
907 	bool const do_merge_name = drivlist && dynamic_cast<driver_device *>(&device);
908 	for (type pass : { type::BIOS, type::NORMAL, type::DISK })
909 	{
910 		tiny_rom_entry const *region(nullptr);
911 		for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom)
912 		{
913 			if (ROMENTRY_ISREGION(rom))
914 				region = rom;
915 			else if (ROMENTRY_ISSYSTEM_BIOS(rom))
916 				biosnames.emplace(ROM_GETBIOSFLAGS(rom), rom->name);
917 
918 			if (!ROMENTRY_ISFILE(rom))
919 				continue;
920 
921 			// only list disks on the disk pass
922 			bool const is_disk = ROMREGION_ISDISKDATA(region);
923 			if ((type::DISK == pass) != is_disk)
924 				continue;
925 
926 			// BIOS ROMs only apply to bioses
927 			// FIXME: disk images associated with a system BIOS will never be listed
928 			u32 const biosno(ROM_GETBIOSFLAGS(rom));
929 			if ((type::BIOS == pass) != bool(biosno))
930 				continue;
931 			char const *const bios_name((!is_disk && biosno) ? get_biosname(rom) : nullptr);
932 
933 			// if we have a valid ROM and we are a clone, see if we can find the parent ROM
934 			util::hash_collection const hashes(rom->hashdata);
935 			char const *const merge_name((do_merge_name && !hashes.flag(util::hash_collection::FLAG_NO_DUMP)) ? get_merge_name(*drivlist, *driver, hashes) : nullptr);
936 
937 			// opening tag
938 			if (is_disk)
939 				out << "\t\t<disk";
940 			else
941 				out << "\t\t<rom";
942 
943 			// add name, merge, bios, and size tags */
944 			char const *const name(rom->name);
945 			if (name && name[0])
946 				out << util::string_format(" name=\"%s\"", normalize_string(name));
947 			if (merge_name)
948 				out << util::string_format(" merge=\"%s\"", normalize_string(merge_name));
949 			if (bios_name)
950 				out << util::string_format(" bios=\"%s\"", normalize_string(bios_name));
951 			if (!is_disk)
952 				out << util::string_format(" size=\"%u\"", rom_file_size(rom));
953 
954 			// dump checksum information only if there is a known dump
955 			if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP))
956 				out << ' ' << hashes.attribute_string(); // iterate over hash function types and print m_output their values
957 			else
958 				out << " status=\"nodump\"";
959 
960 			// append a region name
961 			out << util::string_format(" region=\"%s\"", region->name);
962 
963 			if (!is_disk)
964 			{
965 				// for non-disk entries, print offset
966 				out << util::string_format(" offset=\"%x\"", ROM_GETOFFSET(rom));
967 			}
968 			else
969 			{
970 				// for disk entries, add the disk index
971 				out << util::string_format(" index=\"%x\" writable=\"%s\"", DISK_GETINDEX(rom), DISK_ISREADONLY(rom) ? "no" : "yes");
972 			}
973 
974 			// add optional flag
975 			if (ROM_ISOPTIONAL(rom))
976 				out << " optional=\"yes\"";
977 
978 			out << "/>\n";
979 		}
980 		bios_scanned = true;
981 	}
982 }
983 
984 
985 //-------------------------------------------------
986 //  output_sample - print a list of all
987 //  samples referenced by a game_driver
988 //-------------------------------------------------
989 
output_sample(std::ostream & out,device_t & device)990 void output_sample(std::ostream &out, device_t &device)
991 {
992 	// iterate over sample devices
993 	for (samples_device &samples : samples_device_iterator(device))
994 	{
995 		samples_iterator iter(samples);
996 		std::unordered_set<std::string> already_printed;
997 		for (const char *samplename = iter.first(); samplename != nullptr; samplename = iter.next())
998 		{
999 			// filter out duplicates
1000 			if (!already_printed.insert(samplename).second)
1001 				continue;
1002 
1003 			// output the sample name
1004 			out << util::string_format("\t\t<sample name=\"%s\"/>\n", normalize_string(samplename));
1005 		}
1006 	}
1007 }
1008 
1009 
1010 /*-------------------------------------------------
1011     output_chips - print a list of CPU and
1012     sound chips used by a game
1013 -------------------------------------------------*/
1014 
output_chips(std::ostream & out,device_t & device,const char * root_tag)1015 void output_chips(std::ostream &out, device_t &device, const char *root_tag)
1016 {
1017 	// iterate over executable devices
1018 	for (device_execute_interface &exec : execute_interface_iterator(device))
1019 	{
1020 		if (strcmp(exec.device().tag(), device.tag()))
1021 		{
1022 			std::string newtag(exec.device().tag()), oldtag(":");
1023 			newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1024 
1025 			out << "\t\t<chip";
1026 			out << " type=\"cpu\"";
1027 			out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
1028 			out << util::string_format(" name=\"%s\"", normalize_string(exec.device().name()));
1029 			out << util::string_format(" clock=\"%d\"", exec.device().clock());
1030 			out << "/>\n";
1031 		}
1032 	}
1033 
1034 	// iterate over sound devices
1035 	for (device_sound_interface &sound : sound_interface_iterator(device))
1036 	{
1037 		if (strcmp(sound.device().tag(), device.tag()) != 0 && sound.issound())
1038 		{
1039 			std::string newtag(sound.device().tag()), oldtag(":");
1040 			newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1041 
1042 			out << "\t\t<chip";
1043 			out << " type=\"audio\"";
1044 			out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
1045 			out << util::string_format(" name=\"%s\"", normalize_string(sound.device().name()));
1046 			if (sound.device().clock() != 0)
1047 				out << util::string_format(" clock=\"%d\"", sound.device().clock());
1048 			out << "/>\n";
1049 		}
1050 	}
1051 }
1052 
1053 
1054 //-------------------------------------------------
1055 //  output_display - print a list of all the
1056 //  displays
1057 //-------------------------------------------------
1058 
output_display(std::ostream & out,device_t & device,machine_flags::type const * flags,const char * root_tag)1059 void output_display(std::ostream &out, device_t &device, machine_flags::type const *flags, const char *root_tag)
1060 {
1061 	// iterate over screens
1062 	for (const screen_device &screendev : screen_device_iterator(device))
1063 	{
1064 		if (strcmp(screendev.tag(), device.tag()))
1065 		{
1066 			std::string newtag(screendev.tag()), oldtag(":");
1067 			newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1068 
1069 			out << util::string_format("\t\t<display tag=\"%s\"", normalize_string(newtag.c_str()));
1070 
1071 			switch (screendev.screen_type())
1072 			{
1073 				case SCREEN_TYPE_RASTER:    out << " type=\"raster\"";  break;
1074 				case SCREEN_TYPE_VECTOR:    out << " type=\"vector\"";  break;
1075 				case SCREEN_TYPE_LCD:       out << " type=\"lcd\"";     break;
1076 				case SCREEN_TYPE_SVG:       out << " type=\"svg\"";     break;
1077 				default:                    out << " type=\"unknown\""; break;
1078 			}
1079 
1080 			// output the orientation as a string
1081 			switch (screendev.orientation())
1082 			{
1083 			case ORIENTATION_FLIP_X:
1084 				out << " rotate=\"0\" flipx=\"yes\"";
1085 				break;
1086 			case ORIENTATION_FLIP_Y:
1087 				out << " rotate=\"180\" flipx=\"yes\"";
1088 				break;
1089 			case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
1090 				out << " rotate=\"180\"";
1091 				break;
1092 			case ORIENTATION_SWAP_XY:
1093 				out << " rotate=\"90\" flipx=\"yes\"";
1094 				break;
1095 			case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X:
1096 				out << " rotate=\"90\"";
1097 				break;
1098 			case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y:
1099 				out << " rotate=\"270\"";
1100 				break;
1101 			case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
1102 				out << " rotate=\"270\" flipx=\"yes\"";
1103 				break;
1104 			default:
1105 				out << " rotate=\"0\"";
1106 				break;
1107 			}
1108 
1109 			// output width and height only for games that are not vector
1110 			if (screendev.screen_type() != SCREEN_TYPE_VECTOR)
1111 			{
1112 				const rectangle &visarea = screendev.visible_area();
1113 				out << util::string_format(" width=\"%d\"", visarea.width());
1114 				out << util::string_format(" height=\"%d\"", visarea.height());
1115 			}
1116 
1117 			// output refresh rate
1118 			out << util::string_format(" refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds()));
1119 
1120 			// output raw video parameters only for games that are not vector
1121 			// and had raw parameters specified
1122 			if (screendev.screen_type() != SCREEN_TYPE_VECTOR && !screendev.oldstyle_vblank_supplied())
1123 			{
1124 				int pixclock = screendev.width() * screendev.height() * ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds());
1125 
1126 				out << util::string_format(" pixclock=\"%d\"", pixclock);
1127 				out << util::string_format(" htotal=\"%d\"", screendev.width());
1128 				out << util::string_format(" hbend=\"%d\"", screendev.visible_area().min_x);
1129 				out << util::string_format(" hbstart=\"%d\"", screendev.visible_area().max_x+1);
1130 				out << util::string_format(" vtotal=\"%d\"", screendev.height());
1131 				out << util::string_format(" vbend=\"%d\"", screendev.visible_area().min_y);
1132 				out << util::string_format(" vbstart=\"%d\"", screendev.visible_area().max_y+1);
1133 			}
1134 			out << " />\n";
1135 		}
1136 	}
1137 }
1138 
1139 
1140 //-------------------------------------------------
1141 //  output_sound - print a list of all the
1142 //  speakers
1143 //------------------------------------------------
1144 
output_sound(std::ostream & out,device_t & device)1145 void output_sound(std::ostream &out, device_t &device)
1146 {
1147 	speaker_device_iterator spkiter(device);
1148 	int speakers = spkiter.count();
1149 
1150 	// if we have no sound, zero m_output the speaker count
1151 	sound_interface_iterator snditer(device);
1152 	if (snditer.first() == nullptr)
1153 		speakers = 0;
1154 
1155 	out << util::string_format("\t\t<sound channels=\"%d\"/>\n", speakers);
1156 }
1157 
1158 
1159 //-------------------------------------------------
1160 //  output_ioport_condition - print condition
1161 //  required to use I/O port field/setting
1162 //-------------------------------------------------
1163 
output_ioport_condition(std::ostream & out,const ioport_condition & condition,unsigned indent)1164 void output_ioport_condition(std::ostream &out, const ioport_condition &condition, unsigned indent)
1165 {
1166 	for (unsigned i = 0; indent > i; ++i)
1167 		out << '\t';
1168 
1169 	char const *rel(nullptr);
1170 	switch (condition.condition())
1171 	{
1172 	case ioport_condition::ALWAYS:          throw false;
1173 	case ioport_condition::EQUALS:          rel = "eq"; break;
1174 	case ioport_condition::NOTEQUALS:       rel = "ne"; break;
1175 	case ioport_condition::GREATERTHAN:     rel = "gt"; break;
1176 	case ioport_condition::NOTGREATERTHAN:  rel = "le"; break;
1177 	case ioport_condition::LESSTHAN:        rel = "lt"; break;
1178 	case ioport_condition::NOTLESSTHAN:     rel = "ge"; break;
1179 	}
1180 
1181 	out << util::string_format("<condition tag=\"%s\" mask=\"%u\" relation=\"%s\" value=\"%u\"/>\n", normalize_string(condition.tag()), condition.mask(), rel, condition.value());
1182 }
1183 
1184 //-------------------------------------------------
1185 //  output_input - print a summary of a game's
1186 //  input
1187 //-------------------------------------------------
1188 
output_input(std::ostream & out,const ioport_list & portlist)1189 void output_input(std::ostream &out, const ioport_list &portlist)
1190 {
1191 	// enumerated list of control types
1192 	// NOTE: the order is chosen so that 'spare' button inputs are assigned to the
1193 	// most-likely-correct input device when info is output (you can think of it as
1194 	// a sort of likelihood order of having buttons)
1195 	enum
1196 	{
1197 		CTRL_DIGITAL_BUTTONS,
1198 		CTRL_DIGITAL_JOYSTICK,
1199 		CTRL_ANALOG_JOYSTICK,
1200 		CTRL_ANALOG_LIGHTGUN,
1201 		CTRL_ANALOG_DIAL,
1202 		CTRL_ANALOG_POSITIONAL,
1203 		CTRL_ANALOG_TRACKBALL,
1204 		CTRL_ANALOG_MOUSE,
1205 		CTRL_ANALOG_PADDLE,
1206 		CTRL_ANALOG_PEDAL,
1207 		CTRL_DIGITAL_KEYPAD,
1208 		CTRL_DIGITAL_KEYBOARD,
1209 		CTRL_DIGITAL_MAHJONG,
1210 		CTRL_DIGITAL_HANAFUDA,
1211 		CTRL_DIGITAL_GAMBLING,
1212 		CTRL_COUNT
1213 	};
1214 
1215 	enum
1216 	{
1217 		CTRL_P1,
1218 		CTRL_P2,
1219 		CTRL_P3,
1220 		CTRL_P4,
1221 		CTRL_P5,
1222 		CTRL_P6,
1223 		CTRL_P7,
1224 		CTRL_P8,
1225 		CTRL_P9,
1226 		CTRL_P10,
1227 		CTRL_PCOUNT
1228 	};
1229 
1230 	// directions
1231 	const uint8_t DIR_UP = 0x01;
1232 	const uint8_t DIR_DOWN = 0x02;
1233 	const uint8_t DIR_LEFT = 0x04;
1234 	const uint8_t DIR_RIGHT = 0x08;
1235 
1236 	// initialize the list of control types
1237 	struct
1238 	{
1239 		const char *    type;           // general type of input
1240 		int             player;         // player which the input belongs to
1241 		int             nbuttons;       // total number of buttons
1242 		int             reqbuttons;     // total number of non-optional buttons
1243 		int             maxbuttons;     // max index of buttons (using IPT_BUTTONn) [probably to be removed soonish]
1244 		int             ways;           // directions for joystick
1245 		bool            analog;         // is analog input?
1246 		uint8_t           helper[3];      // for dual joysticks [possibly to be removed soonish]
1247 		int32_t           min;            // analog minimum value
1248 		int32_t           max;            // analog maximum value
1249 		int32_t           sensitivity;    // default analog sensitivity
1250 		int32_t           keydelta;       // default analog keydelta
1251 		bool            reverse;        // default analog reverse setting
1252 	} control_info[CTRL_COUNT * CTRL_PCOUNT];
1253 
1254 	memset(&control_info, 0, sizeof(control_info));
1255 
1256 	// tracking info as we iterate
1257 	int nplayer = 0;
1258 	int ncoin = 0;
1259 	bool service = false;
1260 	bool tilt = false;
1261 
1262 	// iterate over the ports
1263 	for (auto &port : portlist)
1264 	{
1265 		int ctrl_type = CTRL_DIGITAL_BUTTONS;
1266 		bool ctrl_analog = false;
1267 		for (ioport_field &field : port.second->fields())
1268 		{
1269 			// track the highest player number
1270 			if (nplayer < field.player() + 1)
1271 				nplayer = field.player() + 1;
1272 
1273 			// switch off of the type
1274 			switch (field.type())
1275 			{
1276 			// map joysticks
1277 			case IPT_JOYSTICK_UP:
1278 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1279 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1280 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1281 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1282 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_UP;
1283 				break;
1284 			case IPT_JOYSTICK_DOWN:
1285 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1286 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1287 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1288 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1289 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_DOWN;
1290 				break;
1291 			case IPT_JOYSTICK_LEFT:
1292 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1293 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1294 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1295 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1296 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_LEFT;
1297 				break;
1298 			case IPT_JOYSTICK_RIGHT:
1299 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1300 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1301 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1302 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1303 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_RIGHT;
1304 				break;
1305 
1306 			case IPT_JOYSTICKLEFT_UP:
1307 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1308 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1309 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1310 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1311 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_UP;
1312 				break;
1313 			case IPT_JOYSTICKLEFT_DOWN:
1314 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1315 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1316 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1317 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1318 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_DOWN;
1319 				break;
1320 			case IPT_JOYSTICKLEFT_LEFT:
1321 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1322 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1323 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1324 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1325 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_LEFT;
1326 				break;
1327 			case IPT_JOYSTICKLEFT_RIGHT:
1328 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1329 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1330 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1331 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1332 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_RIGHT;
1333 				break;
1334 
1335 			case IPT_JOYSTICKRIGHT_UP:
1336 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1337 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1338 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1339 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1340 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_UP;
1341 				break;
1342 			case IPT_JOYSTICKRIGHT_DOWN:
1343 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1344 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1345 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1346 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1347 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_DOWN;
1348 				break;
1349 			case IPT_JOYSTICKRIGHT_LEFT:
1350 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1351 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1352 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1353 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1354 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_LEFT;
1355 				break;
1356 			case IPT_JOYSTICKRIGHT_RIGHT:
1357 				ctrl_type = CTRL_DIGITAL_JOYSTICK;
1358 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
1359 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1360 				control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
1361 				control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_RIGHT;
1362 				break;
1363 
1364 			// map analog inputs
1365 			case IPT_AD_STICK_X:
1366 			case IPT_AD_STICK_Y:
1367 			case IPT_AD_STICK_Z:
1368 				ctrl_analog = true;
1369 				ctrl_type = CTRL_ANALOG_JOYSTICK;
1370 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "stick";
1371 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1372 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1373 				break;
1374 
1375 			case IPT_PADDLE:
1376 			case IPT_PADDLE_V:
1377 				ctrl_analog = true;
1378 				ctrl_type = CTRL_ANALOG_PADDLE;
1379 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "paddle";
1380 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1381 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1382 				break;
1383 
1384 			case IPT_PEDAL:
1385 			case IPT_PEDAL2:
1386 			case IPT_PEDAL3:
1387 				ctrl_analog = true;
1388 				ctrl_type = CTRL_ANALOG_PEDAL;
1389 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "pedal";
1390 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1391 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1392 				break;
1393 
1394 			case IPT_LIGHTGUN_X:
1395 			case IPT_LIGHTGUN_Y:
1396 				ctrl_analog = true;
1397 				ctrl_type = CTRL_ANALOG_LIGHTGUN;
1398 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "lightgun";
1399 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1400 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1401 				break;
1402 
1403 			case IPT_POSITIONAL:
1404 			case IPT_POSITIONAL_V:
1405 				ctrl_analog = true;
1406 				ctrl_type = CTRL_ANALOG_POSITIONAL;
1407 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "positional";
1408 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1409 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1410 				break;
1411 
1412 			case IPT_DIAL:
1413 			case IPT_DIAL_V:
1414 				ctrl_analog = true;
1415 				ctrl_type = CTRL_ANALOG_DIAL;
1416 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "dial";
1417 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1418 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1419 				break;
1420 
1421 			case IPT_TRACKBALL_X:
1422 			case IPT_TRACKBALL_Y:
1423 				ctrl_analog = true;
1424 				ctrl_type = CTRL_ANALOG_TRACKBALL;
1425 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "trackball";
1426 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1427 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1428 				break;
1429 
1430 			case IPT_MOUSE_X:
1431 			case IPT_MOUSE_Y:
1432 				ctrl_analog = true;
1433 				ctrl_type = CTRL_ANALOG_MOUSE;
1434 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mouse";
1435 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1436 				control_info[field.player() * CTRL_COUNT + ctrl_type].analog = true;
1437 				break;
1438 
1439 			// map buttons
1440 			case IPT_BUTTON1:
1441 			case IPT_BUTTON2:
1442 			case IPT_BUTTON3:
1443 			case IPT_BUTTON4:
1444 			case IPT_BUTTON5:
1445 			case IPT_BUTTON6:
1446 			case IPT_BUTTON7:
1447 			case IPT_BUTTON8:
1448 			case IPT_BUTTON9:
1449 			case IPT_BUTTON10:
1450 			case IPT_BUTTON11:
1451 			case IPT_BUTTON12:
1452 			case IPT_BUTTON13:
1453 			case IPT_BUTTON14:
1454 			case IPT_BUTTON15:
1455 			case IPT_BUTTON16:
1456 				ctrl_analog = false;
1457 				if (control_info[field.player() * CTRL_COUNT + ctrl_type].type == nullptr)
1458 				{
1459 					control_info[field.player() * CTRL_COUNT + ctrl_type].type = "only_buttons";
1460 					control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1461 					control_info[field.player() * CTRL_COUNT + ctrl_type].analog = false;
1462 				}
1463 				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);
1464 				control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1465 				if (!field.optional())
1466 					control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1467 				break;
1468 
1469 			// track maximum coin index
1470 			case IPT_COIN1:
1471 			case IPT_COIN2:
1472 			case IPT_COIN3:
1473 			case IPT_COIN4:
1474 			case IPT_COIN5:
1475 			case IPT_COIN6:
1476 			case IPT_COIN7:
1477 			case IPT_COIN8:
1478 			case IPT_COIN9:
1479 			case IPT_COIN10:
1480 			case IPT_COIN11:
1481 			case IPT_COIN12:
1482 				ncoin = std::max(ncoin, field.type() - IPT_COIN1 + 1);
1483 				break;
1484 
1485 			// track presence of keypads and keyboards
1486 			case IPT_KEYPAD:
1487 				ctrl_type = CTRL_DIGITAL_KEYPAD;
1488 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keypad";
1489 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1490 				control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1491 				if (!field.optional())
1492 					control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1493 				break;
1494 
1495 			case IPT_KEYBOARD:
1496 				ctrl_type = CTRL_DIGITAL_KEYBOARD;
1497 				control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keyboard";
1498 				control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1499 				control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1500 				if (!field.optional())
1501 					control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1502 				break;
1503 
1504 			// additional types
1505 			case IPT_SERVICE:
1506 				service = true;
1507 				break;
1508 
1509 			case IPT_TILT:
1510 				tilt = true;
1511 				break;
1512 
1513 			default:
1514 				if (field.type() > IPT_MAHJONG_FIRST && field.type() < IPT_MAHJONG_LAST)
1515 				{
1516 					ctrl_type = CTRL_DIGITAL_MAHJONG;
1517 					control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mahjong";
1518 					control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1519 					control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1520 					if (!field.optional())
1521 						control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1522 				}
1523 				else if (field.type() > IPT_HANAFUDA_FIRST && field.type() < IPT_HANAFUDA_LAST)
1524 				{
1525 					ctrl_type = CTRL_DIGITAL_HANAFUDA;
1526 					control_info[field.player() * CTRL_COUNT + ctrl_type].type = "hanafuda";
1527 					control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1528 					control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1529 					if (!field.optional())
1530 						control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1531 				}
1532 				else if (field.type() > IPT_GAMBLING_FIRST && field.type() < IPT_GAMBLING_LAST)
1533 				{
1534 					ctrl_type = CTRL_DIGITAL_GAMBLING;
1535 					control_info[field.player() * CTRL_COUNT + ctrl_type].type = "gambling";
1536 					control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
1537 					control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
1538 					if (!field.optional())
1539 						control_info[field.player() * CTRL_COUNT + ctrl_type].reqbuttons++;
1540 				}
1541 				break;
1542 			}
1543 
1544 			if (ctrl_analog)
1545 			{
1546 				// get the analog stats
1547 				if (field.minval() != 0)
1548 					control_info[field.player() * CTRL_COUNT + ctrl_type].min = field.minval();
1549 				if (field.maxval() != 0)
1550 					control_info[field.player() * CTRL_COUNT + ctrl_type].max = field.maxval();
1551 				if (field.sensitivity() != 0)
1552 					control_info[field.player() * CTRL_COUNT + ctrl_type].sensitivity = field.sensitivity();
1553 				if (field.delta() != 0)
1554 					control_info[field.player() * CTRL_COUNT + ctrl_type].keydelta = field.delta();
1555 				if (field.analog_reverse() != 0)
1556 					control_info[field.player() * CTRL_COUNT + ctrl_type].reverse = true;
1557 			}
1558 		}
1559 	}
1560 
1561 	// Clean-up those entries, if any, where buttons were defined in a separate port than the actual controller they belong to.
1562 	// This is quite often the case, especially for arcades where controls can be easily mapped to separate input ports on PCB.
1563 	// If such situation would only happen for joystick, it would be possible to work it around by initializing differently
1564 	// ctrl_type above, but it is quite common among analog inputs as well (for instance, this is the tipical situation
1565 	// for lightguns) and therefore we really need this separate loop.
1566 	for (int i = 0; i < CTRL_PCOUNT; i++)
1567 	{
1568 		bool fix_done = false;
1569 		for (int j = 1; j < CTRL_COUNT; j++)
1570 			if (control_info[i * CTRL_COUNT].type != nullptr && control_info[i * CTRL_COUNT + j].type != nullptr && !fix_done)
1571 			{
1572 				control_info[i * CTRL_COUNT + j].nbuttons += control_info[i * CTRL_COUNT].nbuttons;
1573 				control_info[i * CTRL_COUNT + j].reqbuttons += control_info[i * CTRL_COUNT].reqbuttons;
1574 				control_info[i * CTRL_COUNT + j].maxbuttons = std::max(control_info[i * CTRL_COUNT + j].maxbuttons, control_info[i * CTRL_COUNT].maxbuttons);
1575 
1576 				memset(&control_info[i * CTRL_COUNT], 0, sizeof(control_info[0]));
1577 				fix_done = true;
1578 			}
1579 	}
1580 
1581 	// Output the input info
1582 	// First basic info
1583 	out << "\t\t<input";
1584 	out << util::string_format(" players=\"%d\"", nplayer);
1585 	if (ncoin != 0)
1586 		out << util::string_format(" coins=\"%d\"", ncoin);
1587 	if (service)
1588 		out << util::string_format(" service=\"yes\"");
1589 	if (tilt)
1590 		out << util::string_format(" tilt=\"yes\"");
1591 	out << ">\n";
1592 
1593 	// Then controller specific ones
1594 	for (auto & elem : control_info)
1595 		if (elem.type != nullptr)
1596 		{
1597 			//printf("type %s - player %d - buttons %d\n", elem.type, elem.player, elem.nbuttons);
1598 			if (elem.analog)
1599 			{
1600 				out << util::string_format("\t\t\t<control type=\"%s\"", normalize_string(elem.type));
1601 				if (nplayer > 1)
1602 					out << util::string_format(" player=\"%d\"", elem.player);
1603 				if (elem.nbuttons > 0)
1604 				{
1605 					out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
1606 					if (elem.reqbuttons < elem.nbuttons)
1607 						out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
1608 				}
1609 				if (elem.min != 0 || elem.max != 0)
1610 					out << util::string_format(" minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max);
1611 				if (elem.sensitivity != 0)
1612 					out << util::string_format(" sensitivity=\"%d\"", elem.sensitivity);
1613 				if (elem.keydelta != 0)
1614 					out << util::string_format(" keydelta=\"%d\"", elem.keydelta);
1615 				if (elem.reverse)
1616 					out << " reverse=\"yes\"";
1617 
1618 				out << "/>\n";
1619 			}
1620 			else
1621 			{
1622 				if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
1623 				if (elem.helper[0] == 0 && elem.helper[1] != 0) { elem.helper[0] = elem.helper[1]; elem.helper[1] = 0; }
1624 				if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
1625 				const char *joys = (elem.helper[2] != 0) ? "triple" : (elem.helper[1] != 0) ? "double" : "";
1626 				out << util::string_format("\t\t\t<control type=\"%s%s\"", joys, normalize_string(elem.type));
1627 				if (nplayer > 1)
1628 					out << util::string_format(" player=\"%d\"", elem.player);
1629 				if (elem.nbuttons > 0)
1630 				{
1631 					out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
1632 					if (elem.reqbuttons < elem.nbuttons)
1633 						out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
1634 				}
1635 				for (int lp = 0; lp < 3 && elem.helper[lp] != 0; lp++)
1636 				{
1637 					const char *plural = (lp==2) ? "3" : (lp==1) ? "2" : "";
1638 					const char *ways;
1639 					std::string helper;
1640 					switch (elem.helper[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
1641 					{
1642 						case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
1643 							helper = string_format("%d", (elem.ways == 0) ? 8 : elem.ways);
1644 							ways = helper.c_str();
1645 							break;
1646 						case DIR_LEFT | DIR_RIGHT:
1647 							ways = "2";
1648 							break;
1649 						case DIR_UP | DIR_DOWN:
1650 							ways = "vertical2";
1651 							break;
1652 						case DIR_UP:
1653 						case DIR_DOWN:
1654 						case DIR_LEFT:
1655 						case DIR_RIGHT:
1656 							ways = "1";
1657 							break;
1658 						case DIR_UP | DIR_DOWN | DIR_LEFT:
1659 						case DIR_UP | DIR_DOWN | DIR_RIGHT:
1660 						case DIR_UP | DIR_LEFT | DIR_RIGHT:
1661 						case DIR_DOWN | DIR_LEFT | DIR_RIGHT:
1662 							ways = (elem.ways == 4) ? "3 (half4)" : "5 (half8)";
1663 							break;
1664 						default:
1665 							ways = "strange2";
1666 							break;
1667 					}
1668 					out << util::string_format(" ways%s=\"%s\"", plural, ways);
1669 				}
1670 				out << "/>\n";
1671 			}
1672 		}
1673 
1674 	out << "\t\t</input>\n";
1675 }
1676 
1677 
1678 //-------------------------------------------------
1679 //  output_switches - print the configurations or
1680 //  DIP switch settings
1681 //-------------------------------------------------
1682 
output_switches(std::ostream & out,const ioport_list & portlist,const char * root_tag,int type,const char * outertag,const char * loctag,const char * innertag)1683 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)
1684 {
1685 	// iterate looking for DIP switches
1686 	for (auto &port : portlist)
1687 		for (ioport_field const &field : port.second->fields())
1688 			if (field.type() == type)
1689 			{
1690 				std::string newtag(port.second->tag()), oldtag(":");
1691 				newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1692 
1693 				// output the switch name information
1694 				std::string const normalized_field_name(normalize_string(field.name()));
1695 				std::string const normalized_newtag(normalize_string(newtag.c_str()));
1696 				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());
1697 				if (!field.condition().none())
1698 					output_ioport_condition(out, field.condition(), 3);
1699 
1700 				// loop over locations
1701 				for (ioport_diplocation const &diploc : field.diplocations())
1702 				{
1703 					out << util::string_format("\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, normalize_string(diploc.name()), diploc.number());
1704 					if (diploc.inverted())
1705 						out << " inverted=\"yes\"";
1706 					out << "/>\n";
1707 				}
1708 
1709 				// loop over settings
1710 				for (ioport_setting const &setting : field.settings())
1711 				{
1712 					out << util::string_format("\t\t\t<%s name=\"%s\" value=\"%u\"", innertag, normalize_string(setting.name()), setting.value());
1713 					if (setting.value() == field.defvalue())
1714 						out << " default=\"yes\"";
1715 					if (setting.condition().none())
1716 					{
1717 						out << "/>\n";
1718 					}
1719 					else
1720 					{
1721 						out << ">\n";
1722 						output_ioport_condition(out, setting.condition(), 4);
1723 						out << util::string_format("\t\t\t</%s>\n", innertag);
1724 					}
1725 				}
1726 
1727 				// terminate the switch entry
1728 				out << util::string_format("\t\t</%s>\n", outertag);
1729 			}
1730 }
1731 
1732 //-------------------------------------------------
1733 //  output_ports - print the structure of input
1734 //  ports in the driver
1735 //-------------------------------------------------
output_ports(std::ostream & out,const ioport_list & portlist)1736 void output_ports(std::ostream &out, const ioport_list &portlist)
1737 {
1738 	// cycle through ports
1739 	for (auto &port : portlist)
1740 	{
1741 		out << util::string_format("\t\t<port tag=\"%s\">\n", normalize_string(port.second->tag()));
1742 		for (ioport_field const &field : port.second->fields())
1743 		{
1744 			if (field.is_analog())
1745 				out << util::string_format("\t\t\t<analog mask=\"%u\"/>\n", field.mask());
1746 		}
1747 		out << util::string_format("\t\t</port>\n");
1748 	}
1749 
1750 }
1751 
1752 //-------------------------------------------------
1753 //  output_adjusters - print the Analog
1754 //  Adjusters for a game
1755 //-------------------------------------------------
1756 
output_adjusters(std::ostream & out,const ioport_list & portlist)1757 void output_adjusters(std::ostream &out, const ioport_list &portlist)
1758 {
1759 	// iterate looking for Adjusters
1760 	for (auto &port : portlist)
1761 		for (ioport_field const &field : port.second->fields())
1762 			if (field.type() == IPT_ADJUSTER)
1763 			{
1764 				out << util::string_format("\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", normalize_string(field.name()), field.defvalue());
1765 			}
1766 }
1767 
1768 
1769 //-------------------------------------------------
1770 //  output_driver - print driver status
1771 //-------------------------------------------------
1772 
output_driver(std::ostream & out,game_driver const & driver,device_t::feature_type unemulated,device_t::feature_type imperfect)1773 void output_driver(std::ostream &out, game_driver const &driver, device_t::feature_type unemulated, device_t::feature_type imperfect)
1774 {
1775 	out << "\t\t<driver";
1776 
1777 	/*
1778 	The status entry is an hint for frontend authors to select working
1779 	and not working games without the need to know all the other status
1780 	entries.  Games marked as status=good are perfectly emulated, games
1781 	marked as status=imperfect are emulated with only some minor issues,
1782 	games marked as status=preliminary don't work or have major
1783 	emulation problems.
1784 	*/
1785 
1786 	u32 const flags = driver.flags;
1787 	bool const machine_preliminary(flags & (machine_flags::NOT_WORKING | machine_flags::MECHANICAL));
1788 	bool const unemulated_preliminary(unemulated & (device_t::feature::PALETTE | device_t::feature::GRAPHICS | device_t::feature::SOUND | device_t::feature::KEYBOARD));
1789 	bool const imperfect_preliminary((unemulated | imperfect) & device_t::feature::PROTECTION);
1790 
1791 	if (machine_preliminary || unemulated_preliminary || imperfect_preliminary)
1792 		out << " status=\"preliminary\"";
1793 	else if (imperfect)
1794 		out << " status=\"imperfect\"";
1795 	else
1796 		out << " status=\"good\"";
1797 
1798 	if (flags & machine_flags::NOT_WORKING)
1799 		out << " emulation=\"preliminary\"";
1800 	else
1801 		out << " emulation=\"good\"";
1802 
1803 	if (flags & machine_flags::NO_COCKTAIL)
1804 		out << " cocktail=\"preliminary\"";
1805 
1806 	if (flags & machine_flags::SUPPORTS_SAVE)
1807 		out << " savestate=\"supported\"";
1808 	else
1809 		out << " savestate=\"unsupported\"";
1810 
1811 	out << "/>\n";
1812 }
1813 
1814 
1815 //-------------------------------------------------
1816 //  output_features - print emulation features of
1817 //
1818 //-------------------------------------------------
1819 
output_features(std::ostream & out,device_type type,device_t::feature_type unemulated,device_t::feature_type imperfect)1820 void output_features(std::ostream &out, device_type type, device_t::feature_type unemulated, device_t::feature_type imperfect)
1821 {
1822 	device_t::feature_type const flags(type.unemulated_features() | type.imperfect_features() | unemulated | imperfect);
1823 	for (auto const &feature : f_feature_names)
1824 	{
1825 		if (flags & feature.first)
1826 		{
1827 			out << util::string_format("\t\t<feature type=\"%s\"", feature.second);
1828 			if (type.unemulated_features() & feature.first)
1829 			{
1830 				out << " status=\"unemulated\"";
1831 			}
1832 			else
1833 			{
1834 				if (type.imperfect_features() & feature.first)
1835 					out << " status=\"imperfect\"";
1836 				if (unemulated & feature.first)
1837 					out << " overall=\"unemulated\"";
1838 				else if ((~type.imperfect_features() & imperfect) & feature.first)
1839 					out << " overall=\"imperfect\"";
1840 			}
1841 			out << "/>\n";
1842 		}
1843 	}
1844 }
1845 
1846 
1847 //-------------------------------------------------
1848 //  output_images - prints m_output all info on
1849 //  image devices
1850 //-------------------------------------------------
1851 
output_images(std::ostream & out,device_t & device,const char * root_tag)1852 void output_images(std::ostream &out, device_t &device, const char *root_tag)
1853 {
1854 	for (const device_image_interface &imagedev : image_interface_iterator(device))
1855 	{
1856 		if (strcmp(imagedev.device().tag(), device.tag()))
1857 		{
1858 			bool loadable = imagedev.user_loadable();
1859 			std::string newtag(imagedev.device().tag()), oldtag(":");
1860 			newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1861 
1862 			// print m_output device type
1863 			out << util::string_format("\t\t<device type=\"%s\"", normalize_string(imagedev.image_type_name()));
1864 
1865 			// does this device have a tag?
1866 			if (imagedev.device().tag())
1867 				out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
1868 
1869 			// is this device available as media switch?
1870 			if (!loadable)
1871 				out << " fixed_image=\"1\"";
1872 
1873 			// is this device mandatory?
1874 			if (imagedev.must_be_loaded())
1875 				out << " mandatory=\"1\"";
1876 
1877 			if (imagedev.image_interface() && imagedev.image_interface()[0])
1878 				out << util::string_format(" interface=\"%s\"", normalize_string(imagedev.image_interface()));
1879 
1880 			// close the XML tag
1881 			out << ">\n";
1882 
1883 			if (loadable)
1884 			{
1885 				char const *const name = imagedev.instance_name().c_str();
1886 				char const *const shortname = imagedev.brief_instance_name().c_str();
1887 
1888 				out << "\t\t\t<instance";
1889 				out << util::string_format(" name=\"%s\"", normalize_string(name));
1890 				out << util::string_format(" briefname=\"%s\"", normalize_string(shortname));
1891 				out << "/>\n";
1892 
1893 				char const *extensions(imagedev.file_extensions());
1894 				while (extensions)
1895 				{
1896 					char const *end(extensions);
1897 					while (*end && (',' != *end))
1898 						++end;
1899 					out << util::string_format("\t\t\t<extension name=\"%s\"/>\n", normalize_string(std::string(extensions, end).c_str()));
1900 					extensions = *end ? (end + 1) : nullptr;
1901 				}
1902 			}
1903 			out << "\t\t</device>\n";
1904 		}
1905 	}
1906 }
1907 
1908 
1909 //-------------------------------------------------
1910 //  output_slots - prints all info about slots
1911 //-------------------------------------------------
1912 
output_slots(std::ostream & out,machine_config & config,device_t & device,const char * root_tag,device_type_set * devtypes)1913 void output_slots(std::ostream &out, machine_config &config, device_t &device, const char *root_tag, device_type_set *devtypes)
1914 {
1915 	for (device_slot_interface &slot : slot_interface_iterator(device))
1916 	{
1917 		// shall we list fixed slots as non-configurable?
1918 		bool const listed(!slot.fixed() && strcmp(slot.device().tag(), device.tag()));
1919 
1920 		if (devtypes || listed)
1921 		{
1922 			machine_config::token const tok(config.begin_configuration(slot.device()));
1923 			std::string newtag(slot.device().tag()), oldtag(":");
1924 			newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1925 
1926 			// print m_output device type
1927 			if (listed)
1928 				out << util::string_format("\t\t<slot name=\"%s\">\n", normalize_string(newtag.c_str()));
1929 
1930 			for (auto &option : slot.option_list())
1931 			{
1932 				if (devtypes || (listed && option.second->selectable()))
1933 				{
1934 					device_t *const dev = config.device_add("_dummy", option.second->devtype(), option.second->clock());
1935 					if (!dev->configured())
1936 						dev->config_complete();
1937 
1938 					if (devtypes)
1939 						for (device_t &subdevice : device_iterator(*dev)) devtypes->insert(&subdevice.type());
1940 
1941 					if (listed && option.second->selectable())
1942 					{
1943 						out << util::string_format("\t\t\t<slotoption name=\"%s\"", normalize_string(option.second->name()));
1944 						out << util::string_format(" devname=\"%s\"", normalize_string(dev->shortname()));
1945 						if (slot.default_option() != nullptr && strcmp(slot.default_option(), option.second->name())==0)
1946 							out << " default=\"yes\"";
1947 						out << "/>\n";
1948 					}
1949 
1950 					config.device_remove("_dummy");
1951 				}
1952 			}
1953 
1954 			if (listed)
1955 				out << "\t\t</slot>\n";
1956 		}
1957 	}
1958 }
1959 
1960 
1961 //-------------------------------------------------
1962 //  output_software_lists - print the information
1963 //  for all known software lists for this system
1964 //-------------------------------------------------
1965 
output_software_lists(std::ostream & out,device_t & root,const char * root_tag)1966 void output_software_lists(std::ostream &out, device_t &root, const char *root_tag)
1967 {
1968 	for (const software_list_device &swlist : software_list_device_iterator(root))
1969 	{
1970 		if (&static_cast<const device_t &>(swlist) == &root)
1971 		{
1972 			assert(swlist.list_name().empty());
1973 			continue;
1974 		}
1975 
1976 		std::string newtag(swlist.tag()), oldtag(":");
1977 		newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
1978 		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");
1979 
1980 		if (swlist.filter())
1981 			out << util::string_format(" filter=\"%s\"", normalize_string(swlist.filter()));
1982 		out << "/>\n";
1983 	}
1984 }
1985 
1986 
1987 
1988 //-------------------------------------------------
1989 //  output_ramoptions - prints m_output all RAM
1990 //  options for this system
1991 //-------------------------------------------------
1992 
output_ramoptions(std::ostream & out,device_t & root)1993 void output_ramoptions(std::ostream &out, device_t &root)
1994 {
1995 	for (const ram_device &ram : ram_device_iterator(root, 1))
1996 	{
1997 		if (!std::strcmp(ram.tag(), ":" RAM_TAG))
1998 		{
1999 			uint32_t const defsize(ram.default_size());
2000 			bool havedefault(false);
2001 			for (ram_device::extra_option const &option : ram.extra_options())
2002 			{
2003 				if (defsize == option.second)
2004 				{
2005 					assert(!havedefault);
2006 					havedefault = true;
2007 					out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
2008 				}
2009 				else
2010 				{
2011 					out << util::string_format("\t\t<ramoption name=\"%s\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
2012 				}
2013 			}
2014 			if (!havedefault)
2015 				out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize);
2016 			break;
2017 		}
2018 	}
2019 }
2020 
2021 
2022 //-------------------------------------------------
2023 //  get_merge_name - get the rom name from a
2024 //  parent set
2025 //-------------------------------------------------
2026 
get_merge_name(driver_enumerator & drivlist,const game_driver & driver,util::hash_collection const & romhashes)2027 const char *get_merge_name(driver_enumerator &drivlist, const game_driver &driver, util::hash_collection const &romhashes)
2028 {
2029 	// walk the parent chain
2030 	for (int clone_of = drivlist.find(driver.parent); 0 <= clone_of; clone_of = drivlist.find(drivlist.driver(clone_of).parent))
2031 	{
2032 		// look in the parent's ROMs
2033 		for (romload::region const &pregion : romload::entries(drivlist.driver(clone_of).rom).get_regions())
2034 		{
2035 			for (romload::file const &prom : pregion.get_files())
2036 			{
2037 				// stop when we find a match
2038 				util::hash_collection const phashes(prom.get_hashdata());
2039 				if (!phashes.flag(util::hash_collection::FLAG_NO_DUMP) && (romhashes == phashes))
2040 					return prom.get_name();
2041 			}
2042 		}
2043 	}
2044 
2045 	return nullptr;
2046 }
2047 
2048 
2049 //-------------------------------------------------
2050 //  device_type_compare::operator()
2051 //-------------------------------------------------
2052 
operator ()(const std::add_pointer_t<device_type> & lhs,const std::add_pointer_t<device_type> & rhs) const2053 bool device_type_compare::operator()(const std::add_pointer_t<device_type> &lhs, const std::add_pointer_t<device_type> &rhs) const
2054 {
2055 	return strcmp(lhs->shortname(), rhs->shortname()) < 0;
2056 }
2057 
2058 }
2059