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 << """; break;
504 case '&': stream << "&"; break;
505 case '<': stream << "<"; break;
506 case '>': stream << ">"; 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