generate_datatypes.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #!/usr/bin/env python
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this
  4. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. from __future__ import print_function
  6. import sys
  7. import time
  8. import platform
  9. import getpass
  10. from collections import OrderedDict
  11. import re
  12. import xml.etree.ElementTree as etree
  13. import itertools
  14. import argparse
  15. from nodeset_compiler.opaque_type_mapping import get_base_type_for_opaque
  16. types = OrderedDict() # contains types that were already parsed
  17. typedescriptions = {} # contains type nodeids
  18. excluded_types = ["NodeIdType", "InstanceNode", "TypeNode", "Node", "ObjectNode",
  19. "ObjectTypeNode", "VariableNode", "VariableTypeNode", "ReferenceTypeNode",
  20. "MethodNode", "ViewNode", "DataTypeNode",
  21. "NumericRange", "NumericRangeDimensions",
  22. "UA_ServerDiagnosticsSummaryDataType", "UA_SamplingIntervalDiagnosticsDataType",
  23. "UA_SessionSecurityDiagnosticsDataType", "UA_SubscriptionDiagnosticsDataType",
  24. "UA_SessionDiagnosticsDataType"]
  25. builtin_types = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
  26. "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
  27. "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode",
  28. "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
  29. "Variant", "DiagnosticInfo"]
  30. # If the type does not contain pointers, it can be copied with memcpy
  31. # (internally, not into the protocol message). This dict contains the sizes of
  32. # pointer-free types. Parsed types are added if they apply.
  33. builtin_pointerfree = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
  34. "Int64", "UInt64", "Float", "Double", "DateTime", "Guid", "StatusCode"]
  35. # Some types can be memcpy'd off the binary stream. That's especially important
  36. # for arrays. But we need to check if they contain padding and whether the
  37. # endianness is correct. This dict gives the C-statement that must be true for the
  38. # type to be overlayable. Parsed types are added if they apply.
  39. builtin_overlayable = {"Boolean": "true", "SByte": "true", "Byte": "true",
  40. "Int16": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt16": "UA_BINARY_OVERLAYABLE_INTEGER",
  41. "Int32": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt32": "UA_BINARY_OVERLAYABLE_INTEGER",
  42. "Int64": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt64": "UA_BINARY_OVERLAYABLE_INTEGER",
  43. "Float": "UA_BINARY_OVERLAYABLE_FLOAT", "Double": "UA_BINARY_OVERLAYABLE_FLOAT",
  44. "DateTime": "UA_BINARY_OVERLAYABLE_INTEGER", "StatusCode": "UA_BINARY_OVERLAYABLE_INTEGER",
  45. "Guid": "(UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && " + \
  46. "offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && " + \
  47. "offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32)))"}
  48. ################
  49. # Type Classes #
  50. ################
  51. class StructMember(object):
  52. def __init__(self, name, memberType, isArray):
  53. self.name = name
  54. self.memberType = memberType
  55. self.isArray = isArray
  56. class Type(object):
  57. def __init__(self, outname, xml, namespace):
  58. self.name = xml.get("Name")
  59. self.ns0 = ("true" if namespace == 0 else "false")
  60. self.typeIndex = outname.upper() + "_" + self.name.upper()
  61. self.outname = outname
  62. self.description = ""
  63. self.pointerfree = "false"
  64. self.overlayable = "false"
  65. if self.name in builtin_types:
  66. self.builtin = "true"
  67. else:
  68. self.builtin = "false"
  69. self.members = [StructMember("", self, False)] # Returns one member: itself. Overwritten by some types.
  70. for child in xml:
  71. if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
  72. self.description = child.text
  73. break
  74. def datatype_c(self):
  75. xmlEncodingId = "0"
  76. binaryEncodingId = "0"
  77. if self.name in typedescriptions:
  78. description = typedescriptions[self.name]
  79. typeid = "{%s, UA_NODEIDTYPE_NUMERIC, {%s}}" % (description.namespaceid, description.nodeid)
  80. xmlEncodingId = description.xmlEncodingId
  81. binaryEncodingId = description.binaryEncodingId
  82. else:
  83. typeid = "{0, UA_NODEIDTYPE_NUMERIC, {0}}"
  84. return "{\n UA_TYPENAME(\"%s\") /* .typeName */\n" % self.name + \
  85. " " + typeid + ", /* .typeId */\n" + \
  86. " sizeof(UA_" + self.name + "), /* .memSize */\n" + \
  87. " " + self.typeIndex + ", /* .typeIndex */\n" + \
  88. " " + str(len(self.members)) + ", /* .membersSize */\n" + \
  89. " " + self.builtin + ", /* .builtin */\n" + \
  90. " " + self.pointerfree + ", /* .pointerFree */\n" + \
  91. " " + self.overlayable + ", /* .overlayable */ \n" + \
  92. " " + binaryEncodingId + ", /* .binaryEncodingId */\n" + \
  93. " %s_members" % self.name + " /* .members */\n}"
  94. def members_c(self):
  95. if len(self.members)==0:
  96. return "#define %s_members NULL" % (self.name)
  97. members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
  98. before = None
  99. for index, member in enumerate(self.members):
  100. m = "\n{\n UA_TYPENAME(\"%s\") /* .memberName */\n" % member.name
  101. m += " %s_%s, /* .memberTypeIndex */\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
  102. m += " "
  103. if not before:
  104. m += "0,"
  105. else:
  106. if member.isArray:
  107. m += "offsetof(UA_%s, %sSize)" % (self.name, member.name)
  108. else:
  109. m += "offsetof(UA_%s, %s)" % (self.name, member.name)
  110. m += " - offsetof(UA_%s, %s)" % (self.name, before.name)
  111. if before.isArray:
  112. m += " - sizeof(void*),"
  113. else:
  114. m += " - sizeof(UA_%s)," % before.memberType.name
  115. m += " /* .padding */\n"
  116. m += " %s, /* .namespaceZero */\n" % member.memberType.ns0
  117. m += (" true" if member.isArray else " false") + " /* .isArray */\n},"
  118. members += m
  119. before = member
  120. return members + "};"
  121. def datatype_ptr(self):
  122. return "&" + self.outname.upper() + "[" + self.outname.upper() + "_" + self.name.upper() + "]"
  123. def functions_c(self):
  124. funcs = "static UA_INLINE void\nUA_%s_init(UA_%s *p) {\n memset(p, 0, sizeof(UA_%s));\n}\n\n" % (self.name, self.name, self.name)
  125. funcs += "static UA_INLINE UA_%s *\nUA_%s_new(void) {\n return (UA_%s*)UA_new(%s);\n}\n\n" % (self.name, self.name, self.name, self.datatype_ptr())
  126. if self.pointerfree == "true":
  127. funcs += "static UA_INLINE UA_StatusCode\nUA_%s_copy(const UA_%s *src, UA_%s *dst) {\n *dst = *src;\n return UA_STATUSCODE_GOOD;\n}\n\n" % (self.name, self.name, self.name)
  128. funcs += "static UA_INLINE void\nUA_%s_deleteMembers(UA_%s *p) { }\n\n" % (self.name, self.name)
  129. else:
  130. funcs += "static UA_INLINE UA_StatusCode\nUA_%s_copy(const UA_%s *src, UA_%s *dst) {\n return UA_copy(src, dst, %s);\n}\n\n" % (self.name, self.name, self.name, self.datatype_ptr())
  131. funcs += "static UA_INLINE void\nUA_%s_deleteMembers(UA_%s *p) {\n UA_deleteMembers(p, %s);\n}\n\n" % (self.name, self.name, self.datatype_ptr())
  132. funcs += "static UA_INLINE void\nUA_%s_delete(UA_%s *p) {\n UA_delete(p, %s);\n}" % (self.name, self.name, self.datatype_ptr())
  133. return funcs
  134. def encoding_h(self):
  135. enc = "static UA_INLINE UA_StatusCode\nUA_%s_encodeBinary(const UA_%s *src, UA_Byte **bufPos, const UA_Byte **bufEnd) {\n return UA_encodeBinary(src, %s, bufPos, bufEnd, NULL, NULL);\n}\n"
  136. enc += "static UA_INLINE UA_StatusCode\nUA_%s_decodeBinary(const UA_ByteString *src, size_t *offset, UA_%s *dst) {\n return UA_decodeBinary(src, offset, dst, %s, 0, NULL);\n}"
  137. return enc % tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, self.datatype_ptr()], 2))))
  138. class BuiltinType(Type):
  139. def __init__(self, name):
  140. self.name = name
  141. self.ns0 = "true"
  142. self.typeIndex = "UA_TYPES_" + self.name.upper()
  143. self.outname = "ua_types"
  144. self.description = ""
  145. self.pointerfree = "false"
  146. if self.name in builtin_pointerfree:
  147. self.pointerfree = "true"
  148. self.overlayable = "false"
  149. if name in builtin_overlayable:
  150. self.overlayable = builtin_overlayable[name]
  151. self.builtin = "true"
  152. if self.name == "QualifiedName":
  153. self.members = [StructMember("namespaceIndex", types["Int16"], False), StructMember("name", types["String"], False)]
  154. elif self.name in ["String", "ByteString", "XmlElement"]:
  155. self.members = [StructMember("", types["Byte"], True)]
  156. else:
  157. self.members = [StructMember("", self, False)]
  158. class EnumerationType(Type):
  159. def __init__(self, outname, xml, namespace):
  160. Type.__init__(self, outname, xml, namespace)
  161. self.pointerfree = "true"
  162. self.overlayable = "UA_BINARY_OVERLAYABLE_INTEGER"
  163. self.members = [StructMember("", types["Int32"], False)] # encoded as uint32
  164. self.builtin = "true"
  165. self.typeIndex = "UA_TYPES_INT32"
  166. self.elements = OrderedDict()
  167. for child in xml:
  168. if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
  169. self.elements[child.get("Name")] = child.get("Value")
  170. def typedef_h(self):
  171. if sys.version_info[0] < 3:
  172. values = self.elements.iteritems()
  173. else:
  174. values = self.elements.items()
  175. return "typedef enum {\n " + ",\n ".join(map(lambda kv : "UA_" + self.name.upper() + "_" + kv[0].upper() + \
  176. " = " + kv[1], values)) + \
  177. ",\n __UA_{0}_FORCE32BIT = 0x7fffffff\n".format(self.name.upper()) + "} " + \
  178. "UA_{0};\nUA_STATIC_ASSERT(sizeof(UA_{0}) == sizeof(UA_Int32), enum_must_be_32bit);".format(self.name)
  179. class OpaqueType(Type):
  180. def __init__(self, outname, xml, namespace, baseType):
  181. Type.__init__(self, outname, xml, namespace)
  182. self.baseType = baseType
  183. self.members = [StructMember("", types[baseType], False)] # encoded as string
  184. def typedef_h(self):
  185. return "typedef UA_" + self.baseType + " UA_%s;" % self.name
  186. class StructType(Type):
  187. def __init__(self, outname, xml, namespace):
  188. Type.__init__(self, outname, xml, namespace)
  189. self.members = []
  190. lengthfields = [] # lengthfields of arrays are not included as members
  191. for child in xml:
  192. if child.get("LengthField"):
  193. lengthfields.append(child.get("LengthField"))
  194. for child in xml:
  195. if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  196. continue
  197. if child.get("Name") in lengthfields:
  198. continue
  199. memberName = child.get("Name")
  200. memberName = memberName[:1].lower() + memberName[1:]
  201. memberTypeName = child.get("TypeName")
  202. memberType = types[memberTypeName[memberTypeName.find(":")+1:]]
  203. isArray = True if child.get("LengthField") else False
  204. self.members.append(StructMember(memberName, memberType, isArray))
  205. self.pointerfree = "true"
  206. self.overlayable = "true"
  207. before = None
  208. for m in self.members:
  209. if m.isArray or m.memberType.pointerfree != "true":
  210. self.pointerfree = "false"
  211. self.overlayable = "false"
  212. else:
  213. self.overlayable += " && " + m.memberType.overlayable
  214. if before:
  215. self.overlayable += " && offsetof(UA_%s, %s) == (offsetof(UA_%s, %s) + sizeof(UA_%s))" % \
  216. (self.name, m.name, self.name, before.name, before.memberType.name)
  217. if "false" in self.overlayable:
  218. self.overlayable = "false"
  219. before = m
  220. def typedef_h(self):
  221. if len(self.members) == 0:
  222. return "typedef void * UA_%s;" % self.name
  223. returnstr = "typedef struct {\n"
  224. for member in self.members:
  225. if member.isArray:
  226. returnstr += " size_t %sSize;\n" % member.name
  227. returnstr += " UA_%s *%s;\n" % (member.memberType.name, member.name)
  228. else:
  229. returnstr += " UA_%s %s;\n" % (member.memberType.name, member.name)
  230. return returnstr + "} UA_%s;" % self.name
  231. #########################
  232. # Parse Typedefinitions #
  233. #########################
  234. def parseTypeDefinitions(outname, xmlDescription, namespace):
  235. def typeReady(element):
  236. "Are all member types defined?"
  237. for child in element:
  238. if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
  239. childname = child.get("TypeName")
  240. if childname[childname.find(":")+1:] not in types:
  241. return False
  242. return True
  243. def skipType(name):
  244. if name in excluded_types:
  245. return True
  246. if "Test" in name: # skip all test types
  247. return True
  248. if re.search("NodeId$", name) != None:
  249. return True
  250. return False
  251. snippets = {}
  252. for typeXml in etree.parse(xmlDescription).getroot():
  253. if not typeXml.get("Name"):
  254. continue
  255. name = typeXml.get("Name")
  256. snippets[name] = typeXml
  257. while(len(snippets) > 0):
  258. for name, typeXml in list(snippets.items()):
  259. if name in types or skipType(name):
  260. del snippets[name]
  261. continue
  262. if not typeReady(typeXml):
  263. continue
  264. if name in builtin_types:
  265. types[name] = BuiltinType(name)
  266. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
  267. types[name] = EnumerationType(outname, typeXml, namespace)
  268. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
  269. types[name] = OpaqueType(outname, typeXml, namespace, get_base_type_for_opaque(name)['name'])
  270. elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
  271. types[name] = StructType(outname, typeXml, namespace)
  272. else:
  273. raise Exception("Type not known")
  274. del snippets[name]
  275. ##########################
  276. # Parse TypeDescriptions #
  277. ##########################
  278. class TypeDescription(object):
  279. def __init__(self, name, nodeid, namespaceid):
  280. self.name = name
  281. self.nodeid = nodeid
  282. self.namespaceid = namespaceid
  283. self.xmlEncodingId = "0"
  284. self.binaryEncodingId = "0"
  285. def parseTypeDescriptions(f, namespaceid):
  286. definitions = {}
  287. input_str = f.read()
  288. input_str = input_str.replace('\r','')
  289. rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
  290. for index, row in enumerate(rows):
  291. if len(row) < 3:
  292. continue
  293. if row[2] == "Object":
  294. # Check if node name ends with _Encoding_(DefaultXml|DefaultBinary) and store the node id in the corresponding DataType
  295. m = re.match('(.*?)_Encoding_Default(Xml|Binary)$',row[0])
  296. if (m):
  297. baseType = m.group(1)
  298. if baseType not in types:
  299. continue
  300. if m.group(2) == "Xml":
  301. definitions[baseType].xmlEncodingId = row[1]
  302. else:
  303. definitions[baseType].binaryEncodingId = row[1]
  304. continue
  305. if row[2] != "DataType":
  306. continue
  307. if row[0] == "BaseDataType":
  308. definitions["Variant"] = TypeDescription(row[0], row[1], namespaceid)
  309. elif row[0] == "Structure":
  310. definitions["ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
  311. elif row[0] not in types:
  312. continue
  313. else:
  314. definitions[row[0]] = TypeDescription(row[0], row[1], namespaceid)
  315. return definitions
  316. def merge_dicts(*dict_args):
  317. """
  318. Given any number of dicts, shallow copy and merge into a new dict,
  319. precedence goes to key value pairs in latter dicts.
  320. """
  321. result = {}
  322. for dictionary in dict_args:
  323. result.update(dictionary)
  324. return result
  325. ###############################
  326. # Parse the Command Line Input#
  327. ###############################
  328. parser = argparse.ArgumentParser()
  329. parser.add_argument('-c', '--type-csv',
  330. metavar="<typeDescriptions>",
  331. type=argparse.FileType('r'),
  332. dest="type_csv",
  333. action='append',
  334. default=[],
  335. help='csv file with type descriptions')
  336. parser.add_argument('--namespace',
  337. type=int,
  338. dest="namespace",
  339. default=0,
  340. help='namespace id of the generated type nodeids (defaults to 0)')
  341. parser.add_argument('-s', '--selected-types',
  342. metavar="<selectedTypes>",
  343. type=argparse.FileType('r'),
  344. dest="selected_types",
  345. action='append',
  346. default=[],
  347. help='file with list of types (among those parsed) to be generated. If not given, all types are generated')
  348. parser.add_argument('--no-builtin',
  349. action='store_true',
  350. dest="no_builtin",
  351. help='Do not generate builtin types')
  352. parser.add_argument('-t', '--type-bsd',
  353. metavar="<typeBsds>",
  354. type=argparse.FileType('r'),
  355. dest="type_bsd",
  356. action='append',
  357. default=[],
  358. help='csv file with type descriptions')
  359. parser.add_argument('outfile',
  360. metavar='<outputFile>',
  361. help='output file w/o extension')
  362. args = parser.parse_args()
  363. outname = args.outfile.split("/")[-1]
  364. inname = ', '.join(list(map(lambda x:x.name.split("/")[-1], args.type_bsd)))
  365. ################
  366. # Create Types #
  367. ################
  368. for builtin in builtin_types:
  369. types[builtin] = BuiltinType(builtin)
  370. for f in args.type_bsd:
  371. parseTypeDefinitions(outname, f, args.namespace)
  372. typedescriptions = {}
  373. for f in args.type_csv:
  374. typedescriptions = merge_dicts(typedescriptions, parseTypeDescriptions(f, args.namespace))
  375. selected_types = []
  376. for f in args.selected_types:
  377. selected_types = list(filter(len, [line.strip() for line in f]))
  378. if len(selected_types) == 0:
  379. selected_types = types.keys()
  380. #############################
  381. # Write out the Definitions #
  382. #############################
  383. fh = open(args.outfile + "_generated.h",'w')
  384. ff = open(args.outfile + "_generated_handling.h",'w')
  385. fe = open(args.outfile + "_generated_encoding_binary.h",'w')
  386. fc = open(args.outfile + "_generated.c",'w')
  387. def printh(string):
  388. print(string, end='\n', file=fh)
  389. def printf(string):
  390. print(string, end='\n', file=ff)
  391. def printe(string):
  392. print(string, end='\n', file=fe)
  393. def printc(string):
  394. print(string, end='\n', file=fc)
  395. def iter_types(v):
  396. l = None
  397. if sys.version_info[0] < 3:
  398. l = list(v.itervalues())
  399. else:
  400. l = list(v.values())
  401. if len(selected_types) > 0:
  402. l = list(filter(lambda t: t.name in selected_types, l))
  403. if args.no_builtin:
  404. l = list(filter(lambda t: type(t) != BuiltinType, l))
  405. return l
  406. ################
  407. # Print Header #
  408. ################
  409. printh('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  410. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  411. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  412. #ifndef ''' + outname.upper() + '''_GENERATED_H_
  413. #define ''' + outname.upper() + '''_GENERATED_H_
  414. #ifdef __cplusplus
  415. extern "C" {
  416. #endif
  417. #include "ua_types.h"
  418. ''' + ('#include "ua_types_generated.h"\n' if outname != "ua_types" else ''))
  419. filtered_types = iter_types(types)
  420. printh('''/**
  421. * Every type is assigned an index in an array containing the type descriptions.
  422. * These descriptions are used during type handling (copying, deletion,
  423. * binary encoding, ...). */''')
  424. printh("#define " + outname.upper() + "_COUNT %s" % (str(len(filtered_types))))
  425. printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.upper() + "_COUNT];")
  426. i = 0
  427. for t in filtered_types:
  428. printh("\n/**\n * " + t.name)
  429. printh(" * " + "^" * len(t.name))
  430. if t.description == "":
  431. printh(" */")
  432. else:
  433. printh(" * " + t.description + " */")
  434. if type(t) != BuiltinType:
  435. printh(t.typedef_h() + "\n")
  436. printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
  437. i += 1
  438. printh('''
  439. #ifdef __cplusplus
  440. } // extern "C"
  441. #endif\n
  442. #endif /* %s_GENERATED_H_ */''' % outname.upper())
  443. ##################
  444. # Print Handling #
  445. ##################
  446. printf('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  447. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  448. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  449. #ifndef ''' + outname.upper() + '''_GENERATED_HANDLING_H_
  450. #define ''' + outname.upper() + '''_GENERATED_HANDLING_H_
  451. #ifdef __cplusplus
  452. extern "C" {
  453. #endif
  454. #include "''' + outname + '''_generated.h"
  455. #if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
  456. # pragma GCC diagnostic push
  457. # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  458. # pragma GCC diagnostic ignored "-Wmissing-braces"
  459. #endif
  460. ''')
  461. for t in filtered_types:
  462. printf("\n/* " + t.name + " */")
  463. printf(t.functions_c())
  464. printf('''
  465. #if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
  466. # pragma GCC diagnostic pop
  467. #endif
  468. #ifdef __cplusplus
  469. } // extern "C"
  470. #endif\n
  471. #endif /* %s_GENERATED_HANDLING_H_ */''' % outname.upper())
  472. ###########################
  473. # Print Description Array #
  474. ###########################
  475. printc('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  476. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  477. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  478. #include "''' + outname + '''_generated.h"
  479. #include "ua_util.h"''')
  480. for t in filtered_types:
  481. printc("")
  482. printc("/* " + t.name + " */")
  483. printc(t.members_c())
  484. printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
  485. for t in filtered_types:
  486. printc("")
  487. printc("/* " + t.name + " */")
  488. printc(t.datatype_c() + ",")
  489. printc("};\n")
  490. ##################
  491. # Print Encoding #
  492. ##################
  493. printe('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
  494. * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
  495. ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
  496. #include "ua_types_encoding_binary.h"
  497. #include "''' + outname + '''_generated.h"''')
  498. for t in filtered_types:
  499. printe("\n/* " + t.name + " */")
  500. printe(t.encoding_h())
  501. fh.close()
  502. ff.close()
  503. fc.close()
  504. fe.close()