PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Main/GStreamer/Source/gst-python/codegen/h2def.py

http://ossbuild.googlecode.com/
Python | 536 lines | 497 code | 19 blank | 20 comment | 25 complexity | e7ddb803b54b0c0b9cf1d83c7679c7fe MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0, AGPL-1.0, LGPL-2.1, LGPL-2.0, GPL-3.0, LGPL-3.0, CC-BY-SA-3.0
  1. #!/usr/bin/env python
  2. # -*- Mode: Python; py-indent-offset: 4 -*-
  3. # Search through a header file looking for function prototypes.
  4. # For each prototype, generate a scheme style definition.
  5. # GPL'ed
  6. # Toby D. Reeves <toby@max.rl.plh.af.mil>
  7. #
  8. # Modified by James Henstridge <james@daa.com.au> to output stuff in
  9. # Havoc's new defs format. Info on this format can be seen at:
  10. # http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
  11. # Updated to be PEP-8 compatible and refactored to use OOP
  12. import getopt
  13. import os
  14. import re
  15. import string
  16. import sys
  17. import defsparser
  18. # ------------------ Create typecodes from typenames ---------
  19. _upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
  20. _upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
  21. _upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
  22. def to_upper_str(name):
  23. """Converts a typename to the equivalent upercase and underscores
  24. name. This is used to form the type conversion macros and enum/flag
  25. name variables"""
  26. name = _upperstr_pat1.sub(r'\1_\2', name)
  27. name = _upperstr_pat2.sub(r'\1_\2', name)
  28. name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
  29. return string.upper(name)
  30. def typecode(typename):
  31. """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
  32. return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
  33. # ------------------ Find object definitions -----------------
  34. def strip_comments(buf):
  35. parts = []
  36. lastpos = 0
  37. while 1:
  38. pos = string.find(buf, '/*', lastpos)
  39. if pos >= 0:
  40. parts.append(buf[lastpos:pos])
  41. pos = string.find(buf, '*/', pos)
  42. if pos >= 0:
  43. lastpos = pos + 2
  44. else:
  45. break
  46. else:
  47. parts.append(buf[lastpos:])
  48. break
  49. return string.join(parts, '')
  50. obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
  51. split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
  52. def find_obj_defs(buf, objdefs=[]):
  53. """
  54. Try to find object definitions in header files.
  55. """
  56. # filter out comments from buffer.
  57. buf = strip_comments(buf)
  58. maybeobjdefs = [] # contains all possible objects from file
  59. # first find all structures that look like they may represent a GtkObject
  60. pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" +
  61. "(" + obj_name_pat + ")\s+", re.MULTILINE)
  62. pos = 0
  63. while pos < len(buf):
  64. m = pat.search(buf, pos)
  65. if not m: break
  66. maybeobjdefs.append((m.group(1), m.group(2)))
  67. pos = m.end()
  68. # handle typedef struct { ... } style struct defs.
  69. pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
  70. "(" + obj_name_pat + ")\s+[^}]*}\s*" +
  71. "(" + obj_name_pat + ")\s*;", re.MULTILINE)
  72. pos = 0
  73. while pos < len(buf):
  74. m = pat.search(buf, pos)
  75. if not m: break
  76. maybeobjdefs.append((m.group(2), m.group(2)))
  77. pos = m.end()
  78. # now find all structures that look like they might represent a class:
  79. pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
  80. "(" + obj_name_pat + ")Class\s+", re.MULTILINE)
  81. pos = 0
  82. while pos < len(buf):
  83. m = pat.search(buf, pos)
  84. if not m: break
  85. t = (m.group(1), m.group(2))
  86. # if we find an object structure together with a corresponding
  87. # class structure, then we have probably found a GtkObject subclass.
  88. if t in maybeobjdefs:
  89. objdefs.append(t)
  90. pos = m.end()
  91. pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
  92. "(" + obj_name_pat + ")Class\s+[^}]*}\s*" +
  93. "(" + obj_name_pat + ")Class\s*;", re.MULTILINE)
  94. pos = 0
  95. while pos < len(buf):
  96. m = pat.search(buf, pos)
  97. if not m: break
  98. t = (m.group(2), m.group(1))
  99. # if we find an object structure together with a corresponding
  100. # class structure, then we have probably found a GtkObject subclass.
  101. if t in maybeobjdefs:
  102. objdefs.append(t)
  103. pos = m.end()
  104. # now find all structures that look like they might represent
  105. # a class inherited from GTypeInterface:
  106. pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
  107. "GTypeInterface\s+", re.MULTILINE)
  108. pos = 0
  109. while pos < len(buf):
  110. m = pat.search(buf, pos)
  111. if not m: break
  112. t = (m.group(1), '')
  113. t2 = (m.group(1)+'Class', 'GTypeInterface')
  114. # if we find an object structure together with a corresponding
  115. # class structure, then we have probably found a GtkObject subclass.
  116. if t2 in maybeobjdefs:
  117. objdefs.append(t)
  118. pos = m.end()
  119. # now find all structures that look like they might represent
  120. # an Iface inherited from GTypeInterface:
  121. pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" +
  122. "GTypeInterface\s+", re.MULTILINE)
  123. pos = 0
  124. while pos < len(buf):
  125. m = pat.search(buf, pos)
  126. if not m: break
  127. t = (m.group(1), '')
  128. t2 = (m.group(1)+'Iface', 'GTypeInterface')
  129. # if we find an object structure together with a corresponding
  130. # class structure, then we have probably found a GtkObject subclass.
  131. if t2 in maybeobjdefs:
  132. objdefs.append(t)
  133. pos = m.end()
  134. def sort_obj_defs(objdefs):
  135. objdefs.sort() # not strictly needed, but looks nice
  136. pos = 0
  137. while pos < len(objdefs):
  138. klass,parent = objdefs[pos]
  139. for i in range(pos+1, len(objdefs)):
  140. # parent below subclass ... reorder
  141. if objdefs[i][0] == parent:
  142. objdefs.insert(i+1, objdefs[pos])
  143. del objdefs[pos]
  144. break
  145. else:
  146. pos = pos + 1
  147. return objdefs
  148. # ------------------ Find enum definitions -----------------
  149. def find_enum_defs(buf, enums=[]):
  150. # strip comments
  151. # bulk comments
  152. buf = strip_comments(buf)
  153. buf = re.sub('\n', ' ', buf)
  154. enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
  155. splitter = re.compile(r'\s*,\s', re.MULTILINE)
  156. pos = 0
  157. while pos < len(buf):
  158. m = enum_pat.search(buf, pos)
  159. if not m: break
  160. name = m.group(2)
  161. vals = m.group(1)
  162. isflags = string.find(vals, '<<') >= 0
  163. entries = []
  164. for val in splitter.split(vals):
  165. if not string.strip(val): continue
  166. entries.append(string.split(val)[0])
  167. if name != 'GdkCursorType':
  168. enums.append((name, isflags, entries))
  169. pos = m.end()
  170. # ------------------ Find function definitions -----------------
  171. def clean_func(buf):
  172. """
  173. Ideally would make buf have a single prototype on each line.
  174. Actually just cuts out a good deal of junk, but leaves lines
  175. where a regex can figure prototypes out.
  176. """
  177. # bulk comments
  178. buf = strip_comments(buf)
  179. # compact continued lines
  180. pat = re.compile(r"""\\\n""", re.MULTILINE)
  181. buf = pat.sub('', buf)
  182. # Preprocess directives
  183. pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
  184. buf = pat.sub('', buf)
  185. #typedefs, stucts, and enums
  186. pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""",
  187. re.MULTILINE)
  188. buf = pat.sub('', buf)
  189. #strip DECLS macros
  190. pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE)
  191. buf = pat.sub('', buf)
  192. #extern "C"
  193. pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE)
  194. buf = pat.sub('', buf)
  195. #multiple whitespace
  196. pat = re.compile(r"""\s+""", re.MULTILINE)
  197. buf = pat.sub(' ', buf)
  198. #clean up line ends
  199. pat = re.compile(r""";\s*""", re.MULTILINE)
  200. buf = pat.sub('\n', buf)
  201. buf = buf.lstrip()
  202. #associate *, &, and [] with type instead of variable
  203. #pat = re.compile(r'\s+([*|&]+)\s*(\w+)')
  204. pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE)
  205. buf = pat.sub(r'\1 \2', buf)
  206. pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE)
  207. buf = pat.sub(r'[] \1', buf)
  208. # make return types that are const work.
  209. buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
  210. buf = string.replace(buf, 'const ', 'const-')
  211. return buf
  212. proto_pat=re.compile(r"""
  213. (?P<ret>(-|\w|\&|\*)+\s*) # return type
  214. \s+ # skip whitespace
  215. (?P<func>\w+)\s*[(] # match the function name until the opening (
  216. \s*(?P<args>.*?)\s*[)] # group the function arguments
  217. """, re.IGNORECASE|re.VERBOSE)
  218. #"""
  219. arg_split_pat = re.compile("\s*,\s*")
  220. get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
  221. pointer_pat = re.compile('.*\*$')
  222. func_new_pat = re.compile('(\w+)_new$')
  223. class DefsWriter:
  224. def __init__(self, fp=None, prefix=None, verbose=False,
  225. defsfilter=None):
  226. if not fp:
  227. fp = sys.stdout
  228. self.fp = fp
  229. self.prefix = prefix
  230. self.verbose = verbose
  231. self._enums = {}
  232. self._objects = {}
  233. self._functions = {}
  234. if defsfilter:
  235. filter = defsparser.DefsParser(defsfilter)
  236. filter.startParsing()
  237. for func in filter.functions + filter.methods.values():
  238. self._functions[func.c_name] = func
  239. for obj in filter.objects + filter.boxes + filter.interfaces:
  240. self._objects[obj.c_name] = func
  241. for obj in filter.enums:
  242. self._enums[obj.c_name] = func
  243. def write_def(self, deffile):
  244. buf = open(deffile).read()
  245. self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile))
  246. self._define_func(buf)
  247. self.fp.write('\n')
  248. def write_enum_defs(self, enums, fp=None):
  249. if not fp:
  250. fp = self.fp
  251. fp.write(';; Enumerations and flags ...\n\n')
  252. trans = string.maketrans(string.uppercase + '_',
  253. string.lowercase + '-')
  254. filter = self._enums
  255. for cname, isflags, entries in enums:
  256. if filter:
  257. if cname in filter:
  258. continue
  259. name = cname
  260. module = None
  261. m = split_prefix_pat.match(cname)
  262. if m:
  263. module = m.group(1)
  264. name = m.group(2)
  265. if isflags:
  266. fp.write('(define-flags ' + name + '\n')
  267. else:
  268. fp.write('(define-enum ' + name + '\n')
  269. if module:
  270. fp.write(' (in-module "' + module + '")\n')
  271. fp.write(' (c-name "' + cname + '")\n')
  272. fp.write(' (gtype-id "' + typecode(cname) + '")\n')
  273. prefix = entries[0]
  274. for ent in entries:
  275. # shorten prefix til we get a match ...
  276. # and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
  277. while ent[:len(prefix)] != prefix or len(prefix) >= len(ent):
  278. prefix = prefix[:-1]
  279. prefix_len = len(prefix)
  280. fp.write(' (values\n')
  281. for ent in entries:
  282. fp.write(' \'("%s" "%s")\n' %
  283. (string.translate(ent[prefix_len:], trans), ent))
  284. fp.write(' )\n')
  285. fp.write(')\n\n')
  286. def write_obj_defs(self, objdefs, fp=None):
  287. if not fp:
  288. fp = self.fp
  289. fp.write(';; -*- scheme -*-\n')
  290. fp.write('; object definitions ...\n')
  291. filter = self._objects
  292. for klass, parent in objdefs:
  293. if filter:
  294. if klass in filter:
  295. continue
  296. m = split_prefix_pat.match(klass)
  297. cmodule = None
  298. cname = klass
  299. if m:
  300. cmodule = m.group(1)
  301. cname = m.group(2)
  302. fp.write('(define-object ' + cname + '\n')
  303. if cmodule:
  304. fp.write(' (in-module "' + cmodule + '")\n')
  305. if parent:
  306. fp.write(' (parent "' + parent + '")\n')
  307. fp.write(' (c-name "' + klass + '")\n')
  308. fp.write(' (gtype-id "' + typecode(klass) + '")\n')
  309. # should do something about accessible fields
  310. fp.write(')\n\n')
  311. def _define_func(self, buf):
  312. buf = clean_func(buf)
  313. buf = string.split(buf,'\n')
  314. filter = self._functions
  315. for p in buf:
  316. if not p:
  317. continue
  318. m = proto_pat.match(p)
  319. if m == None:
  320. if self.verbose:
  321. sys.stderr.write('No match:|%s|\n' % p)
  322. continue
  323. func = m.group('func')
  324. if func[0] == '_':
  325. continue
  326. if filter:
  327. if func in filter:
  328. continue
  329. ret = m.group('ret')
  330. args = m.group('args')
  331. args = arg_split_pat.split(args)
  332. for i in range(len(args)):
  333. spaces = string.count(args[i], ' ')
  334. if spaces > 1:
  335. args[i] = string.replace(args[i], ' ', '-', spaces - 1)
  336. self._write_func(func, ret, args)
  337. def _write_func(self, name, ret, args):
  338. if len(args) >= 1:
  339. # methods must have at least one argument
  340. munged_name = name.replace('_', '')
  341. m = get_type_pat.match(args[0])
  342. if m:
  343. obj = m.group(2)
  344. if munged_name[:len(obj)] == obj.lower():
  345. self._write_method(obj, name, ret, args)
  346. return
  347. if self.prefix:
  348. l = len(self.prefix)
  349. if name[:l] == self.prefix and name[l] == '_':
  350. fname = name[l+1:]
  351. else:
  352. fname = name
  353. else:
  354. fname = name
  355. # it is either a constructor or normal function
  356. self.fp.write('(define-function ' + fname + '\n')
  357. self.fp.write(' (c-name "' + name + '")\n')
  358. # Hmmm... Let's asume that a constructor function name
  359. # ends with '_new' and it returns a pointer.
  360. m = func_new_pat.match(name)
  361. if pointer_pat.match(ret) and m:
  362. cname = ''
  363. for s in m.group(1).split ('_'):
  364. cname += s.title()
  365. if cname != '':
  366. self.fp.write(' (is-constructor-of "' + cname + '")\n')
  367. self._write_return(ret)
  368. self._write_arguments(args)
  369. def _write_method(self, obj, name, ret, args):
  370. regex = string.join(map(lambda x: x+'_?', string.lower(obj)),'')
  371. mname = re.sub(regex, '', name, 1)
  372. if self.prefix:
  373. l = len(self.prefix) + 1
  374. if mname[:l] == self.prefix and mname[l+1] == '_':
  375. mname = mname[l+1:]
  376. self.fp.write('(define-method ' + mname + '\n')
  377. self.fp.write(' (of-object "' + obj + '")\n')
  378. self.fp.write(' (c-name "' + name + '")\n')
  379. self._write_return(ret)
  380. self._write_arguments(args[1:])
  381. def _write_return(self, ret):
  382. if ret != 'void':
  383. self.fp.write(' (return-type "' + ret + '")\n')
  384. else:
  385. self.fp.write(' (return-type "none")\n')
  386. def _write_arguments(self, args):
  387. is_varargs = 0
  388. has_args = len(args) > 0
  389. for arg in args:
  390. if arg == '...':
  391. is_varargs = 1
  392. elif arg in ('void', 'void '):
  393. has_args = 0
  394. if has_args:
  395. self.fp.write(' (parameters\n')
  396. for arg in args:
  397. if arg != '...':
  398. tupleArg = tuple(string.split(arg))
  399. if len(tupleArg) == 2:
  400. self.fp.write(' \'("%s" "%s")\n' % tupleArg)
  401. self.fp.write(' )\n')
  402. if is_varargs:
  403. self.fp.write(' (varargs #t)\n')
  404. self.fp.write(')\n\n')
  405. # ------------------ Main function -----------------
  406. def main(args):
  407. verbose = False
  408. onlyenums = False
  409. onlyobjdefs = False
  410. separate = False
  411. modulename = None
  412. defsfilter = None
  413. opts, args = getopt.getopt(args[1:], 'vs:m:f:',
  414. ['onlyenums', 'onlyobjdefs',
  415. 'modulename=', 'separate=',
  416. 'defsfilter='])
  417. for o, v in opts:
  418. if o == '-v':
  419. verbose = True
  420. if o == '--onlyenums':
  421. onlyenums = True
  422. if o == '--onlyobjdefs':
  423. onlyobjdefs = True
  424. if o in ('-s', '--separate'):
  425. separate = v
  426. if o in ('-m', '--modulename'):
  427. modulename = v
  428. if o in ('-f', '--defsfilter'):
  429. defsfilter = v
  430. if not args[0:1]:
  431. print 'Must specify at least one input file name'
  432. return -1
  433. # read all the object definitions in
  434. objdefs = []
  435. enums = []
  436. for filename in args:
  437. buf = open(filename).read()
  438. find_obj_defs(buf, objdefs)
  439. find_enum_defs(buf, enums)
  440. objdefs = sort_obj_defs(objdefs)
  441. if separate:
  442. methods = file(separate + '.defs', 'w')
  443. types = file(separate + '-types.defs', 'w')
  444. dw = DefsWriter(methods, prefix=modulename, verbose=verbose,
  445. defsfilter=defsfilter)
  446. dw.write_obj_defs(objdefs, types)
  447. dw.write_enum_defs(enums, types)
  448. print "Wrote %s-types.defs" % separate
  449. for filename in args:
  450. dw.write_def(filename)
  451. print "Wrote %s.defs" % separate
  452. else:
  453. dw = DefsWriter(prefix=modulename, verbose=verbose,
  454. defsfilter=defsfilter)
  455. if onlyenums:
  456. dw.write_enum_defs(enums)
  457. elif onlyobjdefs:
  458. dw.write_obj_defs(objdefs)
  459. else:
  460. dw.write_obj_defs(objdefs)
  461. dw.write_enum_defs(enums)
  462. for filename in args:
  463. dw.write_def(filename)
  464. if __name__ == '__main__':
  465. sys.exit(main(sys.argv))