structsgen.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import os
  2. import re
  3. #==[regexps]=================================================
  4. # Clean desc
  5. REdefine = re.compile(r''
  6. r'(?P<desc>)' # /** *desc */
  7. r'#\s*define\s(?P<name>[^(\n]+?)\s(?P<code>.+)$' # #define name value
  8. , re.MULTILINE)
  9. # Get structs
  10. REstructs = re.compile(r''
  11. #r'//\s?[\-]*\s(?P<desc>.*?)\*/\s' # /** *desc */
  12. #r'//\s?[\-]*(?P<desc>.*?)\*/(?:.*?)' # garbage
  13. r'//\s?[\-]*\s(?P<desc>.*?)\*/\W*?' # /** *desc */
  14. r'struct\s(?:ASSIMP_API\s)?(?P<name>[a-z][a-z0-9_]\w+\b)' # struct name
  15. r'[^{]*?\{' # {
  16. r'(?P<code>.*?)' # code
  17. r'\}\s*(PACK_STRUCT)?;' # };
  18. , re.IGNORECASE + re.DOTALL + re.MULTILINE)
  19. # Clean desc
  20. REdesc = re.compile(r''
  21. r'^\s*?([*]|/\*\*)(?P<line>.*?)' # * line
  22. , re.IGNORECASE + re.DOTALL + re.MULTILINE)
  23. # Remove #ifdef __cplusplus
  24. RErmifdef = re.compile(r''
  25. r'#ifdef __cplusplus' # #ifdef __cplusplus
  26. r'(?P<code>.*)' # code
  27. r'#endif(\s*//\s*!?\s*__cplusplus)*' # #endif
  28. , re.IGNORECASE + re.DOTALL)
  29. # Replace comments
  30. RErpcom = re.compile(r''
  31. r'[ ]*(/\*\*\s|\*/|\B\*\s|//!)' # /**
  32. r'(?P<line>.*?)' # * line
  33. , re.IGNORECASE + re.DOTALL)
  34. # Restructure
  35. def GetType(type, prefix='c_'):
  36. t = type
  37. while t.endswith('*'):
  38. t = t[:-1]
  39. types = {'unsigned int':'uint', 'unsigned char':'ubyte', 'size_t':'uint',}
  40. if t in types:
  41. t = types[t]
  42. t = prefix + t
  43. while type.endswith('*'):
  44. t = "POINTER(" + t + ")"
  45. type = type[:-1]
  46. return t
  47. def restructure( match ):
  48. type = match.group("type")
  49. if match.group("struct") == "":
  50. type = GetType(type)
  51. elif match.group("struct") == "C_ENUM ":
  52. type = "c_uint"
  53. else:
  54. type = GetType(type[2:].upper(), '')
  55. if match.group("index"):
  56. type = type + "*" + match.group("index")
  57. result = ""
  58. for name in match.group("name").split(','):
  59. result += "(\"" + name.strip() + "\", "+ type + "),"
  60. return result
  61. RErestruc = re.compile(r''
  62. r'(?P<struct>C_STRUCT\s|C_ENUM\s|)' # [C_STRUCT]
  63. r'(?P<type>\w+\s?\w+?[*]*)\s' # type
  64. #r'(?P<name>\w+)' # name
  65. r'(?P<name>\w+|[a-z0-9_, ]+)' # name
  66. r'(:?\[(?P<index>\w+)\])?;' # []; (optional)
  67. , re.DOTALL)
  68. #==[template]================================================
  69. template = """
  70. class $NAME$(Structure):
  71. \"\"\"
  72. $DESCRIPTION$
  73. \"\"\"
  74. $DEFINES$
  75. _fields_ = [
  76. $FIELDS$
  77. ]
  78. """
  79. templateSR = """
  80. class $NAME$(Structure):
  81. \"\"\"
  82. $DESCRIPTION$
  83. \"\"\"
  84. $DEFINES$
  85. $NAME$._fields_ = [
  86. $FIELDS$
  87. ]
  88. """
  89. #============================================================
  90. def Structify(fileName):
  91. file = open(fileName, 'r')
  92. text = file.read()
  93. result = []
  94. # Get defines.
  95. defs = REdefine.findall(text)
  96. # Create defines
  97. defines = "\n"
  98. for define in defs:
  99. # Clean desc
  100. desc = REdesc.sub('', define[0])
  101. # Replace comments
  102. desc = RErpcom.sub('#\g<line>', desc)
  103. defines += desc
  104. defines += " "*4 + define[1] + " = " + define[2] + "\n"
  105. # Get structs
  106. rs = REstructs.finditer(text)
  107. fileName = os.path.basename(fileName)
  108. print fileName
  109. for r in rs:
  110. name = r.group('name')[2:].upper()
  111. desc = r.group('desc')
  112. # Skip some structs
  113. if name == "FILEIO" or name == "FILE" or name == "LOCATEFROMASSIMPHEAP":
  114. continue
  115. text = r.group('code')
  116. # Clean desc
  117. desc = REdesc.sub('', desc)
  118. desc = "See '"+ fileName +"' for details." #TODO
  119. # Remove #ifdef __cplusplus
  120. text = RErmifdef.sub('', text)
  121. # Whether the struct contains more than just POD
  122. primitive = text.find('C_STRUCT') == -1
  123. # Restructure
  124. text = RErestruc.sub(restructure, text)
  125. # Replace comments
  126. text = RErpcom.sub('#\g<line>', text)
  127. # Whether it's selfreferencing: ex. struct Node { Node* parent; };
  128. selfreferencing = text.find('POINTER('+name+')') != -1
  129. complex = name == "SCENE"
  130. # Create description
  131. description = ""
  132. for line in desc.split('\n'):
  133. description += " "*4 + line.strip() + "\n"
  134. description = description.rstrip()
  135. # Create fields
  136. fields = ""
  137. for line in text.split('\n'):
  138. fields += " "*12 + line.strip() + "\n"
  139. fields = fields.strip()
  140. if selfreferencing:
  141. templ = templateSR
  142. else:
  143. templ = template
  144. # Put it all together
  145. text = templ.replace('$NAME$', name)
  146. text = text.replace('$DESCRIPTION$', description)
  147. text = text.replace('$FIELDS$', fields)
  148. if ((name == fileName.split('.')[0][2:].upper()) and (name != 'MATERIAL')) or name == "STRING":
  149. text = text.replace('$DEFINES$', defines)
  150. else:
  151. text = text.replace('$DEFINES$', '')
  152. result.append((primitive, selfreferencing, complex, text))
  153. return result
  154. text = "#-*- coding: UTF-8 -*-\n\n"
  155. text += "from ctypes import POINTER, c_int, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte\n\n"
  156. structs1 = ""
  157. structs2 = ""
  158. structs3 = ""
  159. structs4 = ""
  160. path = '../include/'
  161. files = os.listdir (path)
  162. #files = ["aiScene.h", "aiTypes.h"]
  163. for fileName in files:
  164. if fileName.endswith('.h'):
  165. for struct in Structify(os.path.join(path, fileName)):
  166. primitive, sr, complex, struct = struct
  167. if primitive:
  168. structs1 += struct
  169. elif sr:
  170. structs2 += struct
  171. elif complex:
  172. structs4 += struct
  173. else:
  174. structs3 += struct
  175. text += structs1 + structs2 + structs3 + structs4
  176. file = open('structs.txt', 'w')
  177. file.write(text)
  178. file.close()