230 lines
7.1 KiB
Python
230 lines
7.1 KiB
Python
import xml.dom.minidom
|
|
|
|
def constify(s):
|
|
s = s.replace('-', '_')
|
|
s = s.replace(' ', '_')
|
|
s = s.upper()
|
|
return s
|
|
|
|
def cify(s):
|
|
s = constify(s)
|
|
s = s.lower()
|
|
return s
|
|
|
|
def camelify(s):
|
|
s = constify(s)
|
|
s = s.split('_')
|
|
s = [s[0].lower()] + [w.capitalize() for w in s[1:]]
|
|
s = ''.join(s)
|
|
return s
|
|
|
|
ctypemap = {
|
|
'shortstr': 'cmsg_bytes_t',
|
|
'longstr': 'cmsg_bytes_t',
|
|
'table': 'cmsg_bytes_t', # TODO fix
|
|
'octet': 'uint8_t',
|
|
'short': 'uint16_t',
|
|
'long': 'uint32_t',
|
|
'longlong': 'uint64_t',
|
|
'bit': 'uint8_t',
|
|
'timestamp': 'uint64_t',
|
|
}
|
|
|
|
class Constant:
|
|
def __init__(self, e):
|
|
self.name = e.getAttribute('name')
|
|
self.value = e.getAttribute('value')
|
|
self.class_ = e.getAttribute('class') or None
|
|
|
|
def getName(self):
|
|
if self.class_:
|
|
return 'CMSG_AMQP_ERROR_' + constify(self.name)
|
|
else:
|
|
return 'CMSG_AMQP_' + constify(self.name)
|
|
|
|
def getValue(self):
|
|
return self.value
|
|
|
|
class Field:
|
|
def __init__(self, e):
|
|
self.name = e.getAttribute('name')
|
|
self.domain = e.getAttribute('domain') or e.getAttribute('type')
|
|
# self.reserved = bool(e.getAttribute('reserved'))
|
|
self.type = resolveDomain(self.domain)
|
|
|
|
def getName(self):
|
|
return cify(self.name)
|
|
|
|
def ctype(self):
|
|
return ctypemap[str(self.type)]
|
|
|
|
class Entity:
|
|
def __init__(self, parent, e):
|
|
self.parent = parent
|
|
self.name = e.getAttribute('name')
|
|
self.index = int(e.getAttribute('index'))
|
|
self.fields = [Field(ee) \
|
|
for ee in e.getElementsByTagName('field') \
|
|
if ee.parentNode is e]
|
|
|
|
def getName(self):
|
|
if self.parent:
|
|
return self.parent.getName() + '_' + cify(self.name)
|
|
else:
|
|
return cify(self.name)
|
|
|
|
def printStructDefExtras(self):
|
|
pass
|
|
|
|
def printStructDef(self, suffix):
|
|
if self.fields:
|
|
print
|
|
print 'typedef struct cmsg_amqp_%s_%s_t_ {' % (self.getName(), suffix)
|
|
self.printStructDefExtras()
|
|
for f in self.fields:
|
|
print ' %s %s;' % (f.ctype(), f.getName())
|
|
print '} cmsg_amqp_%s_%s_t;' % (self.getName(), suffix)
|
|
|
|
class BitWriter:
|
|
def __init__(self):
|
|
self.bit_offset = 0
|
|
|
|
def flush(self):
|
|
if self.bit_offset:
|
|
print ' write_amqp_octet(bit_buffer);'
|
|
self.bit_offset = 0
|
|
|
|
def emit(self, valueExpr):
|
|
if self.bit_offset == 0:
|
|
print ' bit_buffer = 0;'
|
|
print ' if (%s) bit_buffer |= 0x%02x;' % (valueExpr, 1 << self.bit_offset)
|
|
self.bit_offset += 1
|
|
if self.bit_offset == 8:
|
|
self.flush()
|
|
|
|
class Method(Entity):
|
|
def __init__(self, parent, e):
|
|
Entity.__init__(self, parent, e)
|
|
self.has_content = bool(e.getAttribute('content'))
|
|
self.synchronous = bool(e.getAttribute('synchronous'))
|
|
self.responses = [ee.getAttribute('name') for ee in e.getElementsByTagName('response')]
|
|
|
|
def methodId(self):
|
|
return self.parent.index << 16 | self.index
|
|
|
|
def printParseClause(self):
|
|
bit_offset = 0
|
|
print ' case 0x%08x: /* %s */ ' % (self.methodId(), self.getName())
|
|
for f in self.fields:
|
|
if f.type == 'bit':
|
|
if bit_offset == 0:
|
|
print ' if (!parse_amqp_octet(&bit_buffer, &input, &offset))'
|
|
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
|
|
print ' output->body.%s.%s = (bit_buffer & 0x%02x) != 0;' % \
|
|
(self.getName(), f.getName(), 1 << bit_offset)
|
|
bit_offset += 1
|
|
if bit_offset == 8: bit_offset = 0
|
|
else:
|
|
print ' if (!parse_amqp_%s(&output->body.%s.%s, &input, &offset))' % \
|
|
(f.type, self.getName(), f.getName())
|
|
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
|
|
print ' return 0;'
|
|
|
|
def printWriteClause(self):
|
|
bw = BitWriter()
|
|
print ' case 0x%08x: /* %s */ ' % (self.methodId(), self.getName())
|
|
for f in self.fields:
|
|
if f.type == 'bit':
|
|
bw.emit('output->body.%s.%s' % (self.getName(), f.getName()))
|
|
else:
|
|
bw.flush()
|
|
print ' write_amqp_%s(output->body.%s.%s);' % \
|
|
(f.type, self.getName(), f.getName())
|
|
bw.flush()
|
|
print ' break;'
|
|
|
|
class Class(Entity):
|
|
def __init__(self, e):
|
|
Entity.__init__(self, None, e)
|
|
self.methods = [Method(self, ee) for ee in e.getElementsByTagName('method')]
|
|
|
|
def printStructDefExtras(self):
|
|
print ' uint32_t _flags;'
|
|
|
|
def resolveDomain(n):
|
|
while n in domainmap and domainmap[n] != n:
|
|
n = domainmap[n]
|
|
return n
|
|
|
|
specxml = xml.dom.minidom.parse("amqp0-9-1.stripped.xml")
|
|
constants = [Constant(e) for e in specxml.getElementsByTagName('constant')]
|
|
domainmap = dict((e.getAttribute('name'), e.getAttribute('type')) \
|
|
for e in specxml.getElementsByTagName('domain'))
|
|
|
|
classes = [Class(e) for e in specxml.getElementsByTagName('class')]
|
|
classmap = dict((c.name, c) for c in classes)
|
|
|
|
def header():
|
|
print '/* TODO: put copyright etc */'
|
|
print '/* Generated from AMQP spec version %s.%s.%s */' % \
|
|
(specxml.documentElement.getAttribute('major'),
|
|
specxml.documentElement.getAttribute('minor'),
|
|
specxml.documentElement.getAttribute('revision'))
|
|
|
|
print
|
|
for c in constants:
|
|
print '#define %s %s' % (c.getName(), c.getValue())
|
|
|
|
for c in classes:
|
|
c.printStructDef('properties')
|
|
|
|
for c in classes:
|
|
for m in c.methods:
|
|
m.printStructDef('method')
|
|
|
|
print
|
|
print 'typedef struct cmsg_amqp_method_t_ {'
|
|
print ' uint32_t id;'
|
|
print ' union {'
|
|
for c in classes:
|
|
for m in c.methods:
|
|
if m.fields:
|
|
print ' cmsg_amqp_%s_method_t %s;' % (m.getName(), m.getName())
|
|
print ' } body;'
|
|
print '} cmsg_amqp_method_t;'
|
|
|
|
print
|
|
print 'int parse_amqp_method('
|
|
print ' cmsg_bytes_t input,'
|
|
print ' cmsg_amqp_method_t *output) {'
|
|
print ' size_t offset = 0;'
|
|
print ' uint8_t bit_buffer = 0;'
|
|
print ' if (!parse_amqp_long(&output->id, &input, &offset))'
|
|
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
|
|
print ' switch (output->id) {'
|
|
for c in classes:
|
|
for m in c.methods:
|
|
m.printParseClause()
|
|
print ' default:'
|
|
print ' warn("Invalid AMQP method number 0x%%08x", output->id);'
|
|
print ' return -CMSG_AMQP_ERROR_NOT_IMPLEMENTED;'
|
|
print ' }'
|
|
print '}'
|
|
|
|
print
|
|
print 'void write_amqp_method('
|
|
print ' IOHandle *h,'
|
|
print ' cmsg_amqp_method_t *m) {'
|
|
print ' uint8_t bit_buffer = 0;'
|
|
print ' write_amqp_long(&m->id);'
|
|
print ' switch (m->id) {'
|
|
for c in classes:
|
|
for m in c.methods:
|
|
m.printWriteClause()
|
|
print ' default:'
|
|
print ' die("Invalid AMQP method number 0x%%08x", m->id);'
|
|
print ' }'
|
|
print '}'
|
|
|
|
header()
|