diff --git a/scripts/minimaws/lib/__init__.py b/scripts/minimaws/lib/__init__.py
new file mode 100644
index 00000000000..d89cb7f81ba
--- /dev/null
+++ b/scripts/minimaws/lib/__init__.py
@@ -0,0 +1,4 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
diff --git a/scripts/minimaws/lib/auxverbs.py b/scripts/minimaws/lib/auxverbs.py
new file mode 100644
index 00000000000..c68c528af6f
--- /dev/null
+++ b/scripts/minimaws/lib/auxverbs.py
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+from . import dbaccess
+
+import sys
+
+
+def do_listfull(options):
+ dbconn = dbaccess.QueryConnection(options.database)
+ dbcurs = dbconn.cursor()
+ first = True
+ for shortname, description in dbcurs.listfull(options.pattern):
+ if first:
+ sys.stdout.write('Name: Description:\n')
+ first = False
+ sys.stdout.write('%-16s "%s"\n' % (shortname, description))
+ if first:
+ sys.stderr.write('No matching systems found for \'%s\'\n' % (options.pattern, ))
+ dbcurs.close()
+ dbconn.close()
+
+
+def do_listsource(options):
+ dbconn = dbaccess.QueryConnection(options.database)
+ dbcurs = dbconn.cursor()
+ shortname = None
+ for shortname, sourcefile in dbcurs.listsource(options.pattern):
+ sys.stdout.write('%-16s %s\n' % (shortname, sourcefile))
+ if shortname is None:
+ sys.stderr.write('No matching systems found for \'%s\'\n' % (options.pattern, ))
+ dbcurs.close()
+ dbconn.close()
+
+
+def do_listclones(options):
+ dbconn = dbaccess.QueryConnection(options.database)
+ dbcurs = dbconn.cursor()
+ first = True
+ for shortname, parent in dbcurs.listclones(options.pattern):
+ if first:
+ sys.stdout.write('Name: Clone of:\n')
+ first = False
+ sys.stdout.write('%-16s %s\n' % (shortname, parent))
+ if first:
+ count = dbcurs.count_systems(options.pattern).fetchone()[0]
+ if count:
+ sys.stderr.write('Found %d match(es) for \'%s\' but none were clones\n' % (count, options.pattern))
+ else:
+ sys.stderr.write('No matching systems found for \'%s\'\n' % (options.pattern, ))
+ dbcurs.close()
+ dbconn.close()
+
+
+def do_listbrothers(options):
+ dbconn = dbaccess.QueryConnection(options.database)
+ dbcurs = dbconn.cursor()
+ first = True
+ for sourcefile, shortname, parent in dbcurs.listbrothers(options.pattern):
+ if first:
+ sys.stdout.write('%-20s %-16s %s\n' % ('Source file:', 'Name:', 'Parent:'))
+ first = False
+ sys.stdout.write('%-20s %-16s %s\n' % (sourcefile, shortname, parent or ''))
+ if first:
+ sys.stderr.write('No matching systems found for \'%s\'\n' % (options.pattern, ))
+ dbcurs.close()
+ dbconn.close()
+
+def do_listaffected(options):
+ dbconn = dbaccess.QueryConnection(options.database)
+ dbcurs = dbconn.cursor()
+ first = True
+ for shortname, description in dbcurs.listaffected(*options.pattern):
+ if first:
+ sys.stdout.write('Name: Description:\n')
+ first = False
+ sys.stdout.write('%-16s "%s"\n' % (shortname, description))
+ if first:
+ sys.stderr.write('No matching systems found for \'%s\'\n' % (options.pattern, ))
+ dbcurs.close()
+ dbconn.close()
diff --git a/scripts/minimaws/lib/dbaccess.py b/scripts/minimaws/lib/dbaccess.py
new file mode 100644
index 00000000000..3358b538b3c
--- /dev/null
+++ b/scripts/minimaws/lib/dbaccess.py
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+import sqlite3
+
+
+class SchemaQueries(object):
+ INDEX_MACHINE_ISDEVICE_SHORTNAME = 'CREATE INDEX machine_isdevice_shortname ON machine (isdevice ASC, shortname ASC)'
+ INDEX_MACHINE_ISDEVICE_DESCRIPTION = 'CREATE INDEX machine_isdevice_description ON machine (isdevice ASC, description ASC)'
+ INDEX_MACHINE_RUNNABLE_SHORTNAME = 'CREATE INDEX machine_runnable_shortname ON machine (runnable ASC, shortname ASC)'
+ INDEX_MACHINE_RUNNABLE_DESCRIPTION = 'CREATE INDEX machine_runnable_description ON machine (runnable ASC, description ASC)'
+
+ INDEX_SYSTEM_YEAR = 'CREATE INDEX system_year ON system (year ASC)'
+ INDEX_SYSTEM_MANUFACTURER = 'CREATE INDEX system_manufacturer ON system (manufacturer ASC)'
+
+ INDEX_ROMOF_PARENT = 'CREATE INDEX romof_parent ON romof (parent ASC)'
+
+ INDEX_CLONEOF_PARENT = 'CREATE INDEX cloneof_parent ON cloneof (parent ASC)'
+
+ INDEX_DEVICEREFERENCE_DEVICE = 'CREATE INDEX devicereference_device ON devicereference (device ASC)'
+
+ INDEX_DIPSWITCH_MACHINE_ISCONFIG = 'CREATE INDEX dipswitch_machine_isconfig ON dipswitch (machine ASC, isconfig ASC)'
+
+ DROP_MACHINE_ISDEVICE_SHORTNAME = 'DROP INDEX IF EXISTS machine_isdevice_shortname'
+ DROP_MACHINE_ISDEVICE_DESCRIPTION = 'DROP INDEX IF EXISTS machine_isdevice_description'
+ DROP_MACHINE_RUNNABLE_SHORTNAME = 'DROP INDEX IF EXISTS machine_runnable_shortname'
+ DROP_MACHINE_RUNNABLE_DESCRIPTION = 'DROP INDEX IF EXISTS machine_runnable_description'
+
+ DROP_SYSTEM_YEAR = 'DROP INDEX IF EXISTS system_year'
+ DROP_SYSTEM_MANUFACTURER = 'DROP INDEX IF EXISTS system_manufacturer'
+
+ DROP_ROMOF_PARENT = 'DROP INDEX IF EXISTS romof_parent'
+
+ DROP_CLONEOF_PARENT = 'DROP INDEX IF EXISTS cloneof_parent'
+
+ DROP_DEVICEREFERENCE_DEVICE = 'DROP INDEX IF EXISTS devicereference_device'
+
+ DROP_DIPSWITCH_MACHINE_ISCONFIG = 'DROP INDEX IF EXISTS dipswitch_machine_isconfig'
+
+
+class UpdateQueries(object):
+ ADD_FEATURETYPE = 'INSERT OR IGNORE INTO featuretype (name) VALUES (?)'
+ ADD_SOURCEFILE = 'INSERT OR IGNORE INTO sourcefile (filename) VALUES (?)'
+ ADD_MACHINE = 'INSERT INTO machine (shortname, description, sourcefile, isdevice, runnable) SELECT ?, ?, id, ?, ? FROM sourcefile WHERE filename = ?'
+ ADD_SYSTEM = 'INSERT INTO system (id, year, manufacturer) VALUES (?, ?, ?)'
+ ADD_CLONEOF = 'INSERT INTO cloneof (id, parent) VALUES (?, ?)'
+ ADD_ROMOF = 'INSERT INTO romof (id, parent) VALUES (?, ?)'
+ ADD_DEVICEREFERENCE = 'INSERT OR IGNORE INTO devicereference (machine, device) VALUES (?, ?)'
+ ADD_DIPSWITCH = 'INSERT INTO dipswitch (machine, isconfig, name, tag, mask) VALUES (?, ?, ?, ?, ?)'
+ ADD_DIPLOCATION = 'INSERT INTO diplocation (dipswitch, bit, name, num, inverted) VALUES (?, ?, ?, ?, ?)'
+ ADD_DIPVALUE = 'INSERT INTO dipvalue (dipswitch, name, value, isdefault) VALUES (?, ?, ?, ?)'
+ ADD_FEATURE = 'INSERT INTO feature (machine, featuretype, status, overall) SELECT ?, id, ?, ? FROM featuretype WHERE name = ?'
+
+
+class QueryCursor(object):
+ def __init__(self, dbconn, **kwargs):
+ super(QueryCursor, self).__init__(**kwargs)
+ self.dbcurs = dbconn.cursor()
+
+ def close(self):
+ self.dbcurs.close()
+
+ def is_glob(self, *patterns):
+ for pattern in patterns:
+ if any(ch in pattern for ch in '?*['):
+ return True
+ return False
+
+ def count_systems(self, pattern):
+ if pattern is not None:
+ return self.dbcurs.execute(
+ 'SELECT COUNT(*) ' \
+ 'FROM machine WHERE isdevice = 0 AND shortname GLOB ? ',
+ (pattern, ))
+ else:
+ return self.dbcurs.execute(
+ 'SELECT COUNT(*) ' \
+ 'FROM machine WHERE isdevice = 0 ')
+
+ def listfull(self, pattern):
+ if pattern is not None:
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine WHERE isdevice = 0 AND shortname GLOB ? ' \
+ 'ORDER BY shortname ASC',
+ (pattern, ))
+ else:
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine WHERE isdevice = 0 ' \
+ 'ORDER BY shortname ASC')
+
+ def listsource(self, pattern):
+ if pattern is not None:
+ return self.dbcurs.execute(
+ 'SELECT machine.shortname, sourcefile.filename ' \
+ 'FROM machine JOIN sourcefile ON machine.sourcefile = sourcefile.id ' \
+ 'WHERE machine.isdevice = 0 AND machine.shortname GLOB ? ' \
+ 'ORDER BY machine.shortname ASC',
+ (pattern, ))
+ else:
+ return self.dbcurs.execute(
+ 'SELECT machine.shortname, sourcefile.filename ' \
+ 'FROM machine JOIN sourcefile ON machine.sourcefile = sourcefile.id ' \
+ 'WHERE machine.isdevice = 0 ORDER BY machine.shortname ASC')
+
+ def listclones(self, pattern):
+ if pattern is not None:
+ return self.dbcurs.execute(
+ 'SELECT machine.shortname, cloneof.parent ' \
+ 'FROM machine JOIN cloneof ON machine.id = cloneof.id ' \
+ 'WHERE machine.shortname GLOB ? OR cloneof.parent GLOB ? ' \
+ 'ORDER BY machine.shortname ASC',
+ (pattern, pattern))
+ else:
+ return self.dbcurs.execute(
+ 'SELECT machine.shortname, cloneof.parent ' \
+ 'FROM machine JOIN cloneof ON machine.id = cloneof.id ' \
+ 'ORDER BY machine.shortname ASC')
+
+ def listbrothers(self, pattern):
+ if pattern is not None:
+ return self.dbcurs.execute(
+ 'SELECT sourcefile.filename, machine.shortname, cloneof.parent ' \
+ 'FROM machine JOIN sourcefile ON machine.sourcefile = sourcefile.id LEFT JOIN cloneof ON machine.id = cloneof.id ' \
+ 'WHERE machine.isdevice = 0 AND sourcefile.id IN (SELECT sourcefile FROM machine WHERE shortname GLOB ?)' \
+ 'ORDER BY machine.shortname ASC',
+ (pattern, ))
+ else:
+ return self.dbcurs.execute(
+ 'SELECT sourcefile.filename, machine.shortname, cloneof.parent ' \
+ 'FROM machine JOIN sourcefile ON machine.sourcefile = sourcefile.id LEFT JOIN cloneof ON machine.id = cloneof.id ' \
+ 'WHERE machine.isdevice = 0 ' \
+ 'ORDER BY machine.shortname ASC')
+
+ def listaffected(self, *patterns):
+ if 1 == len(patterns):
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine ' \
+ 'WHERE id IN (SELECT machine FROM devicereference WHERE device IN (SELECT shortname FROM machine WHERE sourcefile IN (SELECT id FROM sourcefile WHERE filename GLOB ?))) AND runnable = 1 ' \
+ 'ORDER BY shortname ASC',
+ patterns)
+ elif self.is_glob(*patterns):
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine ' \
+ 'WHERE id IN (SELECT machine FROM devicereference WHERE device IN (SELECT shortname FROM machine WHERE sourcefile IN (SELECT id FROM sourcefile WHERE filename GLOB ?' + (' OR filename GLOB ?' * (len(patterns) - 1)) + '))) AND runnable = 1 ' \
+ 'ORDER BY shortname ASC',
+ patterns)
+ else:
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine ' \
+ 'WHERE id IN (SELECT machine FROM devicereference WHERE device IN (SELECT shortname FROM machine WHERE sourcefile IN (SELECT id FROM sourcefile WHERE filename IN (?' + (', ?' * (len(patterns) - 1)) + ')))) AND runnable = 1 ' \
+ 'ORDER BY shortname ASC',
+ patterns)
+
+ def get_machine_info(self, machine):
+ return self.dbcurs.execute(
+ 'SELECT machine.id AS id, machine.description AS description, machine.isdevice AS isdevice, machine.runnable AS runnable, sourcefile.filename AS sourcefile, system.year AS year, system.manufacturer AS manufacturer, cloneof.parent AS cloneof, romof.parent AS romof ' \
+ 'FROM machine JOIN sourcefile ON machine.sourcefile = sourcefile.id LEFT JOIN system ON machine.id = system.id LEFT JOIN cloneof ON system.id = cloneof.id LEFT JOIN romof ON system.id = romof.id ' \
+ 'WHERE machine.shortname = ?',
+ (machine, ))
+
+ def get_devices_referenced(self, machine):
+ return self.dbcurs.execute(
+ 'SELECT devicereference.device AS shortname, machine.description AS description ' \
+ 'FROM devicereference LEFT JOIN machine ON devicereference.device = machine.shortname ' \
+ 'WHERE devicereference.machine = ? ' \
+ 'ORDER BY machine.description ASC, devicereference.device ASC',
+ (machine, ))
+
+ def get_device_references(self, shortname):
+ return self.dbcurs.execute(
+ 'SELECT shortname, description ' \
+ 'FROM machine ' \
+ 'WHERE id IN (SELECT machine FROM devicereference WHERE device = ?) ' \
+ 'ORDER BY description ASC',
+ (shortname, ))
+
+
+class UpdateCursor(object):
+ def __init__(self, dbconn, **kwargs):
+ super(UpdateCursor, self).__init__(**kwargs)
+ self.dbcurs = dbconn.cursor()
+
+ def close(self):
+ self.dbcurs.close()
+
+ def add_featuretype(self, name):
+ self.dbcurs.execute(UpdateQueries.ADD_FEATURETYPE, (name, ))
+
+ def add_sourcefile(self, filename):
+ self.dbcurs.execute(UpdateQueries.ADD_SOURCEFILE, (filename, ))
+
+ def add_machine(self, shortname, description, sourcefile, isdevice, runnable):
+ self.dbcurs.execute(UpdateQueries.ADD_MACHINE, (shortname, description, isdevice, runnable, sourcefile))
+ return self.dbcurs.lastrowid
+
+ def add_system(self, machine, year, manufacturer):
+ self.dbcurs.execute(UpdateQueries.ADD_SYSTEM, (machine, year, manufacturer))
+ return self.dbcurs.lastrowid
+
+ def add_cloneof(self, machine, parent):
+ self.dbcurs.execute(UpdateQueries.ADD_CLONEOF, (machine, parent))
+ return self.dbcurs.lastrowid
+
+ def add_romof(self, machine, parent):
+ self.dbcurs.execute(UpdateQueries.ADD_ROMOF, (machine, parent))
+ return self.dbcurs.lastrowid
+
+ def add_devicereference(self, machine, device):
+ self.dbcurs.execute(UpdateQueries.ADD_DEVICEREFERENCE, (machine, device))
+
+ def add_dipswitch(self, machine, isconfig, name, tag, mask):
+ self.dbcurs.execute(UpdateQueries.ADD_DIPSWITCH, (machine, isconfig, name, tag, mask))
+ return self.dbcurs.lastrowid
+
+ def add_diplocation(self, dipswitch, bit, name, num, inverted):
+ self.dbcurs.execute(UpdateQueries.ADD_DIPLOCATION, (dipswitch, bit, name, num, inverted))
+ return self.dbcurs.lastrowid
+
+ def add_dipvalue(self, dipswitch, name, value, isdefault):
+ self.dbcurs.execute(UpdateQueries.ADD_DIPVALUE, (dipswitch, name, value, isdefault))
+ return self.dbcurs.lastrowid
+
+ def add_feature(self, machine, featuretype, status, overall):
+ self.dbcurs.execute(UpdateQueries.ADD_FEATURE, (machine, status, overall, featuretype))
+ return self.dbcurs.lastrowid
+
+
+class QueryConnection(object):
+ def __init__(self, database, **kwargs):
+ # TODO: detect python versions that allow URL-based read-only connection
+ super(QueryConnection, self).__init__(**kwargs)
+ self.dbconn = sqlite3.connect(database)
+ self.dbconn.row_factory = sqlite3.Row
+ self.dbconn.execute('PRAGMA foreign_keys = ON')
+
+ def close(self):
+ self.dbconn.close()
+
+ def cursor(self):
+ return QueryCursor(self.dbconn)
+
+
+class UpdateConnection(object):
+ def __init__(self, database, **kwargs):
+ super(UpdateConnection, self).__init__(**kwargs)
+ self.dbconn = sqlite3.connect(database)
+ self.dbconn.execute('PRAGMA foreign_keys = ON')
+
+ def commit(self):
+ self.dbconn.commit()
+
+ def rollback(self):
+ self.dbconn.rollback()
+
+ def close(self):
+ self.dbconn.close()
+
+ def cursor(self):
+ return UpdateCursor(self.dbconn)
+
+ def drop_indexes(self):
+ self.dbconn.execute(SchemaQueries.DROP_MACHINE_ISDEVICE_SHORTNAME)
+ self.dbconn.execute(SchemaQueries.DROP_MACHINE_ISDEVICE_DESCRIPTION)
+ self.dbconn.execute(SchemaQueries.DROP_MACHINE_RUNNABLE_SHORTNAME)
+ self.dbconn.execute(SchemaQueries.DROP_MACHINE_RUNNABLE_DESCRIPTION)
+ self.dbconn.execute(SchemaQueries.DROP_SYSTEM_YEAR)
+ self.dbconn.execute(SchemaQueries.DROP_SYSTEM_MANUFACTURER)
+ self.dbconn.execute(SchemaQueries.DROP_ROMOF_PARENT)
+ self.dbconn.execute(SchemaQueries.DROP_CLONEOF_PARENT)
+ self.dbconn.execute(SchemaQueries.DROP_DEVICEREFERENCE_DEVICE)
+ self.dbconn.execute(SchemaQueries.DROP_DIPSWITCH_MACHINE_ISCONFIG)
+ self.dbconn.commit()
+
+ def create_indexes(self):
+ self.dbconn.execute(SchemaQueries.INDEX_MACHINE_ISDEVICE_SHORTNAME)
+ self.dbconn.execute(SchemaQueries.INDEX_MACHINE_ISDEVICE_DESCRIPTION)
+ self.dbconn.execute(SchemaQueries.INDEX_MACHINE_RUNNABLE_SHORTNAME)
+ self.dbconn.execute(SchemaQueries.INDEX_MACHINE_RUNNABLE_DESCRIPTION)
+ self.dbconn.execute(SchemaQueries.INDEX_SYSTEM_YEAR)
+ self.dbconn.execute(SchemaQueries.INDEX_SYSTEM_MANUFACTURER)
+ self.dbconn.execute(SchemaQueries.INDEX_ROMOF_PARENT)
+ self.dbconn.execute(SchemaQueries.INDEX_CLONEOF_PARENT)
+ self.dbconn.execute(SchemaQueries.INDEX_DEVICEREFERENCE_DEVICE)
+ self.dbconn.execute(SchemaQueries.INDEX_DIPSWITCH_MACHINE_ISCONFIG)
+ self.dbconn.commit()
diff --git a/scripts/minimaws/lib/htmltmpl.py b/scripts/minimaws/lib/htmltmpl.py
new file mode 100644
index 00000000000..2c71fea9fb9
--- /dev/null
+++ b/scripts/minimaws/lib/htmltmpl.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+import string
+
+
+MACHINE_PROLOGUE = string.Template(
+ '\n' \
+ '\n' \
+ '
\n' \
+ ' \n' \
+ ' ${description} (${shortname})\n' \
+ '\n' \
+ '\n' \
+ '${description}
\n' \
+ '\n' \
+ ' Short name: | ${shortname} |
\n' \
+ ' Is device: | ${isdevice} |
\n' \
+ ' Runnable: | ${runnable} |
\n' \
+ ' Source file: | ${sourcefile} |
\n')
diff --git a/scripts/minimaws/lib/lxparse.py b/scripts/minimaws/lib/lxparse.py
new file mode 100644
index 00000000000..f9061bcb798
--- /dev/null
+++ b/scripts/minimaws/lib/lxparse.py
@@ -0,0 +1,227 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+from . import dbaccess
+
+import subprocess
+import xml.sax
+import xml.sax.saxutils
+
+
+class ElementHandlerBase(object):
+ def __init__(self, parent, **kwargs):
+ super(ElementHandlerBase, self).__init__(**kwargs)
+ self.dbconn = parent.dbconn if parent is not None else None
+ self.locator = parent.locator if parent is not None else None
+ self.depth = 0
+ self.childhandler = None
+ self.childdepth = 0
+
+ def startMainElement(self, name, attrs):
+ pass
+
+ def endMainElement(self, name):
+ pass
+
+ def mainCharacters(self, content):
+ pass
+
+ def mainIgnorableWitespace(self, whitespace):
+ pass
+
+ def startChildElement(self, name, attrs):
+ pass
+
+ def endChildElement(self, name):
+ pass
+
+ def childCharacters(self, content):
+ pass
+
+ def childIgnorableWitespace(self, whitespace):
+ pass
+
+ def endChildHandler(self, name, handler):
+ pass
+
+ def setChildHandler(self, name, attrs, handler):
+ self.depth -= 1
+ self.childhandler = handler
+ self.childdepth += 1
+ handler.startElement(name, attrs)
+
+ def setDocumentLocator(self, locator):
+ self.locator = locator
+
+ def startElement(self, name, attrs):
+ if self.childhandler is not None:
+ self.childdepth += 1
+ self.childhandler.startElement(name, attrs)
+ else:
+ self.depth += 1
+ if 1 == self.depth:
+ self.startMainElement(name, attrs)
+ else:
+ self.startChildElement(name, attrs)
+
+ def endElement(self, name):
+ if self.childhandler is not None:
+ self.childdepth -= 1
+ self.childhandler.endElement(name)
+ if 0 == self.childdepth:
+ self.endChildHandler(name, self.childhandler)
+ self.childhandler = None
+ else:
+ self.depth -= 1
+ if 0 == self.depth:
+ self.endMainElement(name)
+ else:
+ self.endChildElement(name)
+
+ def characters(self, content):
+ if self.childhandler is not None:
+ self.childhandler.characters(content)
+ elif 1 < self.depth:
+ self.childCharacters(content)
+ else:
+ self.mainCharacters(content)
+
+ def ignorableWhitespace(self, content):
+ if self.childhandler is not None:
+ self.childhandler.ignorableWhitespace(content)
+ elif 1 < self.depth:
+ self.childIgnorableWitespace(content)
+ else:
+ self.mainIgnorableWitespace(content)
+
+
+class ElementHandler(ElementHandlerBase):
+ IGNORE = ElementHandlerBase(parent=None)
+
+
+class TextAccumulator(ElementHandler):
+ def __init__(self, parent, **kwargs):
+ super(TextAccumulator, self).__init__(parent=parent, **kwargs)
+ self.text = ''
+
+ def mainCharacters(self, content):
+ self.text += content
+
+
+class DipSwitchHandler(ElementHandler):
+ def __init__(self, parent, **kwargs):
+ super(DipSwitchHandler, self).__init__(parent=parent, **kwargs)
+ self.dbcurs = parent.dbcurs
+ self.machine = parent.id
+
+ def startMainElement(self, name, attrs):
+ self.mask = int(attrs['mask'])
+ self.bit = 0
+ self.id = self.dbcurs.add_dipswitch(self.machine, name == 'configuration', attrs['name'], attrs['tag'], self.mask)
+
+ def startChildElement(self, name, attrs):
+ if (name == 'diplocation') or (name == 'conflocation'):
+ while (0 != self.mask) and not (self.mask & 1):
+ self.mask >>= 1
+ self.bit += 1
+ self.dbcurs.add_diplocation(self.id, self.bit, attrs['name'], attrs['number'], attrs['inverted'] == 'yes' if 'inverted' in attrs else False)
+ self.mask >>= 1
+ self.bit += 1
+ elif (name == 'dipvalue') or (name == 'confsetting'):
+ self.dbcurs.add_dipvalue(self.id, attrs['name'], attrs['value'], attrs['default'] == 'yes' if 'default' in attrs else False)
+ self.setChildHandler(name, attrs, self.IGNORE)
+
+
+class MachineHandler(ElementHandler):
+ def __init__(self, parent, **kwargs):
+ super(MachineHandler, self).__init__(parent=parent, **kwargs)
+ self.dbcurs = self.dbconn.cursor()
+
+ def startMainElement(self, name, attrs):
+ self.shortname = attrs['name']
+ self.sourcefile = attrs['sourcefile']
+ self.isdevice = attrs['isdevice'] == 'yes' if 'isdevice' in attrs else False
+ self.runnable = attrs['runnable'] == 'yes' if 'runnable' in attrs else True
+ self.cloneof = attrs.get('cloneof')
+ self.romof = attrs.get('romof')
+ self.dbcurs.add_sourcefile(self.sourcefile)
+
+ def startChildElement(self, name, attrs):
+ if (name == 'description') or (name == 'year') or (name == 'manufacturer'):
+ self.setChildHandler(name, attrs, TextAccumulator(self))
+ elif (name == 'dipswitch') or (name == 'configuration'):
+ self.setChildHandler(name, attrs, DipSwitchHandler(self))
+ else:
+ if name == 'device_ref':
+ self.dbcurs.add_devicereference(self.id, attrs['name'])
+ elif name == 'feaure':
+ self.dbcurs.add_featuretype(attrs['type'])
+ status = 0 if 'status' not in attrs else 2 if attrs['status'] == 'unemulated' else 1
+ overall = status if 'overall' not in attrs else 2 if attrs['overall'] == 'unemulated' else 1
+ self.dbcurs.add_feature(self.id, attrs['type'], status, overall)
+ self.setChildHandler(name, attrs, self.IGNORE)
+
+ def endChildHandler(self, name, handler):
+ if name == 'description':
+ self.description = handler.text
+ self.id = self.dbcurs.add_machine(self.shortname, self.description, self.sourcefile, self.isdevice, self.runnable)
+ if self.cloneof is not None:
+ self.dbcurs.add_cloneof(self.id, self.cloneof)
+ if self.romof is not None:
+ self.dbcurs.add_romof(self.id, self.romof)
+ elif name == 'year':
+ self.year = handler.text
+ elif name == 'manufacturer':
+ self.manufacturer = handler.text
+ self.dbcurs.add_system(self.id, self.year, self.manufacturer)
+
+ def endMainElement(self, name):
+ self.dbconn.commit()
+ self.dbcurs.close()
+
+
+class ListXmlHandler(ElementHandler):
+ def __init__(self, dbconn, **kwargs):
+ super(ListXmlHandler, self).__init__(parent=None, **kwargs)
+ self.dbconn = dbconn
+
+ def startDocument(self):
+ pass
+
+ def endDocument(self):
+ pass
+
+ def startMainElement(self, name, attrs):
+ if name != 'mame':
+ raise xml.sax.SAXParseException(
+ msg=('Expected "mame" element but found "%s"' % (name, )),
+ exception=None,
+ locator=self.locator)
+ self.dbconn.drop_indexes()
+
+ def endMainElement(self, name):
+ # TODO: build index by first letter or whatever
+ self.dbconn.create_indexes()
+
+ def startChildElement(self, name, attrs):
+ if name != 'machine':
+ raise xml.sax.SAXParseException(
+ msg=('Expected "machine" element but found "%s"' % (name, )),
+ exception=None,
+ locator=self.locator)
+ self.setChildHandler(name, attrs, MachineHandler(self))
+
+ def processingInstruction(self, target, data):
+ pass
+
+
+def load_info(options):
+ parser = xml.sax.make_parser()
+ parser.setContentHandler(ListXmlHandler(dbaccess.UpdateConnection(options.database)))
+ if options.executable is not None:
+ task = subprocess.Popen([options.executable, '-listxml'], stdout=subprocess.PIPE)
+ parser.parse(task.stdout)
+ else:
+ parser.parse(options.file)
diff --git a/scripts/minimaws/lib/wsgiserve.py b/scripts/minimaws/lib/wsgiserve.py
new file mode 100644
index 00000000000..96ea43f35c5
--- /dev/null
+++ b/scripts/minimaws/lib/wsgiserve.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+from . import dbaccess
+from . import htmltmpl
+
+import cgi
+import sys
+import wsgiref.simple_server
+import wsgiref.util
+
+if sys.version_info > (3, ):
+ import urllib.parse as urlparse
+else:
+ import urlparse
+
+
+class MachineHandler(object):
+ def __init__(self, app, application_uri, environ, start_response, **kwargs):
+ super(MachineHandler, self).__init__(**kwargs)
+ self.application_uri = application_uri
+ self.environ = environ
+ self.start_response = start_response
+ self.dbcurs = app.dbconn.cursor()
+ self.shortname = wsgiref.util.shift_path_info(environ)
+
+ def __iter__(self):
+ if not self.shortname:
+ # could probably list machines here or something
+ self.start_response('403 Forbidden', [('Content-type', 'text/plain')])
+ yield '403 Forbidden'.encode('utf-8')
+ elif self.environ['PATH_INFO']:
+ # subdirectory of a machine
+ self.start_response('404 Not Found', [('Content-type', 'text/plain')])
+ yield '404 Not Found'.encode('utf-8')
+ else:
+ machine_info = self.dbcurs.get_machine_info(self.shortname).fetchone()
+ if not machine_info:
+ self.start_response('404 Not Found', [('Content-type', 'text/plain')])
+ yield '404 Not Found'.encode('utf-8')
+ else:
+ self.start_response('200 OK', [('Content-type', 'text/html; chearset=utf-8')])
+ description = machine_info['description']
+ yield htmltmpl.MACHINE_PROLOGUE.substitute(
+ description=cgi.escape(description),
+ shortname=cgi.escape(self.shortname),
+ isdevice=cgi.escape('Yes' if machine_info['isdevice'] else 'No'),
+ runnable=cgi.escape('Yes' if machine_info['runnable'] else 'No'),
+ sourcefile=cgi.escape(machine_info['sourcefile'])).encode('utf-8')
+ if machine_info['year'] is not None:
+ yield (
+ ' Year: | %s |
\n' \
+ ' Manufacturer: | %s |
\n' %
+ (cgi.escape(machine_info['year']), cgi.escape(machine_info['Manufacturer']))).encode('utf-8')
+ if machine_info['cloneof'] is not None:
+ parent = self.dbcurs.listfull(machine_info['cloneof']).fetchone()
+ if parent:
+ yield (
+ ' Parent Machine: | %s (%s) |
\n' %
+ (cgi.escape('%s/machine/%s' % (self.application_uri, machine_info['cloneof']), True), cgi.escape(parent[1]), cgi.escape(machine_info['cloneof']))).encode('utf-8')
+ else:
+ yield (
+ ' Parent Machine: | %s |
\n' %
+ (cgi.escape('%s/machine/%s' % (self.application_uri, machine_info['cloneof']), True), cgi.escape(machine_info['cloneof']))).encode('utf-8')
+ if (machine_info['romof'] is not None) and (machine_info['romof'] != machine_info['cloneof']):
+ parent = self.dbcurs.listfull(machine_info['romof']).fetchone()
+ if parent:
+ yield (
+ ' Parent ROM set: | %s (%s) |
\n' %
+ (cgi.escape('%s/machine/%s' % (self.application_uri, machine_info['romof']), True), cgi.escape(parent[1]), cgi.escape(machine_info['romof']))).encode('utf-8')
+ else:
+ yield (
+ ' Parent Machine: | %s |
\n' %
+ (cgi.escape('%s/machine/%s' % (self.application_uri, machine_info['romof']), True), cgi.escape(machine_info['romof']))).encode('utf-8')
+ yield '
\n'.encode('utf-8')
+
+ devices = self.dbcurs.get_devices_referenced(machine_info['id'])
+ first = True
+ for name, desc in devices:
+ if first:
+ yield 'Devices Referenced
\n\n'.encode('utf-8')
+ first = False
+ if desc is not None:
+ yield (
+ ' - %s (%s)
\n' %
+ (self.machine_href(name), cgi.escape(desc), cgi.escape(name))).encode('utf-8')
+ else:
+ yield (
+ ' - %s
\n' %
+ (self.machine_href(name), cgi.escape(name))).encode('utf-8')
+ if not first:
+ yield '
\n'.encode('utf-8')
+
+ devices = self.dbcurs.get_device_references(self.shortname)
+ first = True
+ for name, desc in devices:
+ if first:
+ yield 'Referenced By
\n\n'.encode('utf-8')
+ first = False
+ yield (
+ ' - %s (%s)
\n' %
+ (self.machine_href(name), cgi.escape(desc), cgi.escape(name))).encode('utf-8')
+ if not first:
+ yield '
\n'.encode('utf-8')
+
+ yield '\n'.encode('utf-8')
+
+ def machine_href(self, shortname):
+ return cgi.escape(urlparse.urljoin(self.application_uri, 'machine/%s' % (shortname, )), True)
+
+
+class MiniMawsApp(object):
+ def __init__(self, dbfile, **kwargs):
+ super(MiniMawsApp, self).__init__(**kwargs)
+ self.dbconn = dbaccess.QueryConnection(dbfile)
+
+ def __call__(self, environ, start_response):
+ application_uri = wsgiref.util.application_uri(environ)
+ module = wsgiref.util.shift_path_info(environ)
+ if module == 'machine':
+ return MachineHandler(self, application_uri, environ, start_response)
+ else:
+ start_response('200 OK', [('Content-type', 'text/plain')])
+ return ('Module is %s\n' % (module, ), )
+
+
+def run_server(options):
+ application = MiniMawsApp(options.database)
+ server = wsgiref.simple_server.make_server(options.host, options.port, application)
+ try:
+ server.serve_forever()
+ except KeyboardInterrupt:
+ pass
diff --git a/scripts/minimaws/minimaws.py b/scripts/minimaws/minimaws.py
new file mode 100755
index 00000000000..12ddc865b56
--- /dev/null
+++ b/scripts/minimaws/minimaws.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+##
+## license:BSD-3-Clause
+## copyright-holders:Vas Crabb
+
+import lib.auxverbs
+import lib.lxparse
+import lib.wsgiserve
+
+import argparse
+import sys
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--database', metavar='', default='minimaws.sqlite3', help='SQLite 3 info database file (defaults to minimaws.sqlite3)')
+ subparsers = parser.add_subparsers(title='commands', dest='command', metavar='')
+
+ subparser = subparsers.add_parser('listfull', help='list short names and full names')
+ subparser.add_argument('pattern', nargs='?', metavar='', help='short name glob pattern')
+
+ subparser = subparsers.add_parser('listsource', help='list short names and source files')
+ subparser.add_argument('pattern', nargs='?', metavar='', help='short name glob pattern')
+
+ subparser = subparsers.add_parser('listclones', help='show clones')
+ subparser.add_argument('pattern', nargs='?', metavar='', help='short name/parent glob pattern')
+
+ subparser = subparsers.add_parser('listbrothers', help='show drivers from the same source file(s)')
+ subparser.add_argument('pattern', nargs='?', metavar='', help='short name glob pattern')
+
+ subparser = subparsers.add_parser('listaffected', help='show drivers affected by source change(s)')
+ subparser.add_argument('pattern', nargs='+', metavar='', help='source file glob pattern')
+
+ subparser = subparsers.add_parser('serve', help='serve over HTTP')
+ subparser.add_argument('--port', metavar='', default=8080, type=int, help='server TCP port')
+ subparser.add_argument('--host', metavar='', default='', help='server TCP hostname')
+
+ subparser = subparsers.add_parser('load', help='load machine information')
+ group = subparser.add_mutually_exclusive_group(required=True)
+ group.add_argument('--executable', metavar='', help='emulator executable')
+ group.add_argument('--file', metavar='', help='XML machine information file')
+
+ options = parser.parse_args()
+ if options.command == 'listfull':
+ lib.auxverbs.do_listfull(options)
+ elif options.command == 'listsource':
+ lib.auxverbs.do_listsource(options)
+ elif options.command == 'listclones':
+ lib.auxverbs.do_listclones(options)
+ elif options.command == 'listbrothers':
+ lib.auxverbs.do_listbrothers(options)
+ elif options.command == 'listaffected':
+ lib.auxverbs.do_listaffected(options)
+ elif options.command == 'serve':
+ lib.wsgiserve.run_server(options)
+ elif options.command == 'load':
+ lib.lxparse.load_info(options)
+ else:
+ print('%s' % (options, ))
diff --git a/scripts/minimaws/schema.sql b/scripts/minimaws/schema.sql
new file mode 100644
index 00000000000..7633441a123
--- /dev/null
+++ b/scripts/minimaws/schema.sql
@@ -0,0 +1,84 @@
+PRAGMA page_size = 4096;
+PRAGMA foreign_keys = ON;
+
+CREATE TABLE featuretype (
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL,
+ UNIQUE (name ASC));
+
+CREATE TABLE sourcefile (
+ id INTEGER PRIMARY KEY,
+ filename TEXT NOT NULL,
+ UNIQUE (filename ASC));
+
+CREATE TABLE machine (
+ id INTEGER PRIMARY KEY,
+ shortname TEXT NOT NULL,
+ description TEXT NOT NULL,
+ sourcefile INTEGER NOT NULL,
+ isdevice INTEGER NOT NULL,
+ runnable INTEGER NOT NULL,
+ UNIQUE (shortname ASC),
+ UNIQUE (description ASC),
+ FOREIGN KEY (sourcefile) REFERENCES sourcefile (id));
+
+CREATE TABLE system (
+ id INTEGER PRIMARY KEY,
+ year TEXT NOT NULL,
+ manufacturer TEXT NOT NULL,
+ FOREIGN KEY (id) REFERENCES machine (id));
+
+CREATE TABLE cloneof (
+ id INTEGER PRIMARY KEY,
+ parent TEXT NOT NULL,
+ FOREIGN KEY (id) REFERENCES machine (id));
+
+CREATE TABLE romof (
+ id INTEGER PRIMARY KEY,
+ parent TEXT NOT NULL,
+ FOREIGN KEY (id) REFERENCES machine (id));
+
+CREATE TABLE devicereference (
+ id INTEGER PRIMARY KEY,
+ machine INTEGER NOT NULL,
+ device TEXT NOT NULL,
+ UNIQUE (machine ASC, device ASC),
+ FOREIGN KEY (machine) REFERENCES machine (id));
+
+CREATE TABLE dipswitch (
+ id INTEGER PRIMARY KEY,
+ machine INTEGER NOT NULL,
+ isconfig INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ tag TEXT NOT NULL,
+ mask INTEGER NOT NULL,
+ --UNIQUE (machine ASC, tag ASC, mask ASC), not necessarily true, need to expose port conditions
+ FOREIGN KEY (machine) REFERENCES machine (id));
+
+CREATE TABLE diplocation (
+ id INTEGER PRIMARY KEY,
+ dipswitch INTEGER NOT NULL,
+ bit INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ num INTEGER NOT NULL,
+ inverted INTEGER NOT NULL,
+ UNIQUE (dipswitch ASC, bit ASC),
+ FOREIGN KEY (dipswitch) REFERENCES dipswitch (id));
+
+CREATE TABLE dipvalue (
+ id INTEGER PRIMARY KEY,
+ dipswitch INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ value INTEGER NOT NULL,
+ isdefault INTEGER NOT NULL,
+ FOREIGN KEY (dipswitch) REFERENCES dipswitch (id));
+
+CREATE TABLE feature (
+ id INTEGER PRIMARY KEY,
+ machine INTEGER NOT NULL,
+ featuretype INTEGER NOT NULL,
+ status INTEGER NOT NULL,
+ overall INTEGER NOT NULL,
+ UNIQUE (machine ASC, featuretype ASC),
+ FOREIGN KEY (machine) REFERENCES machine (id),
+ FOREIGN KEY (featuretype) REFERENCES featuretype (id));
diff --git a/src/devices/bus/intellec4/intellec4.cpp b/src/devices/bus/intellec4/intellec4.cpp
index 65ea12e743f..7034d4c7b27 100644
--- a/src/devices/bus/intellec4/intellec4.cpp
+++ b/src/devices/bus/intellec4/intellec4.cpp
@@ -7,8 +7,8 @@
#include
-DEFINE_DEVICE_TYPE_NS(INTELLEC4_UNIV_SLOT, bus::intellec4, univ_slot_device, "intlc4univslot", "INTELLEC 4/MOD 40 Universal Slot")
-DEFINE_DEVICE_TYPE_NS(INTELLEC4_UNIV_BUS, bus::intellec4, univ_bus_device, "intlc4univbus", "INTELLEC 4/MOD 40 Universal Bus")
+DEFINE_DEVICE_TYPE_NS(INTELLEC4_UNIV_SLOT, bus::intellec4, univ_slot_device, "intlc4univslot", "INTELLEC 4 Universal Slot")
+DEFINE_DEVICE_TYPE_NS(INTELLEC4_UNIV_BUS, bus::intellec4, univ_bus_device, "intlc4univbus", "INTELLEC 4 Universal Bus")
namespace bus { namespace intellec4 {
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 872d0e7df29..dc488903cb0 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -353,7 +353,7 @@ void cli_frontend::listfull(const std::vector &args)
// determine which drivers to output; return an error if none found
driver_enumerator drivlist(m_options, gamename);
if (drivlist.count() == 0)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename);
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
// print the header
osd_printf_info("Name: Description:\n");
@@ -377,7 +377,7 @@ void cli_frontend::listsource(const std::vector &args)
// determine which drivers to output; return an error if none found
driver_enumerator drivlist(m_options, gamename);
if (drivlist.count() == 0)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename);
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
// iterate through drivers and output the info
while (drivlist.next())
@@ -396,13 +396,13 @@ void cli_frontend::listclones(const std::vector &args)
// start with a filtered list of drivers
driver_enumerator drivlist(m_options, gamename);
- int original_count = drivlist.count();
+ int const original_count = drivlist.count();
// iterate through the remaining ones to see if their parent matches
while (drivlist.next_excluded())
{
// if we have a non-bios clone and it matches, keep it
- int clone_of = drivlist.clone();
+ int const clone_of = drivlist.clone();
if ((clone_of >= 0) && !(drivlist.driver(clone_of).flags & machine_flags::IS_BIOS_ROOT))
if (drivlist.matches(gamename, drivlist.driver(clone_of).name))
drivlist.include();
@@ -413,9 +413,9 @@ void cli_frontend::listclones(const std::vector &args)
{
// see if we match but just weren't a clone
if (original_count == 0)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename);
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
else
- osd_printf_info("Found %lu matches for '%s' but none were clones\n", (unsigned long)drivlist.count(), gamename);
+ osd_printf_info("Found %lu match(es) for '%s' but none were clones\n", (unsigned long)drivlist.count(), gamename); // FIXME: this never gets hit
return;
}
@@ -446,7 +446,7 @@ void cli_frontend::listbrothers(const std::vector &args)
// start with a filtered list of drivers; return an error if none found
driver_enumerator initial_drivlist(m_options, gamename);
if (initial_drivlist.count() == 0)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching games found for '%s'", gamename);
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
// for the final list, start with an empty driver list
driver_enumerator drivlist(m_options);
diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp
index a6d63c34847..01872db6a51 100644
--- a/src/frontend/mame/info.cpp
+++ b/src/frontend/mame/info.cpp
@@ -123,18 +123,26 @@ const char info_xml_creator::s_dtd_string[] =
"\t\t\t\t\n"
"\t\t\t\t\n"
"\t\t\t\t\n"
-"\t\t\n"
+"\t\t\n"
"\t\t\t\n"
"\t\t\t\n"
"\t\t\t\n"
+"\t\t\t\n"
+"\t\t\t\t\n"
+"\t\t\t\t\n"
+"\t\t\t\t\n"
"\t\t\t\n"
"\t\t\t\t\n"
"\t\t\t\t\n"
"\t\t\t\t\n"
-"\t\t\n"
+"\t\t\n"
"\t\t\t\n"
"\t\t\t\n"
"\t\t\t\n"
+"\t\t\t\n"
+"\t\t\t\t\n"
+"\t\t\t\t\n"
+"\t\t\t\t\n"
"\t\t\t\n"
"\t\t\t\t\n"
"\t\t\t\t\n"
@@ -466,14 +474,14 @@ void info_xml_creator::output_one(driver_enumerator &drivlist, device_type_set *
// now print various additional information
output_bios(driver);
output_rom(&drivlist, config->root_device());
- output_device_roms(config->root_device());
+ output_device_refs(config->root_device());
output_sample(config->root_device());
output_chips(config->root_device(), "");
output_display(config->root_device(), &drivlist.driver().flags, "");
output_sound(config->root_device());
output_input(portlist);
- output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "dipvalue");
- output_switches(portlist, "", IPT_CONFIG, "configuration", "confsetting");
+ output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
+ output_switches(portlist, "", IPT_CONFIG, "configuration", "conflocation", "confsetting");
output_ports(portlist);
output_adjusters(portlist);
output_driver(driver, overall_unemulated, overall_imperfect);
@@ -535,6 +543,7 @@ void info_xml_creator::output_one_device(machine_config &config, device_t &devic
fprintf(m_output, "\t\t%s\n", util::xml::normalize_string(device.name()));
output_rom(nullptr, device);
+ output_device_refs(device);
if (device.type().type() != typeid(samples_device)) // ignore samples_device itself
output_sample(device);
@@ -545,8 +554,8 @@ void info_xml_creator::output_one_device(machine_config &config, device_t &devic
output_sound(device);
if (has_input)
output_input(portlist);
- output_switches(portlist, devtag, IPT_DIPSWITCH, "dipswitch", "dipvalue");
- output_switches(portlist, devtag, IPT_CONFIG, "configuration", "confsetting");
+ output_switches(portlist, devtag, IPT_DIPSWITCH, "dipswitch", "diplocation", "dipvalue");
+ output_switches(portlist, devtag, IPT_CONFIG, "configuration", "conflocation", "confsetting");
output_adjusters(portlist);
output_features(device.type(), overall_unemulated, overall_imperfect);
output_images(device, devtag);
@@ -600,14 +609,14 @@ void info_xml_creator::output_devices(device_type_set const *filter)
//------------------------------------------------
-// output_device_roms - when a driver uses roms
-// included in a device set, print a reference
+// output_device_refs - when a machine uses a
+// subdevice, print a reference
//-------------------------------------------------
-void info_xml_creator::output_device_roms(device_t &root)
+void info_xml_creator::output_device_refs(device_t &root)
{
for (device_t &device : device_iterator(root))
- if (device.owner())
+ if (&device != &root)
fprintf(m_output, "\t\t\n", util::xml::normalize_string(device.shortname()));
}
@@ -1448,11 +1457,11 @@ void info_xml_creator::output_input(const ioport_list &portlist)
// DIP switch settings
//-------------------------------------------------
-void info_xml_creator::output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *innertag)
+void info_xml_creator::output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *loctag, const char *innertag)
{
// iterate looking for DIP switches
for (auto &port : portlist)
- for (ioport_field &field : port.second->fields())
+ for (ioport_field const &field : port.second->fields())
if (field.type() == type)
{
std::ostringstream output;
@@ -1461,15 +1470,22 @@ void info_xml_creator::output_switches(const ioport_list &portlist, const char *
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
// output the switch name information
- std::string normalized_field_name(util::xml::normalize_string(field.name()));
- std::string normalized_newtag(util::xml::normalize_string(newtag.c_str()));
- util::stream_format(output,"\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name.c_str(), normalized_newtag.c_str(), field.mask());
+ std::string const normalized_field_name(util::xml::normalize_string(field.name()));
+ std::string const normalized_newtag(util::xml::normalize_string(newtag.c_str()));
+ util::stream_format(output, "\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name.c_str(), normalized_newtag.c_str(), field.mask());
+
+ // loop over locations
+ for (ioport_diplocation const &diploc : field.diplocations())
+ {
+ util::stream_format(output, "\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, util::xml::normalize_string(diploc.name()), diploc.number());
+ if (diploc.inverted())
+ output << " inverted=\"yes\"";
+ output << "/>\n";
+ }
// loop over settings
- for (ioport_setting &setting : field.settings())
- {
+ for (ioport_setting const &setting : field.settings())
util::stream_format(output,"\t\t\t<%s name=\"%s\" value=\"%u\"%s/>\n", innertag, util::xml::normalize_string(setting.name()), setting.value(), setting.value() == field.defvalue() ? " default=\"yes\"" : "");
- }
// terminate the switch entry
util::stream_format(output,"\t\t%s>\n", outertag);
diff --git a/src/frontend/mame/info.h b/src/frontend/mame/info.h
index 635084a3a3b..f210ade6320 100644
--- a/src/frontend/mame/info.h
+++ b/src/frontend/mame/info.h
@@ -49,13 +49,13 @@ private:
void output_sampleof(device_t &device);
void output_bios(game_driver const &driver);
void output_rom(driver_enumerator *drivlist, device_t &device);
- void output_device_roms(device_t &root);
+ void output_device_refs(device_t &root);
void output_sample(device_t &device);
void output_chips(device_t &device, const char *root_tag);
void output_display(device_t &device, machine_flags::type const *flags, const char *root_tag);
void output_sound(device_t &device);
void output_input(const ioport_list &portlist);
- void output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *innertag);
+ void output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *loctag, const char *innertag);
void output_ports(const ioport_list &portlist);
void output_adjusters(const ioport_list &portlist);
void output_driver(game_driver const &driver, device_t::feature_type unemulated, device_t::feature_type imperfect);