PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/gtkNode/priv/generator/src/h2def.py

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