summaryrefslogtreecommitdiffstatshomepage
path: root/scripts/build
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2016-11-20 20:54:10 +1100
committer Vas Crabb <vas@vastheman.com>2016-11-20 20:54:10 +1100
commit5eefcfdb684b94cbe41d41a7dcfd8b712bf86c6a (patch)
tree67e6de1567b0248322e06fefc6285acf769d633c /scripts/build
parentf7198793ee3d99b56b580d4014f0310c52e10298 (diff)
Rewrite complay.py to parse/minify layout XML
Doesn't make much difference to executable size, but it catches XML errors at build time rather than waiting for you to try the system (nw)
Diffstat (limited to 'scripts/build')
-rw-r--r--scripts/build/complay.py193
1 files changed, 138 insertions, 55 deletions
diff --git a/scripts/build/complay.py b/scripts/build/complay.py
index c8a61396dce..c44cc1e678f 100644
--- a/scripts/build/complay.py
+++ b/scripts/build/complay.py
@@ -1,69 +1,152 @@
#!/usr/bin/python
##
## license:BSD-3-Clause
-## copyright-holders:Aaron Giles, Andrew Gardner
+## copyright-holders:Vas Crabb
-from __future__ import with_statement
-
-import sys
import os
+import sys
+import xml.sax
+import xml.sax.saxutils
import zlib
-if len(sys.argv) < 4:
- print('Usage:')
- print(' complay <source.lay> <output.h> <varname>')
- print('')
- sys.exit(0)
-
-srcfile = sys.argv[1]
-dstfile = sys.argv[2]
-varname = sys.argv[3]
-type = 'uint8_t'
-
-try:
- myfile = open(srcfile, 'rb')
-except IOError:
- sys.stderr.write("Unable to open source file '%s'\n" % srcfile)
- sys.exit(-1)
-
-byteCount = os.path.getsize(srcfile)
-compsize = 0
-compressiontype = 1
-
-try:
- dst = open(dstfile,'w')
- dst.write('const %s %s_data[] =\n{\n\t' % ( type, varname))
- offs = 0
- with open(srcfile, "rb") as src:
- while True:
- chunk = src.read(byteCount)
- if chunk:
- compchunk = bytearray(zlib.compress(chunk, 9))
- compsize = len(compchunk)
- for b in compchunk:
- dst.write('%d' % b)
- offs += 1
- if offs != compsize:
- dst.write(',')
+
+class ErrorHandler(object):
+ def __init__(self, **kwargs):
+ super(ErrorHandler, self).__init__(**kwargs)
+ self.errors = 0
+ self.warnings = 0
+
+ def error(self, exception):
+ self.errors += 1
+ sys.stderr.write('error: %s' % (exception))
+
+ def fatalError(self, exception):
+ raise exception
+
+ def warning(self, exception):
+ self.warnings += 1
+ sys.stderr.write('warning: %s' % (exception))
+
+
+class Minifyer(object):
+ def __init__(self, output, **kwargs):
+ super(Minifyer, self).__init__(**kwargs)
+
+ self.output = output
+ self.incomplete_tag = False
+ self.element_content = ''
+
+ def setDocumentLocator(self, locator):
+ pass
+
+ def startDocument(self):
+ self.output('<?xml version="1.0"?>')
+
+ def endDocument(self):
+ self.output('\n')
+
+ def startElement(self, name, attrs):
+ self.flushElementContent()
+ if self.incomplete_tag:
+ self.output('>')
+ self.output('<%s' % (name))
+ for name in attrs.getNames():
+ self.output(' %s=%s' % (name, xml.sax.saxutils.quoteattr(attrs[name])))
+ self.incomplete_tag = True
+
+ def endElement(self, name):
+ self.flushElementContent()
+ if self.incomplete_tag:
+ self.output('/>')
+ else:
+ self.output('</%s>' % (name))
+ self.incomplete_tag = False
+
+ def characters(self, content):
+ self.element_content += content
+
+ def ignorableWhitespace(self, whitespace):
+ pass
+
+ def processingInstruction(self, target, data):
+ pass
+
+ def flushElementContent(self):
+ self.element_content = self.element_content.strip()
+ if self.element_content:
+ if self.incomplete_tag:
+ self.output('>')
+ self.incomplete_tag = False
+ self.output(xml.sax.saxutils.escape(self.element_content))
+ self.element_content = ''
+
+
+class XmlError(Exception):
+ pass
+
+
+def compressLayout(src, dst, comp):
+ state = [0, 0]
+ def write(block):
+ for ch in block:
+ if 0 == state[0]:
+ dst('\t')
+ elif 0 == (state[0] % 32):
+ dst(',\n\t')
else:
- break
- dst.write('\n\t')
+ dst(', ')
+ state[0] += 1
+ dst('%3u' % (ord(ch)))
+
+ def output(text):
+ block = text.encode('UTF-8')
+ state[1] += len(block)
+ write(comp.compress(block))
- dst.write('\n};\n')
+ error_handler = ErrorHandler()
+ content_handler = Minifyer(output)
+ parser = xml.sax.make_parser()
+ parser.setErrorHandler(error_handler)
+ parser.setContentHandler(content_handler)
+ try:
+ parser.parse(src)
+ write(comp.flush())
+ dst('\n')
+ except xml.sax.SAXException as exception:
+ print('fatal error: %s' % (exception))
+ raise XmlError('Fatal error parsing XML')
+ if (error_handler.errors > 0) or (error_handler.warnings > 0):
+ raise XmlError('Error(s) and/or warning(s) parsing XML')
-except IOError:
- sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
- sys.exit(-1)
+ return state[1], state[0]
-try:
- dst.write('extern const internal_layout %s;\n' % ( varname ))
- dst.write('const internal_layout %s = { \n\t' % ( varname ))
- dst.write('%d,%d,%d,%s_data\n' % ( byteCount, compsize, compressiontype, varname ))
- dst.write('\n};\n')
+if __name__ == '__main__':
+ if len(sys.argv) != 4:
+ print('Usage:')
+ print(' complay <source.lay> <output.h> <varname>')
+ sys.exit(0 if len(sys.argv) <= 1 else 1)
- dst.close()
-except IOError:
- sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
- sys.exit(-1)
+ srcfile = sys.argv[1]
+ dstfile = sys.argv[2]
+ varname = sys.argv[3]
+ comp_type = 1
+ try:
+ dst = open(dstfile,'w')
+ dst.write('static const unsigned char %s_data[] = {\n' % (varname))
+ byte_count, comp_size = compressLayout(srcfile, lambda x: dst.write(x), zlib.compressobj())
+ dst.write('};\n\n')
+ dst.write('const internal_layout %s = {\n' % (varname))
+ dst.write('\t%d, sizeof(%s_data), %d, %s_data\n' % (byte_count, varname, comp_type, varname))
+ dst.write('};\n')
+ dst.close()
+ except XmlError:
+ dst.close()
+ os.remove(dstfile)
+ sys.exit(2)
+ except IOError:
+ sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
+ os.remove(dstfile)
+ dst.close()
+ sys.exit(3)